mirror of
https://github.com/WordPress/WordPress.git
synced 2024-11-14 22:56:19 +01:00
External Libraries: Update getID3 to version 1.9.21.
The latest version includes preliminary PHP 8.1 support, as well as a variety of bug fixes. Release notes: https://github.com/JamesHeinrich/getID3/releases/tag/v1.9.21 A full list of changes in this update can be found on GitHub: https://github.com/JamesHeinrich/getID3/compare/v1.9.20...v1.9.21 This commit also includes: * Setting the `$options_audiovideo_quicktime_ReturnAtomData` property (now `false` by default) to `true` in `wp_read_video_metadata()` and `wp_read_audio_metadata()` in order to get the `created_timestamp` value. * PHPCS adjustments previously made for a passing PHP Compatibility scan. Follow-up to [47601], [47737], [47902], [48278], [49621], [50714]. Props jrf, SergeyBiryukov. Fixes #54162. Built from https://develop.svn.wordpress.org/trunk@52254 git-svn-id: http://core.svn.wordpress.org/trunk@51846 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
904c4a8b5c
commit
70f43f261b
@ -3559,6 +3559,9 @@ function wp_read_video_metadata( $file ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$id3 = new getID3();
|
$id3 = new getID3();
|
||||||
|
// Required to get the `created_timestamp` value.
|
||||||
|
$id3->options_audiovideo_quicktime_ReturnAtomData = true; // phpcs:ignore WordPress.NamingConventions.ValidVariableName
|
||||||
|
|
||||||
$data = $id3->analyze( $file );
|
$data = $id3->analyze( $file );
|
||||||
|
|
||||||
if ( isset( $data['video']['lossless'] ) ) {
|
if ( isset( $data['video']['lossless'] ) ) {
|
||||||
@ -3670,6 +3673,9 @@ function wp_read_audio_metadata( $file ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$id3 = new getID3();
|
$id3 = new getID3();
|
||||||
|
// Required to get the `created_timestamp` value.
|
||||||
|
$id3->options_audiovideo_quicktime_ReturnAtomData = true; // phpcs:ignore WordPress.NamingConventions.ValidVariableName
|
||||||
|
|
||||||
$data = $id3->analyze( $file );
|
$data = $id3->analyze( $file );
|
||||||
|
|
||||||
if ( ! empty( $data['audio'] ) ) {
|
if ( ! empty( $data['audio'] ) ) {
|
||||||
|
@ -242,7 +242,7 @@ class getid3_lib
|
|||||||
/**
|
/**
|
||||||
* ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
|
* ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
|
||||||
*
|
*
|
||||||
* @link http://www.psc.edu/general/software/packages/ieee/ieee.html
|
* @link https://web.archive.org/web/20120325162206/http://www.psc.edu/general/software/packages/ieee/ieee.php
|
||||||
* @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
|
* @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
|
||||||
*
|
*
|
||||||
* @param string $byteword
|
* @param string $byteword
|
||||||
@ -294,12 +294,12 @@ class getid3_lib
|
|||||||
|
|
||||||
if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0)) {
|
if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0)) {
|
||||||
// Not a Number
|
// Not a Number
|
||||||
$floatvalue = false;
|
$floatvalue = NAN;
|
||||||
} elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0)) {
|
} elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0)) {
|
||||||
if ($signbit == '1') {
|
if ($signbit == '1') {
|
||||||
$floatvalue = '-infinity';
|
$floatvalue = -INF;
|
||||||
} else {
|
} else {
|
||||||
$floatvalue = '+infinity';
|
$floatvalue = INF;
|
||||||
}
|
}
|
||||||
} elseif (($exponent == 0) && ($fraction == 0)) {
|
} elseif (($exponent == 0) && ($fraction == 0)) {
|
||||||
if ($signbit == '1') {
|
if ($signbit == '1') {
|
||||||
@ -427,14 +427,20 @@ class getid3_lib
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function Dec2Bin($number) {
|
public static function Dec2Bin($number) {
|
||||||
|
if (!is_numeric($number)) {
|
||||||
|
// https://github.com/JamesHeinrich/getID3/issues/299
|
||||||
|
trigger_error('TypeError: Dec2Bin(): Argument #1 ($number) must be numeric, '.gettype($number).' given', E_USER_WARNING);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$bytes = array();
|
||||||
while ($number >= 256) {
|
while ($number >= 256) {
|
||||||
$bytes[] = (($number / 256) - (floor($number / 256))) * 256;
|
$bytes[] = (int) (($number / 256) - (floor($number / 256))) * 256;
|
||||||
$number = floor($number / 256);
|
$number = floor($number / 256);
|
||||||
}
|
}
|
||||||
$bytes[] = $number;
|
$bytes[] = (int) $number;
|
||||||
$binstring = '';
|
$binstring = '';
|
||||||
for ($i = 0; $i < count($bytes); $i++) {
|
foreach ($bytes as $i => $byte) {
|
||||||
$binstring = (($i == count($bytes) - 1) ? decbin($bytes[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)).$binstring;
|
$binstring = (($i == count($bytes) - 1) ? decbin($byte) : str_pad(decbin($byte), 8, '0', STR_PAD_LEFT)).$binstring;
|
||||||
}
|
}
|
||||||
return $binstring;
|
return $binstring;
|
||||||
}
|
}
|
||||||
@ -665,6 +671,7 @@ class getid3_lib
|
|||||||
// or
|
// or
|
||||||
// $foo['path']['to']['my'] = 'file.txt';
|
// $foo['path']['to']['my'] = 'file.txt';
|
||||||
$ArrayPath = ltrim($ArrayPath, $Separator);
|
$ArrayPath = ltrim($ArrayPath, $Separator);
|
||||||
|
$ReturnedArray = array();
|
||||||
if (($pos = strpos($ArrayPath, $Separator)) !== false) {
|
if (($pos = strpos($ArrayPath, $Separator)) !== false) {
|
||||||
$ReturnedArray[substr($ArrayPath, 0, $pos)] = self::CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value);
|
$ReturnedArray[substr($ArrayPath, 0, $pos)] = self::CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value);
|
||||||
} else {
|
} else {
|
||||||
@ -1538,12 +1545,21 @@ class getid3_lib
|
|||||||
public static function CopyTagsToComments(&$ThisFileInfo, $option_tags_html=true) {
|
public static function CopyTagsToComments(&$ThisFileInfo, $option_tags_html=true) {
|
||||||
// Copy all entries from ['tags'] into common ['comments']
|
// Copy all entries from ['tags'] into common ['comments']
|
||||||
if (!empty($ThisFileInfo['tags'])) {
|
if (!empty($ThisFileInfo['tags'])) {
|
||||||
if (isset($ThisFileInfo['tags']['id3v1'])) {
|
|
||||||
|
// Some tag types can only support limited character sets and may contain data in non-standard encoding (usually ID3v1)
|
||||||
|
// and/or poorly-transliterated tag values that are also in tag formats that do support full-range character sets
|
||||||
|
// To make the output more user-friendly, process the potentially-problematic tag formats last to enhance the chance that
|
||||||
|
// the first entries in [comments] are the most correct and the "bad" ones (if any) come later.
|
||||||
|
// https://github.com/JamesHeinrich/getID3/issues/338
|
||||||
|
$processLastTagTypes = array('id3v1','riff');
|
||||||
|
foreach ($processLastTagTypes as $processLastTagType) {
|
||||||
|
if (isset($ThisFileInfo['tags'][$processLastTagType])) {
|
||||||
// bubble ID3v1 to the end, if present to aid in detecting bad ID3v1 encodings
|
// bubble ID3v1 to the end, if present to aid in detecting bad ID3v1 encodings
|
||||||
$ID3v1 = $ThisFileInfo['tags']['id3v1'];
|
$temp = $ThisFileInfo['tags'][$processLastTagType];
|
||||||
unset($ThisFileInfo['tags']['id3v1']);
|
unset($ThisFileInfo['tags'][$processLastTagType]);
|
||||||
$ThisFileInfo['tags']['id3v1'] = $ID3v1;
|
$ThisFileInfo['tags'][$processLastTagType] = $temp;
|
||||||
unset($ID3v1);
|
unset($temp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) {
|
foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) {
|
||||||
foreach ($tagarray as $tagname => $tagdata) {
|
foreach ($tagarray as $tagname => $tagdata) {
|
||||||
@ -1562,7 +1578,7 @@ class getid3_lib
|
|||||||
// new value is identical but shorter-than (or equal-length to) one already in comments - skip
|
// new value is identical but shorter-than (or equal-length to) one already in comments - skip
|
||||||
break 2;
|
break 2;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (function_exists('mb_convert_encoding')) {
|
if (function_exists('mb_convert_encoding')) {
|
||||||
if (trim($value) == trim(substr(mb_convert_encoding($existingvalue, $ThisFileInfo['id3v1']['encoding'], $ThisFileInfo['encoding']), 0, 30))) {
|
if (trim($value) == trim(substr(mb_convert_encoding($existingvalue, $ThisFileInfo['id3v1']['encoding'], $ThisFileInfo['encoding']), 0, 30))) {
|
||||||
// value stored in ID3v1 appears to be probably the multibyte value transliterated (badly) into ISO-8859-1 in ID3v1.
|
// value stored in ID3v1 appears to be probably the multibyte value transliterated (badly) into ISO-8859-1 in ID3v1.
|
||||||
@ -1570,12 +1586,22 @@ class getid3_lib
|
|||||||
break 2;
|
break 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} elseif (!is_array($value)) {
|
} elseif (!is_array($value)) {
|
||||||
|
|
||||||
$newvaluelength = strlen(trim($value));
|
$newvaluelength = strlen(trim($value));
|
||||||
|
$newvaluelengthMB = mb_strlen(trim($value));
|
||||||
foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) {
|
foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) {
|
||||||
$oldvaluelength = strlen(trim($existingvalue));
|
$oldvaluelength = strlen(trim($existingvalue));
|
||||||
|
$oldvaluelengthMB = mb_strlen(trim($existingvalue));
|
||||||
|
if (($newvaluelengthMB == $oldvaluelengthMB) && ($existingvalue == getid3_lib::iconv_fallback('UTF-8', 'ASCII', $value))) {
|
||||||
|
// https://github.com/JamesHeinrich/getID3/issues/338
|
||||||
|
// check for tags containing extended characters that may have been forced into limited-character storage (e.g. UTF8 values into ASCII)
|
||||||
|
// which will usually display unrepresentable characters as "?"
|
||||||
|
$ThisFileInfo['comments'][$tagname][$existingkey] = trim($value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if ((strlen($existingvalue) > 10) && ($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) {
|
if ((strlen($existingvalue) > 10) && ($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) {
|
||||||
$ThisFileInfo['comments'][$tagname][$existingkey] = trim($value);
|
$ThisFileInfo['comments'][$tagname][$existingkey] = trim($value);
|
||||||
break;
|
break;
|
||||||
@ -1601,6 +1627,7 @@ class getid3_lib
|
|||||||
}
|
}
|
||||||
|
|
||||||
// attempt to standardize spelling of returned keys
|
// attempt to standardize spelling of returned keys
|
||||||
|
if (!empty($ThisFileInfo['comments'])) {
|
||||||
$StandardizeFieldNames = array(
|
$StandardizeFieldNames = array(
|
||||||
'tracknumber' => 'track_number',
|
'tracknumber' => 'track_number',
|
||||||
'track' => 'track_number',
|
'track' => 'track_number',
|
||||||
@ -1611,6 +1638,7 @@ class getid3_lib
|
|||||||
unset($ThisFileInfo['comments'][$badkey]);
|
unset($ThisFileInfo['comments'][$badkey]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($option_tags_html) {
|
if ($option_tags_html) {
|
||||||
// Copy ['comments'] to ['comments_html']
|
// Copy ['comments'] to ['comments_html']
|
||||||
@ -1734,6 +1762,7 @@ class getid3_lib
|
|||||||
* @return float|bool
|
* @return float|bool
|
||||||
*/
|
*/
|
||||||
public static function getFileSizeSyscall($path) {
|
public static function getFileSizeSyscall($path) {
|
||||||
|
$commandline = null;
|
||||||
$filesize = false;
|
$filesize = false;
|
||||||
|
|
||||||
if (GETID3_OS_ISWINDOWS) {
|
if (GETID3_OS_ISWINDOWS) {
|
||||||
@ -1795,7 +1824,7 @@ class getid3_lib
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function mb_basename($path, $suffix = null) {
|
public static function mb_basename($path, $suffix = '') {
|
||||||
$splited = preg_split('#/#', rtrim($path, '/ '));
|
$splited = preg_split('#/#', rtrim($path, '/ '));
|
||||||
return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1);
|
return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1);
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,6 @@ if (!defined('GETID3_OS_ISWINDOWS')) {
|
|||||||
if (!defined('GETID3_INCLUDEPATH')) {
|
if (!defined('GETID3_INCLUDEPATH')) {
|
||||||
define('GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR);
|
define('GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR);
|
||||||
}
|
}
|
||||||
// Workaround Bug #39923 (https://bugs.php.net/bug.php?id=39923)
|
|
||||||
if (!defined('IMG_JPG') && defined('IMAGETYPE_JPEG')) {
|
|
||||||
define('IMG_JPG', IMAGETYPE_JPEG);
|
|
||||||
}
|
|
||||||
if (!defined('ENT_SUBSTITUTE')) { // PHP5.3 adds ENT_IGNORE, PHP5.4 adds ENT_SUBSTITUTE
|
if (!defined('ENT_SUBSTITUTE')) { // PHP5.3 adds ENT_IGNORE, PHP5.4 adds ENT_SUBSTITUTE
|
||||||
define('ENT_SUBSTITUTE', (defined('ENT_IGNORE') ? ENT_IGNORE : 8));
|
define('ENT_SUBSTITUTE', (defined('ENT_IGNORE') ? ENT_IGNORE : 8));
|
||||||
}
|
}
|
||||||
@ -57,7 +53,7 @@ if ($open_basedir) {
|
|||||||
if (substr($basedir, -1, 1) != DIRECTORY_SEPARATOR) {
|
if (substr($basedir, -1, 1) != DIRECTORY_SEPARATOR) {
|
||||||
$basedir .= DIRECTORY_SEPARATOR;
|
$basedir .= DIRECTORY_SEPARATOR;
|
||||||
}
|
}
|
||||||
if (preg_match('#^'.preg_quote($basedir).'#', $temp_dir)) {
|
if (strpos($temp_dir, $basedir) === 0) {
|
||||||
$found_valid_tempdir = true;
|
$found_valid_tempdir = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -214,6 +210,140 @@ class getID3
|
|||||||
*/
|
*/
|
||||||
public $option_fread_buffer_size = 32768;
|
public $option_fread_buffer_size = 32768;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// module-specific options
|
||||||
|
|
||||||
|
/** archive.rar
|
||||||
|
* if true use PHP RarArchive extension, if false (non-extension parsing not yet written in getID3)
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $options_archive_rar_use_php_rar_extension = true;
|
||||||
|
|
||||||
|
/** archive.gzip
|
||||||
|
* Optional file list - disable for speed.
|
||||||
|
* Decode gzipped files, if possible, and parse recursively (.tar.gz for example).
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $options_archive_gzip_parse_contents = false;
|
||||||
|
|
||||||
|
/** audio.midi
|
||||||
|
* if false only parse most basic information, much faster for some files but may be inaccurate
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $options_audio_midi_scanwholefile = true;
|
||||||
|
|
||||||
|
/** audio.mp3
|
||||||
|
* Forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow,
|
||||||
|
* unrecommended, but may provide data from otherwise-unusable files.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $options_audio_mp3_allow_bruteforce = false;
|
||||||
|
|
||||||
|
/** audio.mp3
|
||||||
|
* number of frames to scan to determine if MPEG-audio sequence is valid
|
||||||
|
* Lower this number to 5-20 for faster scanning
|
||||||
|
* Increase this number to 50+ for most accurate detection of valid VBR/CBR mpeg-audio streams
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $options_audio_mp3_mp3_valid_check_frames = 50;
|
||||||
|
|
||||||
|
/** audio.wavpack
|
||||||
|
* Avoid scanning all frames (break after finding ID_RIFF_HEADER and ID_CONFIG_BLOCK,
|
||||||
|
* significantly faster for very large files but other data may be missed
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $options_audio_wavpack_quick_parsing = false;
|
||||||
|
|
||||||
|
/** audio-video.flv
|
||||||
|
* Break out of the loop if too many frames have been scanned; only scan this
|
||||||
|
* many if meta frame does not contain useful duration.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $options_audiovideo_flv_max_frames = 100000;
|
||||||
|
|
||||||
|
/** audio-video.matroska
|
||||||
|
* 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 $options_audiovideo_matroska_hide_clusters = true;
|
||||||
|
|
||||||
|
/** audio-video.matroska
|
||||||
|
* True to parse the whole file, not only header [default: FALSE].
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $options_audiovideo_matroska_parse_whole_file = false;
|
||||||
|
|
||||||
|
/** audio-video.quicktime
|
||||||
|
* return all parsed data from all atoms if true, otherwise just returned parsed metadata
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $options_audiovideo_quicktime_ReturnAtomData = false;
|
||||||
|
|
||||||
|
/** audio-video.quicktime
|
||||||
|
* return all parsed data from all atoms if true, otherwise just returned parsed metadata
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $options_audiovideo_quicktime_ParseAllPossibleAtoms = false;
|
||||||
|
|
||||||
|
/** audio-video.swf
|
||||||
|
* return all parsed tags if true, otherwise do not return tags not parsed by getID3
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $options_audiovideo_swf_ReturnAllTagData = false;
|
||||||
|
|
||||||
|
/** graphic.bmp
|
||||||
|
* return BMP palette
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $options_graphic_bmp_ExtractPalette = false;
|
||||||
|
|
||||||
|
/** graphic.bmp
|
||||||
|
* return image data
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $options_graphic_bmp_ExtractData = false;
|
||||||
|
|
||||||
|
/** graphic.png
|
||||||
|
* If data chunk is larger than this do not read it completely (getID3 only needs the first
|
||||||
|
* few dozen bytes for parsing).
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $options_graphic_png_max_data_bytes = 10000000;
|
||||||
|
|
||||||
|
/** misc.pdf
|
||||||
|
* return full details of PDF Cross-Reference Table (XREF)
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $options_misc_pdf_returnXREF = false;
|
||||||
|
|
||||||
|
/** misc.torrent
|
||||||
|
* Assume all .torrent files are less than 1MB and just read entire thing into memory for easy processing.
|
||||||
|
* Override this value if you need to process files larger than 1MB
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $options_misc_torrent_max_torrent_filesize = 1048576;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Public variables
|
// Public variables
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -257,7 +387,7 @@ class getID3
|
|||||||
*/
|
*/
|
||||||
protected $startup_warning = '';
|
protected $startup_warning = '';
|
||||||
|
|
||||||
const VERSION = '1.9.20-202006061653';
|
const VERSION = '1.9.21-202109171300';
|
||||||
const FREAD_BUFFER_SIZE = 32768;
|
const FREAD_BUFFER_SIZE = 32768;
|
||||||
|
|
||||||
const ATTACHMENTS_NONE = false;
|
const ATTACHMENTS_NONE = false;
|
||||||
@ -637,6 +767,18 @@ class getID3
|
|||||||
return $this->error('Format not supported, module "'.$determined_format['include'].'" is corrupt.');
|
return $this->error('Format not supported, module "'.$determined_format['include'].'" is corrupt.');
|
||||||
}
|
}
|
||||||
$class = new $class_name($this);
|
$class = new $class_name($this);
|
||||||
|
|
||||||
|
// set module-specific options
|
||||||
|
foreach (get_object_vars($this) as $getid3_object_vars_key => $getid3_object_vars_value) {
|
||||||
|
if (preg_match('#^options_([^_]+)_([^_]+)_(.+)$#i', $getid3_object_vars_key, $matches)) {
|
||||||
|
list($dummy, $GOVgroup, $GOVmodule, $GOVsetting) = $matches;
|
||||||
|
$GOVgroup = (($GOVgroup == 'audiovideo') ? 'audio-video' : $GOVgroup); // variable names can only contain 0-9a-z_ so standardize here
|
||||||
|
if (($GOVgroup == $determined_format['group']) && ($GOVmodule == $determined_format['module'])) {
|
||||||
|
$class->$GOVsetting = $getid3_object_vars_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$class->Analyze();
|
$class->Analyze();
|
||||||
unset($class);
|
unset($class);
|
||||||
|
|
||||||
@ -1355,6 +1497,16 @@ class getID3
|
|||||||
'fail_ape' => 'ERROR',
|
'fail_ape' => 'ERROR',
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// TORRENT - .torrent
|
||||||
|
'torrent' => array(
|
||||||
|
'pattern' => '^(d8\\:announce|d7\\:comment)',
|
||||||
|
'group' => 'misc',
|
||||||
|
'module' => 'torrent',
|
||||||
|
'mime_type' => 'application/x-bittorrent',
|
||||||
|
'fail_id3' => 'ERROR',
|
||||||
|
'fail_ape' => 'ERROR',
|
||||||
|
),
|
||||||
|
|
||||||
// CUE - data - CUEsheet (index to single-file disc images)
|
// CUE - data - CUEsheet (index to single-file disc images)
|
||||||
'cue' => array(
|
'cue' => array(
|
||||||
'pattern' => '', // empty pattern means cannot be automatically detected, will fall through all other formats and match based on filename and very basic file contents
|
'pattern' => '', // empty pattern means cannot be automatically detected, will fall through all other formats and match based on filename and very basic file contents
|
||||||
@ -1489,7 +1641,7 @@ class getID3
|
|||||||
if (is_string($value)) {
|
if (is_string($value)) {
|
||||||
$value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed!
|
$value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed!
|
||||||
}
|
}
|
||||||
if ($value) {
|
if (isset($value) && $value !== "") {
|
||||||
if (!is_numeric($key)) {
|
if (!is_numeric($key)) {
|
||||||
$this->info['tags'][trim($tag_name)][trim($tag_key)][$key] = $value;
|
$this->info['tags'][trim($tag_name)][trim($tag_key)][$key] = $value;
|
||||||
} else {
|
} else {
|
||||||
@ -2096,8 +2248,9 @@ abstract class getid3_handler
|
|||||||
$this->data_string_position = $this->data_string_length + $bytes;
|
$this->data_string_position = $this->data_string_length + $bytes;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0; // fseek returns 0 on success
|
||||||
} else {
|
}
|
||||||
|
|
||||||
$pos = $bytes;
|
$pos = $bytes;
|
||||||
if ($whence == SEEK_CUR) {
|
if ($whence == SEEK_CUR) {
|
||||||
$pos = $this->ftell() + $bytes;
|
$pos = $this->ftell() + $bytes;
|
||||||
@ -2107,8 +2260,13 @@ abstract class getid3_handler
|
|||||||
if (!getid3_lib::intValueSupported($pos)) {
|
if (!getid3_lib::intValueSupported($pos)) {
|
||||||
throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10);
|
throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/JamesHeinrich/getID3/issues/327
|
||||||
|
$result = fseek($this->getid3->fp, $bytes, $whence);
|
||||||
|
if ($result !== 0) { // fseek returns 0 on success
|
||||||
|
throw new getid3_exception('cannot fseek('.$pos.'). resource/stream does not appear to support seeking', 10);
|
||||||
}
|
}
|
||||||
return fseek($this->getid3->fp, $bytes, $whence);
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2224,6 +2382,8 @@ abstract class getid3_handler
|
|||||||
* @throws getid3_exception
|
* @throws getid3_exception
|
||||||
*/
|
*/
|
||||||
public function saveAttachment($name, $offset, $length, $image_mime=null) {
|
public function saveAttachment($name, $offset, $length, $image_mime=null) {
|
||||||
|
$fp_dest = null;
|
||||||
|
$dest = null;
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// do not extract at all
|
// do not extract at all
|
||||||
|
@ -93,6 +93,7 @@ class getid3_asf extends getid3_handler
|
|||||||
$offset = 0;
|
$offset = 0;
|
||||||
$thisfile_asf_streambitratepropertiesobject = array();
|
$thisfile_asf_streambitratepropertiesobject = array();
|
||||||
$thisfile_asf_codeclistobject = array();
|
$thisfile_asf_codeclistobject = array();
|
||||||
|
$StreamPropertiesObjectData = array();
|
||||||
|
|
||||||
for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) {
|
for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) {
|
||||||
$NextObjectGUID = substr($ASFHeaderData, $offset, 16);
|
$NextObjectGUID = substr($ASFHeaderData, $offset, 16);
|
||||||
@ -283,7 +284,7 @@ class getid3_asf extends getid3_handler
|
|||||||
$thisfile_asf_headerextensionobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
|
$thisfile_asf_headerextensionobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
|
||||||
$offset += 2;
|
$offset += 2;
|
||||||
if ($thisfile_asf_headerextensionobject['reserved_2'] != 6) {
|
if ($thisfile_asf_headerextensionobject['reserved_2'] != 6) {
|
||||||
$this->warning('header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"');
|
$this->warning('header_extension_object.reserved_2 ('.$thisfile_asf_headerextensionobject['reserved_2'].') does not match expected value of "6"');
|
||||||
//return false;
|
//return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -535,7 +536,7 @@ class getid3_asf extends getid3_handler
|
|||||||
$thisfile_asf_markerobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
|
$thisfile_asf_markerobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
|
||||||
$offset += 2;
|
$offset += 2;
|
||||||
if ($thisfile_asf_markerobject['reserved_2'] != 0) {
|
if ($thisfile_asf_markerobject['reserved_2'] != 0) {
|
||||||
$this->warning('marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"');
|
$this->warning('marker_object.reserved_2 ('.$thisfile_asf_markerobject['reserved_2'].') does not match expected value of "0"');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$thisfile_asf_markerobject['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
|
$thisfile_asf_markerobject['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
|
||||||
@ -1193,7 +1194,7 @@ class getid3_asf extends getid3_handler
|
|||||||
$thisfile_asf_dataobject['reserved'] = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 2));
|
$thisfile_asf_dataobject['reserved'] = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 2));
|
||||||
$offset += 2;
|
$offset += 2;
|
||||||
if ($thisfile_asf_dataobject['reserved'] != 0x0101) {
|
if ($thisfile_asf_dataobject['reserved'] != 0x0101) {
|
||||||
$this->warning('data_object.reserved ('.getid3_lib::PrintHexBytes($thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"');
|
$this->warning('data_object.reserved (0x'.sprintf('%04X', $thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"');
|
||||||
//return false;
|
//return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -161,6 +161,7 @@ class getid3_flv extends getid3_handler
|
|||||||
$info['flv']['video']['videoCodec'] = $LastHeaderByte & 0x07;
|
$info['flv']['video']['videoCodec'] = $LastHeaderByte & 0x07;
|
||||||
|
|
||||||
$FLVvideoHeader = $this->fread(11);
|
$FLVvideoHeader = $this->fread(11);
|
||||||
|
$PictureSizeEnc = array();
|
||||||
|
|
||||||
if ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H264) {
|
if ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H264) {
|
||||||
// this code block contributed by: moysevichØgmail*com
|
// this code block contributed by: moysevichØgmail*com
|
||||||
|
@ -224,14 +224,14 @@ class getid3_matroska extends getid3_handler
|
|||||||
*
|
*
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
public static $hide_clusters = true;
|
public $hide_clusters = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True to parse the whole file, not only header [default: FALSE].
|
* True to parse the whole file, not only header [default: FALSE].
|
||||||
*
|
*
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
public static $parse_whole_file = false;
|
public $parse_whole_file = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Private parser settings/placeholders.
|
* Private parser settings/placeholders.
|
||||||
@ -586,7 +586,7 @@ class getid3_matroska extends getid3_handler
|
|||||||
$info['matroska']['segment'][0]['length'] = $top_element['length'];
|
$info['matroska']['segment'][0]['length'] = $top_element['length'];
|
||||||
|
|
||||||
while ($this->getEBMLelement($element_data, $top_element['end'])) {
|
while ($this->getEBMLelement($element_data, $top_element['end'])) {
|
||||||
if ($element_data['id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required
|
if ($element_data['id'] != EBML_ID_CLUSTER || !$this->hide_clusters) { // collect clusters only if required
|
||||||
$info['matroska']['segments'][] = $element_data;
|
$info['matroska']['segments'][] = $element_data;
|
||||||
}
|
}
|
||||||
switch ($element_data['id']) {
|
switch ($element_data['id']) {
|
||||||
@ -618,7 +618,7 @@ class getid3_matroska extends getid3_handler
|
|||||||
$this->warning('seek_entry[target_id] unexpectedly not set at '.$seek_entry['offset']);
|
$this->warning('seek_entry[target_id] unexpectedly not set at '.$seek_entry['offset']);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (($seek_entry['target_id'] != EBML_ID_CLUSTER) || !self::$hide_clusters) { // collect clusters only if required
|
if (($seek_entry['target_id'] != EBML_ID_CLUSTER) || !$this->hide_clusters) { // collect clusters only if required
|
||||||
$info['matroska']['seek'][] = $seek_entry;
|
$info['matroska']['seek'][] = $seek_entry;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -905,7 +905,7 @@ class getid3_matroska extends getid3_handler
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 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.
|
case 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
|
if ($this->hide_clusters) { // do not parse cues if hide clusters is "ON" till they point to clusters anyway
|
||||||
$this->current_offset = $element_data['end'];
|
$this->current_offset = $element_data['end'];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1246,12 +1246,12 @@ class getid3_matroska extends getid3_handler
|
|||||||
}
|
}
|
||||||
$this->current_offset = $subelement['end'];
|
$this->current_offset = $subelement['end'];
|
||||||
}
|
}
|
||||||
if (!self::$hide_clusters) {
|
if (!$this->hide_clusters) {
|
||||||
$info['matroska']['cluster'][] = $cluster_entry;
|
$info['matroska']['cluster'][] = $cluster_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check to see if all the data we need exists already, if so, break out of the loop
|
// check to see if all the data we need exists already, if so, break out of the loop
|
||||||
if (!self::$parse_whole_file) {
|
if (!$this->parse_whole_file) {
|
||||||
if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
|
if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
|
||||||
if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
|
if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
|
||||||
if (count($info['matroska']['track_data_offsets']) == count($info['matroska']['tracks']['tracks'])) {
|
if (count($info['matroska']['track_data_offsets']) == count($info['matroska']['tracks']['tracks'])) {
|
||||||
|
@ -24,7 +24,18 @@ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE_
|
|||||||
class getid3_quicktime extends getid3_handler
|
class getid3_quicktime extends getid3_handler
|
||||||
{
|
{
|
||||||
|
|
||||||
public $ReturnAtomData = true;
|
/** audio-video.quicktime
|
||||||
|
* return all parsed data from all atoms if true, otherwise just returned parsed metadata
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $ReturnAtomData = false;
|
||||||
|
|
||||||
|
/** audio-video.quicktime
|
||||||
|
* return all parsed data from all atoms if true, otherwise just returned parsed metadata
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
public $ParseAllPossibleAtoms = false;
|
public $ParseAllPossibleAtoms = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -170,7 +181,7 @@ class getid3_quicktime extends getid3_handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) {
|
if (!isset($info['bitrate']) && !empty($info['playtime_seconds'])) {
|
||||||
$info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
$info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||||
}
|
}
|
||||||
if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) {
|
if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) {
|
||||||
@ -560,15 +571,28 @@ class getid3_quicktime extends getid3_handler
|
|||||||
default:
|
default:
|
||||||
$atom_structure['data'] = substr($boxdata, 8);
|
$atom_structure['data'] = substr($boxdata, 8);
|
||||||
if ($atomname == 'covr') {
|
if ($atomname == 'covr') {
|
||||||
// not a foolproof check, but better than nothing
|
if (!empty($atom_structure['data'])) {
|
||||||
if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) {
|
$atom_structure['image_mime'] = 'image/unknown'; // provide default MIME type to ensure array keys exist
|
||||||
$atom_structure['image_mime'] = 'image/jpeg';
|
if (function_exists('getimagesizefromstring') && ($getimagesize = getimagesizefromstring($atom_structure['data'])) && !empty($getimagesize['mime'])) {
|
||||||
} elseif (preg_match('#^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A#', $atom_structure['data'])) {
|
$atom_structure['image_mime'] = $getimagesize['mime'];
|
||||||
$atom_structure['image_mime'] = 'image/png';
|
} else {
|
||||||
} elseif (preg_match('#^GIF#', $atom_structure['data'])) {
|
// if getimagesizefromstring is not available, or fails for some reason, fall back to simple detection of common image formats
|
||||||
$atom_structure['image_mime'] = 'image/gif';
|
$ImageFormatSignatures = array(
|
||||||
|
'image/jpeg' => "\xFF\xD8\xFF",
|
||||||
|
'image/png' => "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A",
|
||||||
|
'image/gif' => 'GIF',
|
||||||
|
);
|
||||||
|
foreach ($ImageFormatSignatures as $mime => $image_format_signature) {
|
||||||
|
if (substr($atom_structure['data'], 0, strlen($image_format_signature)) == $image_format_signature) {
|
||||||
|
$atom_structure['image_mime'] = $mime;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover');
|
$info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover');
|
||||||
|
} else {
|
||||||
|
$this->warning('Unknown empty "covr" image at offset '.$baseoffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -728,11 +752,13 @@ class getid3_quicktime extends getid3_handler
|
|||||||
$atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag'];
|
$atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag'];
|
||||||
$atom_structure['flags']['slide_show'] = (bool) $atom_structure['slide_show_flag'];
|
$atom_structure['flags']['slide_show'] = (bool) $atom_structure['slide_show_flag'];
|
||||||
|
|
||||||
$ptv_lookup[0] = 'normal';
|
$ptv_lookup = array(
|
||||||
$ptv_lookup[1] = 'double';
|
0 => 'normal',
|
||||||
$ptv_lookup[2] = 'half';
|
1 => 'double',
|
||||||
$ptv_lookup[3] = 'full';
|
2 => 'half',
|
||||||
$ptv_lookup[4] = 'current';
|
3 => 'full',
|
||||||
|
4 => 'current'
|
||||||
|
);
|
||||||
if (isset($ptv_lookup[$atom_structure['display_size_raw']])) {
|
if (isset($ptv_lookup[$atom_structure['display_size_raw']])) {
|
||||||
$atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']];
|
$atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']];
|
||||||
} else {
|
} else {
|
||||||
@ -908,13 +934,13 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in
|
|||||||
$atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66, 2));
|
$atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66, 2));
|
||||||
$atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2));
|
$atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2));
|
||||||
|
|
||||||
$atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');
|
$atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (((int) $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');
|
||||||
$atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']);
|
$atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']);
|
||||||
|
|
||||||
if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') {
|
if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') {
|
||||||
$info['quicktime']['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
|
$info['quicktime']['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
|
||||||
$info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
|
$info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
|
||||||
$info['quicktime']['video']['codec'] = (($atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']);
|
$info['quicktime']['video']['codec'] = (((int) $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']);
|
||||||
$info['quicktime']['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'];
|
$info['quicktime']['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'];
|
||||||
$info['quicktime']['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name'];
|
$info['quicktime']['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name'];
|
||||||
|
|
||||||
@ -1598,33 +1624,61 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'NCDT':
|
case 'NCDT':
|
||||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
|
// https://exiftool.org/TagNames/Nikon.html
|
||||||
// Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
|
// Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
|
||||||
$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
|
$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
|
||||||
break;
|
break;
|
||||||
case 'NCTH': // Nikon Camera THumbnail image
|
case 'NCTH': // Nikon Camera THumbnail image
|
||||||
case 'NCVW': // Nikon Camera preVieW image
|
case 'NCVW': // Nikon Camera preVieW image
|
||||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
|
case 'NCM1': // Nikon Camera preview iMage 1
|
||||||
|
case 'NCM2': // Nikon Camera preview iMage 2
|
||||||
|
// https://exiftool.org/TagNames/Nikon.html
|
||||||
if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) {
|
if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) {
|
||||||
|
$descriptions = array(
|
||||||
|
'NCTH' => 'Nikon Camera Thumbnail Image',
|
||||||
|
'NCVW' => 'Nikon Camera Preview Image',
|
||||||
|
'NCM1' => 'Nikon Camera Preview Image 1',
|
||||||
|
'NCM2' => 'Nikon Camera Preview Image 2',
|
||||||
|
);
|
||||||
$atom_structure['data'] = $atom_data;
|
$atom_structure['data'] = $atom_data;
|
||||||
$atom_structure['image_mime'] = 'image/jpeg';
|
$atom_structure['image_mime'] = 'image/jpeg';
|
||||||
$atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image'));
|
$atom_structure['description'] = isset($descriptions[$atomname]) ? $descriptions[$atomname] : 'Nikon preview image';
|
||||||
$info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']);
|
$info['quicktime']['comments']['picture'][] = array(
|
||||||
|
'image_mime' => $atom_structure['image_mime'],
|
||||||
|
'data' => $atom_data,
|
||||||
|
'description' => $atom_structure['description']
|
||||||
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'NCTG': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
|
case 'NCTG': // Nikon - https://exiftool.org/TagNames/Nikon.html#NCTG
|
||||||
$atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data);
|
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.nikon-nctg.php', __FILE__, true);
|
||||||
|
$nikonNCTG = new getid3_tag_nikon_nctg($this->getid3);
|
||||||
|
|
||||||
|
$atom_structure['data'] = $nikonNCTG->parse($atom_data);
|
||||||
break;
|
break;
|
||||||
case 'NCHD': // Nikon:MakerNoteVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
|
case 'NCHD': // Nikon:MakerNoteVersion - https://exiftool.org/TagNames/Nikon.html
|
||||||
case 'NCDB': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
|
$makerNoteVersion = '';
|
||||||
case 'CNCV': // Canon:CompressorVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html
|
for ($i = 0, $iMax = strlen($atom_data); $i < $iMax; ++$i) {
|
||||||
|
if (ord($atom_data[$i]) >= 0x00 && ord($atom_data[$i]) <= 0x1F) {
|
||||||
|
$makerNoteVersion .= ' '.ord($atom_data[$i]);
|
||||||
|
} else {
|
||||||
|
$makerNoteVersion .= $atom_data[$i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$makerNoteVersion = rtrim($makerNoteVersion, "\x00");
|
||||||
|
$atom_structure['data'] = array(
|
||||||
|
'MakerNoteVersion' => $makerNoteVersion
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'NCDB': // Nikon - https://exiftool.org/TagNames/Nikon.html
|
||||||
|
case 'CNCV': // Canon:CompressorVersion - https://exiftool.org/TagNames/Canon.html
|
||||||
$atom_structure['data'] = $atom_data;
|
$atom_structure['data'] = $atom_data;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "\x00\x00\x00\x00":
|
case "\x00\x00\x00\x00":
|
||||||
// some kind of metacontainer, may contain a big data dump such as:
|
// some kind of metacontainer, may contain a big data dump such as:
|
||||||
// mdta keys \005 mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst \01D \001 \015data \001DE\010Apple 0 \002 (data \001DE\0102011-05-11T17:54:04+0200 2 \003 *data \001DE\010+52.4936+013.3897+040.247/ \01D \004 \015data \001DE\0104.3.1 \005 \018data \001DE\010iPhone 4
|
// mdta keys \005 mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst \01D \001 \015data \001DE\010Apple 0 \002 (data \001DE\0102011-05-11T17:54:04+0200 2 \003 *data \001DE\010+52.4936+013.3897+040.247/ \01D \004 \015data \001DE\0104.3.1 \005 \018data \001DE\010iPhone 4
|
||||||
// http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
|
// https://xhelmboyx.tripod.com/formats/qti-layout.txt
|
||||||
|
|
||||||
$atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
|
$atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
|
||||||
$atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
|
$atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
|
||||||
@ -1721,6 +1775,7 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in
|
|||||||
'unknown_data' => array(),
|
'unknown_data' => array(),
|
||||||
'debug_list' => '', // Used to debug variables stored as comma delimited strings
|
'debug_list' => '', // Used to debug variables stored as comma delimited strings
|
||||||
);
|
);
|
||||||
|
$debug_structure = array();
|
||||||
$debug_structure['debug_items'] = array();
|
$debug_structure['debug_items'] = array();
|
||||||
// Can start loop here to decode all sensor data in 32 Byte chunks:
|
// Can start loop here to decode all sensor data in 32 Byte chunks:
|
||||||
foreach (str_split($atom_SENSOR_data, 32) as $sensor_key => $sensor_data) {
|
foreach (str_split($atom_SENSOR_data, 32) as $sensor_key => $sensor_data) {
|
||||||
@ -2039,7 +2094,7 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in
|
|||||||
* @return array|false
|
* @return array|false
|
||||||
*/
|
*/
|
||||||
public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
|
public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
|
||||||
$atom_structure = false;
|
$atom_structure = array();
|
||||||
$subatomoffset = 0;
|
$subatomoffset = 0;
|
||||||
$subatomcounter = 0;
|
$subatomcounter = 0;
|
||||||
if ((strlen($atom_data) == 4) && (getid3_lib::BigEndian2Int($atom_data) == 0x00000000)) {
|
if ((strlen($atom_data) == 4) && (getid3_lib::BigEndian2Int($atom_data) == 0x00000000)) {
|
||||||
@ -2057,17 +2112,22 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in
|
|||||||
$subatomoffset += 4;
|
$subatomoffset += 4;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return $atom_structure;
|
break;
|
||||||
}
|
}
|
||||||
if (strlen($subatomdata) < ($subatomsize - 8)) {
|
if (strlen($subatomdata) < ($subatomsize - 8)) {
|
||||||
// we don't have enough data to decode the subatom.
|
// we don't have enough data to decode the subatom.
|
||||||
// this may be because we are refusing to parse large subatoms, or it may be because this atom had its size set too large
|
// this may be because we are refusing to parse large subatoms, or it may be because this atom had its size set too large
|
||||||
// so we passed in the start of a following atom incorrectly?
|
// so we passed in the start of a following atom incorrectly?
|
||||||
return $atom_structure;
|
break;
|
||||||
}
|
}
|
||||||
$atom_structure[$subatomcounter++] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms);
|
$atom_structure[$subatomcounter++] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms);
|
||||||
$subatomoffset += $subatomsize;
|
$subatomoffset += $subatomsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (empty($atom_structure)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return $atom_structure;
|
return $atom_structure;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2552,8 +2612,9 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in
|
|||||||
static $QuicktimeContentRatingLookup = array();
|
static $QuicktimeContentRatingLookup = array();
|
||||||
if (empty($QuicktimeContentRatingLookup)) {
|
if (empty($QuicktimeContentRatingLookup)) {
|
||||||
$QuicktimeContentRatingLookup[0] = 'None';
|
$QuicktimeContentRatingLookup[0] = 'None';
|
||||||
|
$QuicktimeContentRatingLookup[1] = 'Explicit';
|
||||||
$QuicktimeContentRatingLookup[2] = 'Clean';
|
$QuicktimeContentRatingLookup[2] = 'Clean';
|
||||||
$QuicktimeContentRatingLookup[4] = 'Explicit';
|
$QuicktimeContentRatingLookup[4] = 'Explicit (old)';
|
||||||
}
|
}
|
||||||
return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid');
|
return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid');
|
||||||
}
|
}
|
||||||
@ -2606,189 +2667,6 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in
|
|||||||
return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid');
|
return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $atom_data
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function QuicktimeParseNikonNCTG($atom_data) {
|
|
||||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
|
|
||||||
// Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
|
|
||||||
// Data is stored as records of:
|
|
||||||
// * 4 bytes record type
|
|
||||||
// * 2 bytes size of data field type:
|
|
||||||
// 0x0001 = flag (size field *= 1-byte)
|
|
||||||
// 0x0002 = char (size field *= 1-byte)
|
|
||||||
// 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
|
|
||||||
// 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
|
|
||||||
// 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
|
|
||||||
// 0x0007 = bytes (size field *= 1-byte), values are stored as ??????
|
|
||||||
// 0x0008 = ????? (size field *= 2-byte), values are stored as ??????
|
|
||||||
// * 2 bytes data size field
|
|
||||||
// * ? bytes data (string data may be null-padded; datestamp fields are in the format "2011:05:25 20:24:15")
|
|
||||||
// all integers are stored BigEndian
|
|
||||||
|
|
||||||
$NCTGtagName = array(
|
|
||||||
0x00000001 => 'Make',
|
|
||||||
0x00000002 => 'Model',
|
|
||||||
0x00000003 => 'Software',
|
|
||||||
0x00000011 => 'CreateDate',
|
|
||||||
0x00000012 => 'DateTimeOriginal',
|
|
||||||
0x00000013 => 'FrameCount',
|
|
||||||
0x00000016 => 'FrameRate',
|
|
||||||
0x00000022 => 'FrameWidth',
|
|
||||||
0x00000023 => 'FrameHeight',
|
|
||||||
0x00000032 => 'AudioChannels',
|
|
||||||
0x00000033 => 'AudioBitsPerSample',
|
|
||||||
0x00000034 => 'AudioSampleRate',
|
|
||||||
0x02000001 => 'MakerNoteVersion',
|
|
||||||
0x02000005 => 'WhiteBalance',
|
|
||||||
0x0200000b => 'WhiteBalanceFineTune',
|
|
||||||
0x0200001e => 'ColorSpace',
|
|
||||||
0x02000023 => 'PictureControlData',
|
|
||||||
0x02000024 => 'WorldTime',
|
|
||||||
0x02000032 => 'UnknownInfo',
|
|
||||||
0x02000083 => 'LensType',
|
|
||||||
0x02000084 => 'Lens',
|
|
||||||
);
|
|
||||||
|
|
||||||
$offset = 0;
|
|
||||||
$data = null;
|
|
||||||
$datalength = strlen($atom_data);
|
|
||||||
$parsed = array();
|
|
||||||
while ($offset < $datalength) {
|
|
||||||
$record_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4)); $offset += 4;
|
|
||||||
$data_size_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2;
|
|
||||||
$data_size = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2;
|
|
||||||
switch ($data_size_type) {
|
|
||||||
case 0x0001: // 0x0001 = flag (size field *= 1-byte)
|
|
||||||
$data = getid3_lib::BigEndian2Int(substr($atom_data, $offset, $data_size * 1));
|
|
||||||
$offset += ($data_size * 1);
|
|
||||||
break;
|
|
||||||
case 0x0002: // 0x0002 = char (size field *= 1-byte)
|
|
||||||
$data = substr($atom_data, $offset, $data_size * 1);
|
|
||||||
$offset += ($data_size * 1);
|
|
||||||
$data = rtrim($data, "\x00");
|
|
||||||
break;
|
|
||||||
case 0x0003: // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
|
|
||||||
$data = '';
|
|
||||||
for ($i = $data_size - 1; $i >= 0; $i--) {
|
|
||||||
$data .= substr($atom_data, $offset + ($i * 2), 2);
|
|
||||||
}
|
|
||||||
$data = getid3_lib::BigEndian2Int($data);
|
|
||||||
$offset += ($data_size * 2);
|
|
||||||
break;
|
|
||||||
case 0x0004: // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
|
|
||||||
$data = '';
|
|
||||||
for ($i = $data_size - 1; $i >= 0; $i--) {
|
|
||||||
$data .= substr($atom_data, $offset + ($i * 4), 4);
|
|
||||||
}
|
|
||||||
$data = getid3_lib::BigEndian2Int($data);
|
|
||||||
$offset += ($data_size * 4);
|
|
||||||
break;
|
|
||||||
case 0x0005: // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
|
|
||||||
$data = array();
|
|
||||||
for ($i = 0; $i < $data_size; $i++) {
|
|
||||||
$numerator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 0, 4));
|
|
||||||
$denomninator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 4, 4));
|
|
||||||
if ($denomninator == 0) {
|
|
||||||
$data[$i] = false;
|
|
||||||
} else {
|
|
||||||
$data[$i] = (double) $numerator / $denomninator;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$offset += (8 * $data_size);
|
|
||||||
if (count($data) == 1) {
|
|
||||||
$data = $data[0];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x0007: // 0x0007 = bytes (size field *= 1-byte), values are stored as ??????
|
|
||||||
$data = substr($atom_data, $offset, $data_size * 1);
|
|
||||||
$offset += ($data_size * 1);
|
|
||||||
break;
|
|
||||||
case 0x0008: // 0x0008 = ????? (size field *= 2-byte), values are stored as ??????
|
|
||||||
$data = substr($atom_data, $offset, $data_size * 2);
|
|
||||||
$offset += ($data_size * 2);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br>';
|
|
||||||
break 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($record_type) {
|
|
||||||
case 0x00000011: // CreateDate
|
|
||||||
case 0x00000012: // DateTimeOriginal
|
|
||||||
$data = strtotime($data);
|
|
||||||
break;
|
|
||||||
case 0x0200001e: // ColorSpace
|
|
||||||
switch ($data) {
|
|
||||||
case 1:
|
|
||||||
$data = 'sRGB';
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
$data = 'Adobe RGB';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x02000023: // PictureControlData
|
|
||||||
$PictureControlAdjust = array(0=>'default', 1=>'quick', 2=>'full');
|
|
||||||
$FilterEffect = array(0x80=>'off', 0x81=>'yellow', 0x82=>'orange', 0x83=>'red', 0x84=>'green', 0xff=>'n/a');
|
|
||||||
$ToningEffect = array(0x80=>'b&w', 0x81=>'sepia', 0x82=>'cyanotype', 0x83=>'red', 0x84=>'yellow', 0x85=>'green', 0x86=>'blue-green', 0x87=>'blue', 0x88=>'purple-blue', 0x89=>'red-purple', 0xff=>'n/a');
|
|
||||||
$data = array(
|
|
||||||
'PictureControlVersion' => substr($data, 0, 4),
|
|
||||||
'PictureControlName' => rtrim(substr($data, 4, 20), "\x00"),
|
|
||||||
'PictureControlBase' => rtrim(substr($data, 24, 20), "\x00"),
|
|
||||||
//'?' => substr($data, 44, 4),
|
|
||||||
'PictureControlAdjust' => $PictureControlAdjust[ord(substr($data, 48, 1))],
|
|
||||||
'PictureControlQuickAdjust' => ord(substr($data, 49, 1)),
|
|
||||||
'Sharpness' => ord(substr($data, 50, 1)),
|
|
||||||
'Contrast' => ord(substr($data, 51, 1)),
|
|
||||||
'Brightness' => ord(substr($data, 52, 1)),
|
|
||||||
'Saturation' => ord(substr($data, 53, 1)),
|
|
||||||
'HueAdjustment' => ord(substr($data, 54, 1)),
|
|
||||||
'FilterEffect' => $FilterEffect[ord(substr($data, 55, 1))],
|
|
||||||
'ToningEffect' => $ToningEffect[ord(substr($data, 56, 1))],
|
|
||||||
'ToningSaturation' => ord(substr($data, 57, 1)),
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 0x02000024: // WorldTime
|
|
||||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime
|
|
||||||
// timezone is stored as offset from GMT in minutes
|
|
||||||
$timezone = getid3_lib::BigEndian2Int(substr($data, 0, 2));
|
|
||||||
if ($timezone & 0x8000) {
|
|
||||||
$timezone = 0 - (0x10000 - $timezone);
|
|
||||||
}
|
|
||||||
$timezone /= 60;
|
|
||||||
|
|
||||||
$dst = (bool) getid3_lib::BigEndian2Int(substr($data, 2, 1));
|
|
||||||
switch (getid3_lib::BigEndian2Int(substr($data, 3, 1))) {
|
|
||||||
case 2:
|
|
||||||
$datedisplayformat = 'D/M/Y'; break;
|
|
||||||
case 1:
|
|
||||||
$datedisplayformat = 'M/D/Y'; break;
|
|
||||||
case 0:
|
|
||||||
default:
|
|
||||||
$datedisplayformat = 'Y/M/D'; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = array('timezone'=>floatval($timezone), 'dst'=>$dst, 'display'=>$datedisplayformat);
|
|
||||||
break;
|
|
||||||
case 0x02000083: // LensType
|
|
||||||
$data = array(
|
|
||||||
//'_' => $data,
|
|
||||||
'mf' => (bool) ($data & 0x01),
|
|
||||||
'd' => (bool) ($data & 0x02),
|
|
||||||
'g' => (bool) ($data & 0x04),
|
|
||||||
'vr' => (bool) ($data & 0x08),
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$tag_name = (isset($NCTGtagName[$record_type]) ? $NCTGtagName[$record_type] : '0x'.str_pad(dechex($record_type), 8, '0', STR_PAD_LEFT));
|
|
||||||
$parsed[$tag_name] = $data;
|
|
||||||
}
|
|
||||||
return $parsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $keyname
|
* @param string $keyname
|
||||||
* @param string|array $data
|
* @param string|array $data
|
||||||
|
@ -56,6 +56,7 @@ class getid3_riff extends getid3_handler
|
|||||||
$thisfile_riff_video = &$thisfile_riff['video'];
|
$thisfile_riff_video = &$thisfile_riff['video'];
|
||||||
$thisfile_riff_WAVE = array();
|
$thisfile_riff_WAVE = array();
|
||||||
|
|
||||||
|
$Original = array();
|
||||||
$Original['avdataoffset'] = $info['avdataoffset'];
|
$Original['avdataoffset'] = $info['avdataoffset'];
|
||||||
$Original['avdataend'] = $info['avdataend'];
|
$Original['avdataend'] = $info['avdataend'];
|
||||||
|
|
||||||
@ -296,9 +297,18 @@ class getid3_riff extends getid3_handler
|
|||||||
// shortcut
|
// shortcut
|
||||||
$thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0];
|
$thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0];
|
||||||
|
|
||||||
$thisfile_riff_WAVE_bext_0['title'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 0, 256));
|
$thisfile_riff_WAVE_bext_0['title'] = substr($thisfile_riff_WAVE_bext_0['data'], 0, 256);
|
||||||
$thisfile_riff_WAVE_bext_0['author'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 256, 32));
|
$thisfile_riff_WAVE_bext_0['author'] = substr($thisfile_riff_WAVE_bext_0['data'], 256, 32);
|
||||||
$thisfile_riff_WAVE_bext_0['reference'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 288, 32));
|
$thisfile_riff_WAVE_bext_0['reference'] = substr($thisfile_riff_WAVE_bext_0['data'], 288, 32);
|
||||||
|
foreach (array('title','author','reference') as $bext_key) {
|
||||||
|
// Some software (notably Logic Pro) may not blank existing data before writing a null-terminated string to the offsets
|
||||||
|
// assigned for text fields, resulting in a null-terminated string (or possibly just a single null) followed by garbage
|
||||||
|
// Keep only string as far as first null byte, discard rest of fixed-width data
|
||||||
|
// https://github.com/JamesHeinrich/getID3/issues/263
|
||||||
|
$null_terminator_offset = strpos($thisfile_riff_WAVE_bext_0[$bext_key], "\x00");
|
||||||
|
$thisfile_riff_WAVE_bext_0[$bext_key] = substr($thisfile_riff_WAVE_bext_0[$bext_key], 0, $null_terminator_offset);
|
||||||
|
}
|
||||||
|
|
||||||
$thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10);
|
$thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10);
|
||||||
$thisfile_riff_WAVE_bext_0['origin_time'] = substr($thisfile_riff_WAVE_bext_0['data'], 330, 8);
|
$thisfile_riff_WAVE_bext_0['origin_time'] = substr($thisfile_riff_WAVE_bext_0['data'], 330, 8);
|
||||||
$thisfile_riff_WAVE_bext_0['time_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338, 8));
|
$thisfile_riff_WAVE_bext_0['time_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338, 8));
|
||||||
@ -307,6 +317,7 @@ class getid3_riff extends getid3_handler
|
|||||||
$thisfile_riff_WAVE_bext_0['coding_history'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601)));
|
$thisfile_riff_WAVE_bext_0['coding_history'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601)));
|
||||||
if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) {
|
if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) {
|
||||||
if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) {
|
if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) {
|
||||||
|
$bext_timestamp = array();
|
||||||
list($dummy, $bext_timestamp['year'], $bext_timestamp['month'], $bext_timestamp['day']) = $matches_bext_date;
|
list($dummy, $bext_timestamp['year'], $bext_timestamp['month'], $bext_timestamp['day']) = $matches_bext_date;
|
||||||
list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time;
|
list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time;
|
||||||
$thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime($bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second'], $bext_timestamp['month'], $bext_timestamp['day'], $bext_timestamp['year']);
|
$thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime($bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second'], $bext_timestamp['month'], $bext_timestamp['day'], $bext_timestamp['year']);
|
||||||
@ -451,7 +462,62 @@ class getid3_riff extends getid3_handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($thisfile_riff_WAVE['guan'][0]['data'])) {
|
||||||
|
// shortcut
|
||||||
|
$thisfile_riff_WAVE_guan_0 = &$thisfile_riff_WAVE['guan'][0];
|
||||||
|
if (!empty($thisfile_riff_WAVE_guan_0['data']) && (substr($thisfile_riff_WAVE_guan_0['data'], 0, 14) == 'GUANO|Version:')) {
|
||||||
|
$thisfile_riff['guano'] = array();
|
||||||
|
foreach (explode("\n", $thisfile_riff_WAVE_guan_0['data']) as $line) {
|
||||||
|
if ($line) {
|
||||||
|
@list($key, $value) = explode(':', $line, 2);
|
||||||
|
if (substr($value, 0, 3) == '[{"') {
|
||||||
|
if ($decoded = @json_decode($value, true)) {
|
||||||
|
if (!empty($decoded) && (count($decoded) == 1)) {
|
||||||
|
$value = $decoded[0];
|
||||||
|
} else {
|
||||||
|
$value = $decoded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$thisfile_riff['guano'] = array_merge_recursive($thisfile_riff['guano'], getid3_lib::CreateDeepArray($key, '|', $value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.wildlifeacoustics.com/SCHEMA/GUANO.html
|
||||||
|
foreach ($thisfile_riff['guano'] as $key => $value) {
|
||||||
|
switch ($key) {
|
||||||
|
case 'Loc Position':
|
||||||
|
if (preg_match('#^([\\+\\-]?[0-9]+\\.[0-9]+) ([\\+\\-]?[0-9]+\\.[0-9]+)$#', $value, $matches)) {
|
||||||
|
list($dummy, $latitude, $longitude) = $matches;
|
||||||
|
$thisfile_riff['comments']['gps_latitude'][0] = floatval($latitude);
|
||||||
|
$thisfile_riff['comments']['gps_longitude'][0] = floatval($longitude);
|
||||||
|
$thisfile_riff['guano'][$key] = floatval($latitude).' '.floatval($longitude);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'Loc Elevation': // Elevation/altitude above mean sea level in meters
|
||||||
|
$thisfile_riff['comments']['gps_altitude'][0] = floatval($value);
|
||||||
|
$thisfile_riff['guano'][$key] = (float) $value;
|
||||||
|
break;
|
||||||
|
case 'Filter HP': // High-pass filter frequency in kHz
|
||||||
|
case 'Filter LP': // Low-pass filter frequency in kHz
|
||||||
|
case 'Humidity': // Relative humidity as a percentage
|
||||||
|
case 'Length': // Recording length in seconds
|
||||||
|
case 'Loc Accuracy': // Estimated Position Error in meters
|
||||||
|
case 'Temperature Ext': // External temperature in degrees Celsius outside the recorder's housing
|
||||||
|
case 'Temperature Int': // Internal temperature in degrees Celsius inside the recorder's housing
|
||||||
|
$thisfile_riff['guano'][$key] = (float) $value;
|
||||||
|
break;
|
||||||
|
case 'Samplerate': // Recording sample rate, Hz
|
||||||
|
case 'TE': // Time-expansion factor. If not specified, then 1 (no time-expansion a.k.a. direct-recording) is assumed.
|
||||||
|
$thisfile_riff['guano'][$key] = (int) $value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$this->warning('RIFF.guan data not in expected format');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
|
if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
|
||||||
$thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
|
$thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
|
||||||
@ -733,6 +799,7 @@ class getid3_riff extends getid3_handler
|
|||||||
}
|
}
|
||||||
if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
|
if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
|
||||||
if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) {
|
if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) {
|
||||||
|
$thisfile_riff_raw_strf_strhfccType_streamindex = null;
|
||||||
for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) {
|
for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) {
|
||||||
if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
|
if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
|
||||||
$strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'];
|
$strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'];
|
||||||
@ -1069,7 +1136,7 @@ class getid3_riff extends getid3_handler
|
|||||||
if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) {
|
if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) {
|
||||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
|
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
|
||||||
$getid3_temp = new getID3();
|
$getid3_temp = new getID3();
|
||||||
$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
|
$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
|
||||||
$getid3_id3v2 = new getid3_id3v2($getid3_temp);
|
$getid3_id3v2 = new getid3_id3v2($getid3_temp);
|
||||||
$getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8;
|
$getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8;
|
||||||
if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
|
if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
|
||||||
@ -1172,7 +1239,7 @@ class getid3_riff extends getid3_handler
|
|||||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, true);
|
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, true);
|
||||||
|
|
||||||
$getid3_temp = new getID3();
|
$getid3_temp = new getID3();
|
||||||
$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
|
$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
|
||||||
$getid3_mpeg = new getid3_mpeg($getid3_temp);
|
$getid3_mpeg = new getid3_mpeg($getid3_temp);
|
||||||
$getid3_mpeg->Analyze();
|
$getid3_mpeg->Analyze();
|
||||||
if (empty($getid3_temp->info['error'])) {
|
if (empty($getid3_temp->info['error'])) {
|
||||||
@ -1258,7 +1325,7 @@ class getid3_riff extends getid3_handler
|
|||||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
|
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
|
||||||
|
|
||||||
$getid3_temp = new getID3();
|
$getid3_temp = new getID3();
|
||||||
$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
|
$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
|
||||||
$getid3_id3v2 = new getid3_id3v2($getid3_temp);
|
$getid3_id3v2 = new getid3_id3v2($getid3_temp);
|
||||||
$getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8;
|
$getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8;
|
||||||
if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
|
if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
|
||||||
@ -1514,6 +1581,9 @@ class getid3_riff extends getid3_handler
|
|||||||
|
|
||||||
$RIFFchunk = false;
|
$RIFFchunk = false;
|
||||||
$FoundAllChunksWeNeed = false;
|
$FoundAllChunksWeNeed = false;
|
||||||
|
$LISTchunkParent = null;
|
||||||
|
$LISTchunkMaxOffset = null;
|
||||||
|
$AC3syncwordBytes = pack('n', getid3_ac3::syncword); // 0x0B77 -> "\x0B\x77"
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->fseek($startoffset);
|
$this->fseek($startoffset);
|
||||||
@ -1557,7 +1627,7 @@ class getid3_riff extends getid3_handler
|
|||||||
// MP3
|
// MP3
|
||||||
if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
|
if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
|
||||||
$getid3_temp = new getID3();
|
$getid3_temp = new getID3();
|
||||||
$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
|
$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
|
||||||
$getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
|
$getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
|
||||||
$getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
|
$getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
|
||||||
$getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
|
$getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
|
||||||
@ -1575,11 +1645,10 @@ class getid3_riff extends getid3_handler
|
|||||||
unset($getid3_temp, $getid3_mp3);
|
unset($getid3_temp, $getid3_mp3);
|
||||||
}
|
}
|
||||||
|
|
||||||
} elseif (strpos($FirstFourBytes, getid3_ac3::syncword) === 0) {
|
} elseif (strpos($FirstFourBytes, $AC3syncwordBytes) === 0) {
|
||||||
|
|
||||||
// AC3
|
// AC3
|
||||||
$getid3_temp = new getID3();
|
$getid3_temp = new getID3();
|
||||||
$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
|
$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
|
||||||
$getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
|
$getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
|
||||||
$getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
|
$getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
|
||||||
$getid3_ac3 = new getid3_ac3($getid3_temp);
|
$getid3_ac3 = new getid3_ac3($getid3_temp);
|
||||||
@ -1640,7 +1709,7 @@ class getid3_riff extends getid3_handler
|
|||||||
// Probably is MP3 data
|
// Probably is MP3 data
|
||||||
if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
|
if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
|
||||||
$getid3_temp = new getID3();
|
$getid3_temp = new getID3();
|
||||||
$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
|
$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
|
||||||
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
|
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
|
||||||
$getid3_temp->info['avdataend'] = $info['avdataend'];
|
$getid3_temp->info['avdataend'] = $info['avdataend'];
|
||||||
$getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
|
$getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
|
||||||
@ -1652,12 +1721,12 @@ class getid3_riff extends getid3_handler
|
|||||||
unset($getid3_temp, $getid3_mp3);
|
unset($getid3_temp, $getid3_mp3);
|
||||||
}
|
}
|
||||||
|
|
||||||
} elseif (($isRegularAC3 = (substr($testData, 0, 2) == getid3_ac3::syncword)) || substr($testData, 8, 2) == strrev(getid3_ac3::syncword)) {
|
} elseif (($isRegularAC3 = (substr($testData, 0, 2) == $AC3syncwordBytes)) || substr($testData, 8, 2) == strrev($AC3syncwordBytes)) {
|
||||||
|
|
||||||
// This is probably AC-3 data
|
// This is probably AC-3 data
|
||||||
$getid3_temp = new getID3();
|
$getid3_temp = new getID3();
|
||||||
if ($isRegularAC3) {
|
if ($isRegularAC3) {
|
||||||
$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
|
$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
|
||||||
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
|
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
|
||||||
$getid3_temp->info['avdataend'] = $info['avdataend'];
|
$getid3_temp->info['avdataend'] = $info['avdataend'];
|
||||||
}
|
}
|
||||||
@ -1673,6 +1742,8 @@ class getid3_riff extends getid3_handler
|
|||||||
$ac3_data .= substr($testData, 8 + $i + 1, 1);
|
$ac3_data .= substr($testData, 8 + $i + 1, 1);
|
||||||
$ac3_data .= substr($testData, 8 + $i + 0, 1);
|
$ac3_data .= substr($testData, 8 + $i + 0, 1);
|
||||||
}
|
}
|
||||||
|
$getid3_ac3->getid3->info['avdataoffset'] = 0;
|
||||||
|
$getid3_ac3->getid3->info['avdataend'] = strlen($ac3_data);
|
||||||
$getid3_ac3->AnalyzeString($ac3_data);
|
$getid3_ac3->AnalyzeString($ac3_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1691,7 +1762,7 @@ class getid3_riff extends getid3_handler
|
|||||||
|
|
||||||
// This is probably DTS data
|
// This is probably DTS data
|
||||||
$getid3_temp = new getID3();
|
$getid3_temp = new getID3();
|
||||||
$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
|
$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
|
||||||
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
|
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
|
||||||
$getid3_dts = new getid3_dts($getid3_temp);
|
$getid3_dts = new getid3_dts($getid3_temp);
|
||||||
$getid3_dts->Analyze();
|
$getid3_dts->Analyze();
|
||||||
@ -1732,6 +1803,8 @@ class getid3_riff extends getid3_handler
|
|||||||
case 'indx':
|
case 'indx':
|
||||||
case 'MEXT':
|
case 'MEXT':
|
||||||
case 'DISP':
|
case 'DISP':
|
||||||
|
case 'wamd':
|
||||||
|
case 'guan':
|
||||||
// always read data in
|
// always read data in
|
||||||
case 'JUNK':
|
case 'JUNK':
|
||||||
// should be: never read data in
|
// should be: never read data in
|
||||||
@ -2076,6 +2149,7 @@ class getid3_riff extends getid3_handler
|
|||||||
*/
|
*/
|
||||||
public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) {
|
public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) {
|
||||||
|
|
||||||
|
$parsed = array();
|
||||||
$parsed['biSize'] = substr($BITMAPINFOHEADER, 0, 4); // number of bytes required by the BITMAPINFOHEADER structure
|
$parsed['biSize'] = substr($BITMAPINFOHEADER, 0, 4); // number of bytes required by the BITMAPINFOHEADER structure
|
||||||
$parsed['biWidth'] = substr($BITMAPINFOHEADER, 4, 4); // width of the bitmap in pixels
|
$parsed['biWidth'] = substr($BITMAPINFOHEADER, 4, 4); // width of the bitmap in pixels
|
||||||
$parsed['biHeight'] = substr($BITMAPINFOHEADER, 8, 4); // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner
|
$parsed['biHeight'] = substr($BITMAPINFOHEADER, 8, 4); // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner
|
||||||
|
@ -402,6 +402,7 @@ class getid3_flac extends getid3_handler
|
|||||||
public function parsePICTURE() {
|
public function parsePICTURE() {
|
||||||
$info = &$this->getid3->info;
|
$info = &$this->getid3->info;
|
||||||
|
|
||||||
|
$picture = array();
|
||||||
$picture['typeid'] = getid3_lib::BigEndian2Int($this->fread(4));
|
$picture['typeid'] = getid3_lib::BigEndian2Int($this->fread(4));
|
||||||
$picture['picturetype'] = self::pictureTypeLookup($picture['typeid']);
|
$picture['picturetype'] = self::pictureTypeLookup($picture['typeid']);
|
||||||
$picture['image_mime'] = $this->fread(getid3_lib::BigEndian2Int($this->fread(4)));
|
$picture['image_mime'] = $this->fread(getid3_lib::BigEndian2Int($this->fread(4)));
|
||||||
|
@ -18,12 +18,6 @@ if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that acce
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// number of frames to scan to determine if MPEG-audio sequence is valid
|
|
||||||
// Lower this number to 5-20 for faster scanning
|
|
||||||
// Increase this number to 50+ for most accurate detection of valid VBR/CBR
|
|
||||||
// mpeg-audio streams
|
|
||||||
define('GETID3_MP3_VALID_CHECK_FRAMES', 35);
|
|
||||||
|
|
||||||
|
|
||||||
class getid3_mp3 extends getid3_handler
|
class getid3_mp3 extends getid3_handler
|
||||||
{
|
{
|
||||||
@ -35,6 +29,15 @@ class getid3_mp3 extends getid3_handler
|
|||||||
*/
|
*/
|
||||||
public $allow_bruteforce = false;
|
public $allow_bruteforce = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* number of frames to scan to determine if MPEG-audio sequence is valid
|
||||||
|
* Lower this number to 5-20 for faster scanning
|
||||||
|
* Increase this number to 50+ for most accurate detection of valid VBR/CBR mpeg-audio streams
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $mp3_valid_check_frames = 50;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
@ -55,6 +58,7 @@ class getid3_mp3 extends getid3_handler
|
|||||||
$info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
|
$info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$CurrentDataLAMEversionString = null;
|
||||||
if (((isset($info['id3v2']['headerlength']) && ($info['avdataoffset'] > $info['id3v2']['headerlength'])) || (!isset($info['id3v2']) && ($info['avdataoffset'] > 0) && ($info['avdataoffset'] != $initialOffset)))) {
|
if (((isset($info['id3v2']['headerlength']) && ($info['avdataoffset'] > $info['id3v2']['headerlength'])) || (!isset($info['id3v2']) && ($info['avdataoffset'] > 0) && ($info['avdataoffset'] != $initialOffset)))) {
|
||||||
|
|
||||||
$synchoffsetwarning = 'Unknown data before synch ';
|
$synchoffsetwarning = 'Unknown data before synch ';
|
||||||
@ -121,6 +125,12 @@ class getid3_mp3 extends getid3_handler
|
|||||||
if (substr($PossiblyLongerLAMEversion_String, 0, strlen($CurrentDataLAMEversionString)) == $CurrentDataLAMEversionString) {
|
if (substr($PossiblyLongerLAMEversion_String, 0, strlen($CurrentDataLAMEversionString)) == $CurrentDataLAMEversionString) {
|
||||||
$PossiblyLongerLAMEversion_NewString = substr($PossiblyLongerLAMEversion_String, 0, strspn($PossiblyLongerLAMEversion_String, 'LAME0123456789., (abcdefghijklmnopqrstuvwxyzJFSOND)')); //"LAME3.90.3" "LAME3.87 (beta 1, Sep 27 2000)" "LAME3.88 (beta)"
|
$PossiblyLongerLAMEversion_NewString = substr($PossiblyLongerLAMEversion_String, 0, strspn($PossiblyLongerLAMEversion_String, 'LAME0123456789., (abcdefghijklmnopqrstuvwxyzJFSOND)')); //"LAME3.90.3" "LAME3.87 (beta 1, Sep 27 2000)" "LAME3.88 (beta)"
|
||||||
if (empty($info['audio']['encoder']) || (strlen($PossiblyLongerLAMEversion_NewString) > strlen($info['audio']['encoder']))) {
|
if (empty($info['audio']['encoder']) || (strlen($PossiblyLongerLAMEversion_NewString) > strlen($info['audio']['encoder']))) {
|
||||||
|
if (!empty($info['audio']['encoder']) && !empty($info['mpeg']['audio']['LAME']['short_version']) && ($info['audio']['encoder'] == $info['mpeg']['audio']['LAME']['short_version'])) {
|
||||||
|
if (preg_match('#^LAME[0-9\\.]+#', $PossiblyLongerLAMEversion_NewString, $matches)) {
|
||||||
|
// "LAME3.100" -> "LAME3.100.1", but avoid including "(alpha)" and similar
|
||||||
|
$info['mpeg']['audio']['LAME']['short_version'] = $matches[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
$info['audio']['encoder'] = $PossiblyLongerLAMEversion_NewString;
|
$info['audio']['encoder'] = $PossiblyLongerLAMEversion_NewString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,7 +305,7 @@ class getid3_mp3 extends getid3_handler
|
|||||||
} elseif (!empty($info['audio']['bitrate'])) {
|
} elseif (!empty($info['audio']['bitrate'])) {
|
||||||
|
|
||||||
if ($info['audio']['bitrate_mode'] == 'cbr') {
|
if ($info['audio']['bitrate_mode'] == 'cbr') {
|
||||||
$encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
|
$encoder_options = strtoupper($info['audio']['bitrate_mode']).round($info['audio']['bitrate'] / 1000);
|
||||||
} else {
|
} else {
|
||||||
$encoder_options = strtoupper($info['audio']['bitrate_mode']);
|
$encoder_options = strtoupper($info['audio']['bitrate_mode']);
|
||||||
}
|
}
|
||||||
@ -488,7 +498,7 @@ class getid3_mp3 extends getid3_handler
|
|||||||
if ($MPEGaudioHeaderValidCache[$head4_key]) {
|
if ($MPEGaudioHeaderValidCache[$head4_key]) {
|
||||||
$thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray;
|
$thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray;
|
||||||
} else {
|
} else {
|
||||||
$this->error('Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset);
|
$this->warning('Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -722,15 +732,17 @@ class getid3_mp3 extends getid3_handler
|
|||||||
|
|
||||||
$thisfile_mpeg_audio_lame['long_version'] = substr($headerstring, $VBRidOffset + 120, 20);
|
$thisfile_mpeg_audio_lame['long_version'] = substr($headerstring, $VBRidOffset + 120, 20);
|
||||||
$thisfile_mpeg_audio_lame['short_version'] = substr($thisfile_mpeg_audio_lame['long_version'], 0, 9);
|
$thisfile_mpeg_audio_lame['short_version'] = substr($thisfile_mpeg_audio_lame['long_version'], 0, 9);
|
||||||
$thisfile_mpeg_audio_lame['numeric_version'] = str_replace('LAME', '', $thisfile_mpeg_audio_lame['short_version']);
|
|
||||||
if (preg_match('#^LAME([0-9\\.a-z]+)#', $thisfile_mpeg_audio_lame['long_version'], $matches)) {
|
//$thisfile_mpeg_audio_lame['numeric_version'] = str_replace('LAME', '', $thisfile_mpeg_audio_lame['short_version']);
|
||||||
|
$thisfile_mpeg_audio_lame['numeric_version'] = '';
|
||||||
|
if (preg_match('#^LAME([0-9\\.a-z]*)#', $thisfile_mpeg_audio_lame['long_version'], $matches)) {
|
||||||
$thisfile_mpeg_audio_lame['short_version'] = $matches[0];
|
$thisfile_mpeg_audio_lame['short_version'] = $matches[0];
|
||||||
$thisfile_mpeg_audio_lame['numeric_version'] = $matches[1];
|
$thisfile_mpeg_audio_lame['numeric_version'] = $matches[1];
|
||||||
}
|
}
|
||||||
|
if (strlen($thisfile_mpeg_audio_lame['numeric_version']) > 0) {
|
||||||
foreach (explode('.', $thisfile_mpeg_audio_lame['numeric_version']) as $key => $number) {
|
foreach (explode('.', $thisfile_mpeg_audio_lame['numeric_version']) as $key => $number) {
|
||||||
$thisfile_mpeg_audio_lame['integer_version'][$key] = intval($number);
|
$thisfile_mpeg_audio_lame['integer_version'][$key] = intval($number);
|
||||||
}
|
}
|
||||||
|
|
||||||
//if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') {
|
//if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') {
|
||||||
if ((($thisfile_mpeg_audio_lame['integer_version'][0] * 1000) + $thisfile_mpeg_audio_lame['integer_version'][1]) >= 3090) { // cannot use string version compare, may have "LAME3.90" or "LAME3.100" -- see https://github.com/JamesHeinrich/getID3/issues/207
|
if ((($thisfile_mpeg_audio_lame['integer_version'][0] * 1000) + $thisfile_mpeg_audio_lame['integer_version'][1]) >= 3090) { // cannot use string version compare, may have "LAME3.90" or "LAME3.100" -- see https://github.com/JamesHeinrich/getID3/issues/207
|
||||||
|
|
||||||
@ -915,6 +927,7 @@ class getid3_mp3 extends getid3_handler
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -1009,6 +1022,22 @@ class getid3_mp3 extends getid3_handler
|
|||||||
if (!$this->RecursiveFrameScanning($offset, $nextframetestoffset, $ScanAsCBR)) {
|
if (!$this->RecursiveFrameScanning($offset, $nextframetestoffset, $ScanAsCBR)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!empty($this->getid3->info['mp3_validity_check_bitrates']) && !empty($thisfile_mpeg_audio['bitrate_mode']) && ($thisfile_mpeg_audio['bitrate_mode'] == 'vbr') && !empty($thisfile_mpeg_audio['VBR_bitrate'])) {
|
||||||
|
// https://github.com/JamesHeinrich/getID3/issues/287
|
||||||
|
if (count(array_keys($this->getid3->info['mp3_validity_check_bitrates'])) == 1) {
|
||||||
|
list($cbr_bitrate_in_short_scan) = array_keys($this->getid3->info['mp3_validity_check_bitrates']);
|
||||||
|
$deviation_cbr_from_header_bitrate = abs($thisfile_mpeg_audio['VBR_bitrate'] - $cbr_bitrate_in_short_scan) / $cbr_bitrate_in_short_scan;
|
||||||
|
if ($deviation_cbr_from_header_bitrate < 0.01) {
|
||||||
|
// VBR header bitrate may differ slightly from true bitrate of frames, perhaps accounting for overhead of VBR header frame itself?
|
||||||
|
// If measured CBR bitrate is within 1% of specified bitrate in VBR header then assume that file is truly CBR
|
||||||
|
$thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
|
||||||
|
//$this->warning('VBR header ignored, assuming CBR '.round($cbr_bitrate_in_short_scan / 1000).'kbps based on scan of '.$this->mp3_valid_check_frames.' frames');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isset($this->getid3->info['mp3_validity_check_bitrates'])) {
|
||||||
|
unset($this->getid3->info['mp3_validity_check_bitrates']);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1130,8 +1159,9 @@ class getid3_mp3 extends getid3_handler
|
|||||||
$firstframetestarray = array('error' => array(), 'warning'=> array(), 'avdataend' => $info['avdataend'], 'avdataoffset' => $info['avdataoffset']);
|
$firstframetestarray = array('error' => array(), 'warning'=> array(), 'avdataend' => $info['avdataend'], 'avdataoffset' => $info['avdataoffset']);
|
||||||
$this->decodeMPEGaudioHeader($offset, $firstframetestarray, false);
|
$this->decodeMPEGaudioHeader($offset, $firstframetestarray, false);
|
||||||
|
|
||||||
for ($i = 0; $i < GETID3_MP3_VALID_CHECK_FRAMES; $i++) {
|
$info['mp3_validity_check_bitrates'] = array();
|
||||||
// check next GETID3_MP3_VALID_CHECK_FRAMES frames for validity, to make sure we haven't run across a false synch
|
for ($i = 0; $i < $this->mp3_valid_check_frames; $i++) {
|
||||||
|
// check next (default: 50) frames for validity, to make sure we haven't run across a false synch
|
||||||
if (($nextframetestoffset + 4) >= $info['avdataend']) {
|
if (($nextframetestoffset + 4) >= $info['avdataend']) {
|
||||||
// end of file
|
// end of file
|
||||||
return true;
|
return true;
|
||||||
@ -1139,6 +1169,7 @@ class getid3_mp3 extends getid3_handler
|
|||||||
|
|
||||||
$nextframetestarray = array('error' => array(), 'warning' => array(), 'avdataend' => $info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
|
$nextframetestarray = array('error' => array(), 'warning' => array(), 'avdataend' => $info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
|
||||||
if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) {
|
if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) {
|
||||||
|
getid3_lib::safe_inc($info['mp3_validity_check_bitrates'][$nextframetestarray['mpeg']['audio']['bitrate']]);
|
||||||
if ($ScanAsCBR) {
|
if ($ScanAsCBR) {
|
||||||
// force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header
|
// force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header
|
||||||
if (!isset($nextframetestarray['mpeg']['audio']['bitrate']) || !isset($firstframetestarray['mpeg']['audio']['bitrate']) || ($nextframetestarray['mpeg']['audio']['bitrate'] != $firstframetestarray['mpeg']['audio']['bitrate'])) {
|
if (!isset($nextframetestarray['mpeg']['audio']['bitrate']) || !isset($firstframetestarray['mpeg']['audio']['bitrate']) || ($nextframetestarray['mpeg']['audio']['bitrate'] != $firstframetestarray['mpeg']['audio']['bitrate'])) {
|
||||||
@ -1273,6 +1304,7 @@ class getid3_mp3 extends getid3_handler
|
|||||||
$LongMPEGbitrateLookup = array();
|
$LongMPEGbitrateLookup = array();
|
||||||
$LongMPEGpaddingLookup = array();
|
$LongMPEGpaddingLookup = array();
|
||||||
$LongMPEGfrequencyLookup = array();
|
$LongMPEGfrequencyLookup = array();
|
||||||
|
$Distribution = array();
|
||||||
$Distribution['bitrate'] = array();
|
$Distribution['bitrate'] = array();
|
||||||
$Distribution['frequency'] = array();
|
$Distribution['frequency'] = array();
|
||||||
$Distribution['layer'] = array();
|
$Distribution['layer'] = array();
|
||||||
@ -1433,6 +1465,9 @@ class getid3_mp3 extends getid3_handler
|
|||||||
$header = $this->fread($sync_seek_buffer_size);
|
$header = $this->fread($sync_seek_buffer_size);
|
||||||
$sync_seek_buffer_size = strlen($header);
|
$sync_seek_buffer_size = strlen($header);
|
||||||
$SynchSeekOffset = 0;
|
$SynchSeekOffset = 0;
|
||||||
|
$SyncSeekAttempts = 0;
|
||||||
|
$SyncSeekAttemptsMax = 1000;
|
||||||
|
$FirstFrameThisfileInfo = null;
|
||||||
while ($SynchSeekOffset < $sync_seek_buffer_size) {
|
while ($SynchSeekOffset < $sync_seek_buffer_size) {
|
||||||
if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !feof($this->getid3->fp)) {
|
if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !feof($this->getid3->fp)) {
|
||||||
|
|
||||||
@ -1471,7 +1506,24 @@ class getid3_mp3 extends getid3_handler
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($header[$SynchSeekOffset] == "\xFF") && ($header[($SynchSeekOffset + 1)] > "\xE0")) { // synch detected
|
if (($header[$SynchSeekOffset] == "\xFF") && ($header[($SynchSeekOffset + 1)] > "\xE0")) { // possible synch detected
|
||||||
|
if (++$SyncSeekAttempts >= $SyncSeekAttemptsMax) {
|
||||||
|
// https://github.com/JamesHeinrich/getID3/issues/286
|
||||||
|
// corrupt files claiming to be MP3, with a large number of 0xFF bytes near the beginning, can cause this loop to take a very long time
|
||||||
|
// should have escape condition to avoid spending too much time scanning a corrupt file
|
||||||
|
// if a synch's not found within the first 128k bytes, then give up
|
||||||
|
$this->error('Could not find valid MPEG audio synch after scanning '.$SyncSeekAttempts.' candidate offsets');
|
||||||
|
if (isset($info['audio']['bitrate'])) {
|
||||||
|
unset($info['audio']['bitrate']);
|
||||||
|
}
|
||||||
|
if (isset($info['mpeg']['audio'])) {
|
||||||
|
unset($info['mpeg']['audio']);
|
||||||
|
}
|
||||||
|
if (empty($info['mpeg'])) {
|
||||||
|
unset($info['mpeg']);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
$FirstFrameAVDataOffset = null;
|
$FirstFrameAVDataOffset = null;
|
||||||
if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) {
|
if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) {
|
||||||
$FirstFrameThisfileInfo = $info;
|
$FirstFrameThisfileInfo = $info;
|
||||||
@ -1511,9 +1563,9 @@ class getid3_mp3 extends getid3_handler
|
|||||||
if ($this->decodeMPEGaudioHeader($GarbageOffsetEnd, $dummy, true, true)) {
|
if ($this->decodeMPEGaudioHeader($GarbageOffsetEnd, $dummy, true, true)) {
|
||||||
$info = $dummy;
|
$info = $dummy;
|
||||||
$info['avdataoffset'] = $GarbageOffsetEnd;
|
$info['avdataoffset'] = $GarbageOffsetEnd;
|
||||||
$this->warning('apparently-valid VBR header not used because could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.'), but did find valid CBR stream starting at '.$GarbageOffsetEnd);
|
$this->warning('apparently-valid VBR header not used because could not find '.$this->mp3_valid_check_frames.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.'), but did find valid CBR stream starting at '.$GarbageOffsetEnd);
|
||||||
} else {
|
} else {
|
||||||
$this->warning('using data from VBR header even though could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')');
|
$this->warning('using data from VBR header even though could not find '.$this->mp3_valid_check_frames.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1558,6 +1610,7 @@ class getid3_mp3 extends getid3_handler
|
|||||||
$pct_data_scanned = 0;
|
$pct_data_scanned = 0;
|
||||||
for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) {
|
for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) {
|
||||||
$frames_scanned_this_segment = 0;
|
$frames_scanned_this_segment = 0;
|
||||||
|
$scan_start_offset = array();
|
||||||
if ($this->ftell() >= $info['avdataend']) {
|
if ($this->ftell() >= $info['avdataend']) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1887,6 +1940,7 @@ class getid3_mp3 extends getid3_handler
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$MPEGrawHeader = array();
|
||||||
$MPEGrawHeader['synch'] = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4;
|
$MPEGrawHeader['synch'] = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4;
|
||||||
$MPEGrawHeader['version'] = (ord($Header4Bytes[1]) & 0x18) >> 3; // BB
|
$MPEGrawHeader['version'] = (ord($Header4Bytes[1]) & 0x18) >> 3; // BB
|
||||||
$MPEGrawHeader['layer'] = (ord($Header4Bytes[1]) & 0x06) >> 1; // CC
|
$MPEGrawHeader['layer'] = (ord($Header4Bytes[1]) & 0x06) >> 1; // CC
|
||||||
|
@ -529,6 +529,7 @@ class getid3_ogg extends getid3_handler
|
|||||||
*/
|
*/
|
||||||
public function ParseOggPageHeader() {
|
public function ParseOggPageHeader() {
|
||||||
// http://xiph.org/ogg/vorbis/doc/framing.html
|
// http://xiph.org/ogg/vorbis/doc/framing.html
|
||||||
|
$oggheader = array();
|
||||||
$oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file
|
$oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file
|
||||||
|
|
||||||
$filedata = $this->fread($this->getid3->fread_buffer_size());
|
$filedata = $this->fread($this->getid3->fread_buffer_size());
|
||||||
@ -680,7 +681,7 @@ class getid3_ogg extends getid3_handler
|
|||||||
|
|
||||||
$VorbisCommentPage++;
|
$VorbisCommentPage++;
|
||||||
|
|
||||||
$oggpageinfo = $this->ParseOggPageHeader();
|
if ($oggpageinfo = $this->ParseOggPageHeader()) {
|
||||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
|
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
|
||||||
|
|
||||||
// First, save what we haven't read yet
|
// First, save what we haven't read yet
|
||||||
@ -709,6 +710,10 @@ class getid3_ogg extends getid3_handler
|
|||||||
$commentdata .= $this->fread($readlength);
|
$commentdata .= $this->fread($readlength);
|
||||||
|
|
||||||
//$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];
|
//$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];
|
||||||
|
} else {
|
||||||
|
$this->warning('failed to ParseOggPageHeader() at offset '.$this->ftell());
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$ThisFileInfo_ogg_comments_raw[$i]['offset'] = $commentdataoffset;
|
$ThisFileInfo_ogg_comments_raw[$i]['offset'] = $commentdataoffset;
|
||||||
$commentstring = substr($commentdata, $commentdataoffset, $ThisFileInfo_ogg_comments_raw[$i]['size']);
|
$commentstring = substr($commentdata, $commentdataoffset, $ThisFileInfo_ogg_comments_raw[$i]['size']);
|
||||||
|
@ -360,6 +360,7 @@ class getid3_apetag extends getid3_handler
|
|||||||
// http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html
|
// http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html
|
||||||
|
|
||||||
// shortcut
|
// shortcut
|
||||||
|
$headerfooterinfo = array();
|
||||||
$headerfooterinfo['raw'] = array();
|
$headerfooterinfo['raw'] = array();
|
||||||
$headerfooterinfo_raw = &$headerfooterinfo['raw'];
|
$headerfooterinfo_raw = &$headerfooterinfo['raw'];
|
||||||
|
|
||||||
@ -389,6 +390,7 @@ class getid3_apetag extends getid3_handler
|
|||||||
// "Note: APE Tags 1.0 do not use any of the APE Tag flags.
|
// "Note: APE Tags 1.0 do not use any of the APE Tag flags.
|
||||||
// All are set to zero on creation and ignored on reading."
|
// All are set to zero on creation and ignored on reading."
|
||||||
// http://wiki.hydrogenaud.io/index.php?title=Ape_Tags_Flags
|
// http://wiki.hydrogenaud.io/index.php?title=Ape_Tags_Flags
|
||||||
|
$flags = array();
|
||||||
$flags['header'] = (bool) ($rawflagint & 0x80000000);
|
$flags['header'] = (bool) ($rawflagint & 0x80000000);
|
||||||
$flags['footer'] = (bool) ($rawflagint & 0x40000000);
|
$flags['footer'] = (bool) ($rawflagint & 0x40000000);
|
||||||
$flags['this_is_header'] = (bool) ($rawflagint & 0x20000000);
|
$flags['this_is_header'] = (bool) ($rawflagint & 0x20000000);
|
||||||
|
@ -31,14 +31,22 @@ class getid3_id3v1 extends getid3_handler
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($info['filesize'] < 256) {
|
||||||
|
$this->fseek(-128, SEEK_END);
|
||||||
|
$preid3v1 = '';
|
||||||
|
$id3v1tag = $this->fread(128);
|
||||||
|
} else {
|
||||||
$this->fseek(-256, SEEK_END);
|
$this->fseek(-256, SEEK_END);
|
||||||
$preid3v1 = $this->fread(128);
|
$preid3v1 = $this->fread(128);
|
||||||
$id3v1tag = $this->fread(128);
|
$id3v1tag = $this->fread(128);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (substr($id3v1tag, 0, 3) == 'TAG') {
|
if (substr($id3v1tag, 0, 3) == 'TAG') {
|
||||||
|
|
||||||
$info['avdataend'] = $info['filesize'] - 128;
|
$info['avdataend'] = $info['filesize'] - 128;
|
||||||
|
|
||||||
|
$ParsedID3v1 = array();
|
||||||
$ParsedID3v1['title'] = $this->cutfield(substr($id3v1tag, 3, 30));
|
$ParsedID3v1['title'] = $this->cutfield(substr($id3v1tag, 3, 30));
|
||||||
$ParsedID3v1['artist'] = $this->cutfield(substr($id3v1tag, 33, 30));
|
$ParsedID3v1['artist'] = $this->cutfield(substr($id3v1tag, 33, 30));
|
||||||
$ParsedID3v1['album'] = $this->cutfield(substr($id3v1tag, 63, 30));
|
$ParsedID3v1['album'] = $this->cutfield(substr($id3v1tag, 63, 30));
|
||||||
@ -297,6 +305,50 @@ class getid3_id3v1 extends getid3_handler
|
|||||||
145 => 'Anime',
|
145 => 'Anime',
|
||||||
146 => 'JPop',
|
146 => 'JPop',
|
||||||
147 => 'Synthpop',
|
147 => 'Synthpop',
|
||||||
|
148 => 'Abstract',
|
||||||
|
149 => 'Art Rock',
|
||||||
|
150 => 'Baroque',
|
||||||
|
151 => 'Bhangra',
|
||||||
|
152 => 'Big Beat',
|
||||||
|
153 => 'Breakbeat',
|
||||||
|
154 => 'Chillout',
|
||||||
|
155 => 'Downtempo',
|
||||||
|
156 => 'Dub',
|
||||||
|
157 => 'EBM',
|
||||||
|
158 => 'Eclectic',
|
||||||
|
159 => 'Electro',
|
||||||
|
160 => 'Electroclash',
|
||||||
|
161 => 'Emo',
|
||||||
|
162 => 'Experimental',
|
||||||
|
163 => 'Garage',
|
||||||
|
164 => 'Global',
|
||||||
|
165 => 'IDM',
|
||||||
|
166 => 'Illbient',
|
||||||
|
167 => 'Industro-Goth',
|
||||||
|
168 => 'Jam Band',
|
||||||
|
169 => 'Krautrock',
|
||||||
|
170 => 'Leftfield',
|
||||||
|
171 => 'Lounge',
|
||||||
|
172 => 'Math Rock',
|
||||||
|
173 => 'New Romantic',
|
||||||
|
174 => 'Nu-Breakz',
|
||||||
|
175 => 'Post-Punk',
|
||||||
|
176 => 'Post-Rock',
|
||||||
|
177 => 'Psytrance',
|
||||||
|
178 => 'Shoegaze',
|
||||||
|
179 => 'Space Rock',
|
||||||
|
180 => 'Trop Rock',
|
||||||
|
181 => 'World Music',
|
||||||
|
182 => 'Neoclassical',
|
||||||
|
183 => 'Audiobook',
|
||||||
|
184 => 'Audio Theatre',
|
||||||
|
185 => 'Neue Deutsche Welle',
|
||||||
|
186 => 'Podcast',
|
||||||
|
187 => 'Indie-Rock',
|
||||||
|
188 => 'G-Funk',
|
||||||
|
189 => 'Dubstep',
|
||||||
|
190 => 'Garage Rock',
|
||||||
|
191 => 'Psybient',
|
||||||
|
|
||||||
255 => 'Unknown',
|
255 => 'Unknown',
|
||||||
|
|
||||||
|
@ -345,7 +345,7 @@ class getid3_id3v2 extends getid3_handler
|
|||||||
}
|
}
|
||||||
if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) {
|
if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) {
|
||||||
|
|
||||||
unset($parsedFrame);
|
$parsedFrame = array();
|
||||||
$parsedFrame['frame_name'] = $frame_name;
|
$parsedFrame['frame_name'] = $frame_name;
|
||||||
$parsedFrame['frame_flags_raw'] = $frame_flags;
|
$parsedFrame['frame_flags_raw'] = $frame_flags;
|
||||||
$parsedFrame['data'] = substr($framedata, 0, $frame_size);
|
$parsedFrame['data'] = substr($framedata, 0, $frame_size);
|
||||||
@ -994,6 +994,7 @@ class getid3_id3v2 extends getid3_handler
|
|||||||
$this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
|
$this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
|
||||||
$frame_textencoding_terminator = "\x00";
|
$frame_textencoding_terminator = "\x00";
|
||||||
}
|
}
|
||||||
|
if (strlen($parsedFrame['data']) >= (4 + strlen($frame_textencoding_terminator))) { // shouldn't be an issue but badly-written files have been spotted in the wild with not only no contents but also missing the required language field, see https://github.com/JamesHeinrich/getID3/issues/315
|
||||||
$frame_language = substr($parsedFrame['data'], $frame_offset, 3);
|
$frame_language = substr($parsedFrame['data'], $frame_offset, 3);
|
||||||
$frame_offset += 3;
|
$frame_offset += 3;
|
||||||
$frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
|
$frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
|
||||||
@ -1013,6 +1014,9 @@ class getid3_id3v2 extends getid3_handler
|
|||||||
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
|
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
|
||||||
$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
|
$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$this->warning('Invalid data in frame "'.$parsedFrame['frame_name'].'" at offset '.$parsedFrame['dataoffset']);
|
||||||
|
}
|
||||||
unset($parsedFrame['data']);
|
unset($parsedFrame['data']);
|
||||||
|
|
||||||
|
|
||||||
@ -1370,6 +1374,8 @@ class getid3_id3v2 extends getid3_handler
|
|||||||
$frame_textencoding_terminator = "\x00";
|
$frame_textencoding_terminator = "\x00";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$frame_imagetype = null;
|
||||||
|
$frame_mimetype = null;
|
||||||
if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) {
|
if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) {
|
||||||
$frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3);
|
$frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3);
|
||||||
if (strtolower($frame_imagetype) == 'ima') {
|
if (strtolower($frame_imagetype) == 'ima') {
|
||||||
@ -1956,18 +1962,14 @@ class getid3_id3v2 extends getid3_handler
|
|||||||
$frame_offset = 0;
|
$frame_offset = 0;
|
||||||
$parsedFrame['peakamplitude'] = getid3_lib::BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4));
|
$parsedFrame['peakamplitude'] = getid3_lib::BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4));
|
||||||
$frame_offset += 4;
|
$frame_offset += 4;
|
||||||
$rg_track_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
|
foreach (array('track','album') as $rgad_entry_type) {
|
||||||
|
$rg_adjustment_word = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
|
||||||
$frame_offset += 2;
|
$frame_offset += 2;
|
||||||
$rg_album_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
|
$parsedFrame['raw'][$rgad_entry_type]['name'] = ($rg_adjustment_word & 0xE000) >> 13;
|
||||||
$frame_offset += 2;
|
$parsedFrame['raw'][$rgad_entry_type]['originator'] = ($rg_adjustment_word & 0x1C00) >> 10;
|
||||||
$parsedFrame['raw']['track']['name'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 0, 3));
|
$parsedFrame['raw'][$rgad_entry_type]['signbit'] = ($rg_adjustment_word & 0x0200) >> 9;
|
||||||
$parsedFrame['raw']['track']['originator'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 3, 3));
|
$parsedFrame['raw'][$rgad_entry_type]['adjustment'] = ($rg_adjustment_word & 0x0100);
|
||||||
$parsedFrame['raw']['track']['signbit'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 6, 1));
|
}
|
||||||
$parsedFrame['raw']['track']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 7, 9));
|
|
||||||
$parsedFrame['raw']['album']['name'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 0, 3));
|
|
||||||
$parsedFrame['raw']['album']['originator'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 3, 3));
|
|
||||||
$parsedFrame['raw']['album']['signbit'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 6, 1));
|
|
||||||
$parsedFrame['raw']['album']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 7, 9));
|
|
||||||
$parsedFrame['track']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['track']['name']);
|
$parsedFrame['track']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['track']['name']);
|
||||||
$parsedFrame['track']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['track']['originator']);
|
$parsedFrame['track']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['track']['originator']);
|
||||||
$parsedFrame['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['track']['adjustment'], $parsedFrame['raw']['track']['signbit']);
|
$parsedFrame['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['track']['adjustment'], $parsedFrame['raw']['track']['signbit']);
|
||||||
@ -2444,7 +2446,8 @@ class getid3_id3v2 extends getid3_handler
|
|||||||
TMM Manats
|
TMM Manats
|
||||||
TND Dinars
|
TND Dinars
|
||||||
TOP Pa'anga
|
TOP Pa'anga
|
||||||
TRL Liras
|
TRL Liras (old)
|
||||||
|
TRY Liras
|
||||||
TTD Dollars
|
TTD Dollars
|
||||||
TVD Tuvalu Dollars
|
TVD Tuvalu Dollars
|
||||||
TWD New Dollars
|
TWD New Dollars
|
||||||
@ -2645,6 +2648,7 @@ class getid3_id3v2 extends getid3_handler
|
|||||||
TND Tunisia
|
TND Tunisia
|
||||||
TOP Tonga
|
TOP Tonga
|
||||||
TRL Turkey
|
TRL Turkey
|
||||||
|
TRY Turkey
|
||||||
TTD Trinidad and Tobago
|
TTD Trinidad and Tobago
|
||||||
TVD Tuvalu
|
TVD Tuvalu
|
||||||
TWD Taiwan
|
TWD Taiwan
|
||||||
|
@ -33,6 +33,9 @@ class getid3_lyrics3 extends getid3_handler
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->fseek((0 - 128 - 9 - 6), SEEK_END); // end - ID3v1 - "LYRICSEND" - [Lyrics3size]
|
$this->fseek((0 - 128 - 9 - 6), SEEK_END); // end - ID3v1 - "LYRICSEND" - [Lyrics3size]
|
||||||
|
$lyrics3offset = null;
|
||||||
|
$lyrics3version = null;
|
||||||
|
$lyrics3size = null;
|
||||||
$lyrics3_id3v1 = $this->fread(128 + 9 + 6);
|
$lyrics3_id3v1 = $this->fread(128 + 9 + 6);
|
||||||
$lyrics3lsz = (int) substr($lyrics3_id3v1, 0, 6); // Lyrics3size
|
$lyrics3lsz = (int) substr($lyrics3_id3v1, 0, 6); // Lyrics3size
|
||||||
$lyrics3end = substr($lyrics3_id3v1, 6, 9); // LYRICSEND or LYRICS200
|
$lyrics3end = substr($lyrics3_id3v1, 6, 9); // LYRICSEND or LYRICS200
|
||||||
|
@ -625,3 +625,4 @@ Reference material:
|
|||||||
* http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
|
* http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
|
||||||
* http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header
|
* http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header
|
||||||
* http://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf
|
* http://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf
|
||||||
|
* https://fileformats.fandom.com/wiki/Torrent_file
|
@ -16,7 +16,7 @@
|
|||||||
*
|
*
|
||||||
* @global string $wp_version
|
* @global string $wp_version
|
||||||
*/
|
*/
|
||||||
$wp_version = '5.9-alpha-52253';
|
$wp_version = '5.9-alpha-52254';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||||
|
Loading…
Reference in New Issue
Block a user