Update getID3 library to fix issues with PHP7.4
Updates to trunk version that includes fixes for PHP7.4 Changelog: https://github.com/JamesHeinrich/getID3/compare/v1.9.14...00f3fbfd77e583099ca70a3cf0bc092e113d2b20 See: #47751,#47783. Fixes: #48040. Built from https://develop.svn.wordpress.org/trunk@46112 git-svn-id: http://core.svn.wordpress.org/trunk@45924 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
b7fbf7d373
commit
1ed691f574
File diff suppressed because it is too large
Load Diff
|
@ -1,10 +1,9 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// Please see readme.txt for more information //
|
||||
// ///
|
||||
|
@ -26,6 +25,14 @@ if (!defined('ENT_SUBSTITUTE')) { // PHP5.3 adds ENT_IGNORE, PHP5.4 adds ENT_SUB
|
|||
define('ENT_SUBSTITUTE', (defined('ENT_IGNORE') ? ENT_IGNORE : 8));
|
||||
}
|
||||
|
||||
/*
|
||||
https://www.getid3.org/phpBB3/viewtopic.php?t=2114
|
||||
If you are running into a the problem where filenames with special characters are being handled
|
||||
incorrectly by external helper programs (e.g. metaflac), notably with the special characters removed,
|
||||
and you are passing in the filename in UTF8 (typically via a HTML form), try uncommenting this line:
|
||||
*/
|
||||
//setlocale(LC_CTYPE, 'en_US.UTF-8');
|
||||
|
||||
// attempt to define temp dir as something flexible but reliable
|
||||
$temp_dir = ini_get('upload_tmp_dir');
|
||||
if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) {
|
||||
|
@ -74,53 +81,190 @@ unset($open_basedir, $temp_dir);
|
|||
|
||||
class getID3
|
||||
{
|
||||
// public: Settings
|
||||
public $encoding = 'UTF-8'; // CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE
|
||||
public $encoding_id3v1 = 'ISO-8859-1'; // Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' or 'CP1252'
|
||||
/*
|
||||
* Settings
|
||||
*/
|
||||
|
||||
// public: Optional tag checks - disable for speed.
|
||||
public $option_tag_id3v1 = true; // Read and process ID3v1 tags
|
||||
public $option_tag_id3v2 = true; // Read and process ID3v2 tags
|
||||
public $option_tag_lyrics3 = true; // Read and process Lyrics3 tags
|
||||
public $option_tag_apetag = true; // Read and process APE tags
|
||||
public $option_tags_process = true; // Copy tags to root key 'tags' and encode to $this->encoding
|
||||
public $option_tags_html = true; // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
|
||||
/**
|
||||
* CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $encoding = 'UTF-8';
|
||||
|
||||
// public: Optional tag/comment calucations
|
||||
public $option_extra_info = true; // Calculate additional info such as bitrate, channelmode etc
|
||||
/**
|
||||
* Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' or 'CP1252'
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $encoding_id3v1 = 'ISO-8859-1';
|
||||
|
||||
// public: Optional handling of embedded attachments (e.g. images)
|
||||
public $option_save_attachments = true; // defaults to true (ATTACHMENTS_INLINE) for backward compatibility
|
||||
/*
|
||||
* Optional tag checks - disable for speed.
|
||||
*/
|
||||
|
||||
// public: Optional calculations
|
||||
public $option_md5_data = false; // Get MD5 sum of data part - slow
|
||||
public $option_md5_data_source = false; // Use MD5 of source file if availble - only FLAC and OptimFROG
|
||||
public $option_sha1_data = false; // Get SHA1 sum of data part - slow
|
||||
public $option_max_2gb_check = null; // Check whether file is larger than 2GB and thus not supported by 32-bit PHP (null: auto-detect based on PHP_INT_MAX)
|
||||
/**
|
||||
* Read and process ID3v1 tags
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $option_tag_id3v1 = true;
|
||||
|
||||
// public: Read buffer size in bytes
|
||||
/**
|
||||
* Read and process ID3v2 tags
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $option_tag_id3v2 = true;
|
||||
|
||||
/**
|
||||
* Read and process Lyrics3 tags
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $option_tag_lyrics3 = true;
|
||||
|
||||
/**
|
||||
* Read and process APE tags
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $option_tag_apetag = true;
|
||||
|
||||
/**
|
||||
* Copy tags to root key 'tags' and encode to $this->encoding
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $option_tags_process = true;
|
||||
|
||||
/**
|
||||
* Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $option_tags_html = true;
|
||||
|
||||
/*
|
||||
* Optional tag/comment calculations
|
||||
*/
|
||||
|
||||
/**
|
||||
* Calculate additional info such as bitrate, channelmode etc
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $option_extra_info = true;
|
||||
|
||||
/*
|
||||
* Optional handling of embedded attachments (e.g. images)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defaults to true (ATTACHMENTS_INLINE) for backward compatibility
|
||||
*
|
||||
* @var bool|string
|
||||
*/
|
||||
public $option_save_attachments = true;
|
||||
|
||||
/*
|
||||
* Optional calculations
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get MD5 sum of data part - slow
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $option_md5_data = false;
|
||||
|
||||
/**
|
||||
* Use MD5 of source file if availble - only FLAC and OptimFROG
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $option_md5_data_source = false;
|
||||
|
||||
/**
|
||||
* Get SHA1 sum of data part - slow
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $option_sha1_data = false;
|
||||
|
||||
/**
|
||||
* Check whether file is larger than 2GB and thus not supported by 32-bit PHP (null: auto-detect based on
|
||||
* PHP_INT_MAX)
|
||||
*
|
||||
* @var bool|null
|
||||
*/
|
||||
public $option_max_2gb_check;
|
||||
|
||||
/**
|
||||
* Read buffer size in bytes
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $option_fread_buffer_size = 32768;
|
||||
|
||||
// Public variables
|
||||
public $filename; // Filename of file being analysed.
|
||||
public $fp; // Filepointer to file being analysed.
|
||||
public $info; // Result array.
|
||||
|
||||
/**
|
||||
* Filename of file being analysed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $filename;
|
||||
|
||||
/**
|
||||
* Filepointer to file being analysed.
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
public $fp;
|
||||
|
||||
/**
|
||||
* Result array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $info;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $tempdir = GETID3_TEMP_DIR;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $memory_limit = 0;
|
||||
|
||||
// Protected variables
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $startup_error = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $startup_warning = '';
|
||||
|
||||
const VERSION = '1.9.14-201706111222';
|
||||
const VERSION = '1.9.17-201907240906';
|
||||
const FREAD_BUFFER_SIZE = 32768;
|
||||
|
||||
const ATTACHMENTS_NONE = false;
|
||||
const ATTACHMENTS_INLINE = true;
|
||||
|
||||
// public: constructor
|
||||
public function __construct() {
|
||||
|
||||
// Check for PHP version
|
||||
$required_php_version = '5.3.0';
|
||||
if (version_compare(PHP_VERSION, $required_php_version, '<')) {
|
||||
$this->startup_error .= 'getID3() requires PHP v'.$required_php_version.' or higher - you are running v'.PHP_VERSION."\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Check memory
|
||||
$this->memory_limit = ini_get('memory_limit');
|
||||
if (preg_match('#([0-9]+) ?M#i', $this->memory_limit, $matches)) {
|
||||
|
@ -176,7 +320,7 @@ class getID3
|
|||
|
||||
// Needed for Windows only:
|
||||
// Define locations of helper applications for Shorten, VorbisComment, MetaFLAC
|
||||
// as well as other helper functions such as head, tail, md5sum, etc
|
||||
// as well as other helper functions such as head, etc
|
||||
// This path cannot contain spaces, but the below code will attempt to get the
|
||||
// 8.3-equivalent path automatically
|
||||
// IMPORTANT: This path must include the trailing slash
|
||||
|
@ -219,20 +363,27 @@ class getID3
|
|||
echo $this->startup_error;
|
||||
throw new getid3_exception($this->startup_error);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function version() {
|
||||
return self::VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function fread_buffer_size() {
|
||||
return $this->option_fread_buffer_size;
|
||||
}
|
||||
|
||||
|
||||
// public: setOption
|
||||
/**
|
||||
* @param array $optArray
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function setOption($optArray) {
|
||||
if (!is_array($optArray) || empty($optArray)) {
|
||||
return false;
|
||||
|
@ -246,8 +397,15 @@ class getID3
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function openfile($filename, $filesize=null) {
|
||||
/**
|
||||
* @param string $filename
|
||||
* @param int $filesize
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws getid3_exception
|
||||
*/
|
||||
public function openfile($filename, $filesize=null, $fp=null) {
|
||||
try {
|
||||
if (!empty($this->startup_error)) {
|
||||
throw new getid3_exception($this->startup_error);
|
||||
|
@ -270,11 +428,13 @@ class getID3
|
|||
}
|
||||
|
||||
$filename = str_replace('/', DIRECTORY_SEPARATOR, $filename);
|
||||
$filename = preg_replace('#(?<!gs:)('.preg_quote(DIRECTORY_SEPARATOR).'{2,})#', DIRECTORY_SEPARATOR, $filename);
|
||||
//$filename = preg_replace('#(?<!gs:)('.preg_quote(DIRECTORY_SEPARATOR).'{2,})#', DIRECTORY_SEPARATOR, $filename);
|
||||
|
||||
// open local file
|
||||
//if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see http://www.getid3.org/phpBB3/viewtopic.php?t=1720
|
||||
if ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
|
||||
//if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see https://www.getid3.org/phpBB3/viewtopic.php?t=1720
|
||||
if (($fp != null) && ((get_resource_type($fp) == 'file') || (get_resource_type($fp) == 'stream'))) {
|
||||
$this->fp = $fp;
|
||||
} elseif ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
|
||||
// great
|
||||
} else {
|
||||
$errormessagelist = array();
|
||||
|
@ -331,10 +491,10 @@ class getID3
|
|||
} elseif (getid3_lib::intValueSupported($real_filesize)) {
|
||||
unset($this->info['filesize']);
|
||||
fclose($this->fp);
|
||||
throw new getid3_exception('PHP seems to think the file is larger than '.round(PHP_INT_MAX / 1073741824).'GB, but filesystem reports it as '.number_format($real_filesize, 3).'GB, please report to info@getid3.org');
|
||||
throw new getid3_exception('PHP seems to think the file is larger than '.round(PHP_INT_MAX / 1073741824).'GB, but filesystem reports it as '.number_format($real_filesize / 1073741824, 3).'GB, please report to info@getid3.org');
|
||||
}
|
||||
$this->info['filesize'] = $real_filesize;
|
||||
$this->warning('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB (filesystem reports it as '.number_format($real_filesize, 3).'GB) and is not properly supported by PHP.');
|
||||
$this->warning('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB (filesystem reports it as '.number_format($real_filesize / 1073741824, 3).'GB) and is not properly supported by PHP.');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -346,10 +506,18 @@ class getID3
|
|||
return false;
|
||||
}
|
||||
|
||||
// public: analyze file
|
||||
public function analyze($filename, $filesize=null, $original_filename='') {
|
||||
/**
|
||||
* analyze file
|
||||
*
|
||||
* @param string $filename
|
||||
* @param int $filesize
|
||||
* @param string $original_filename
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function analyze($filename, $filesize=null, $original_filename='', $fp=null) {
|
||||
try {
|
||||
if (!$this->openfile($filename, $filesize)) {
|
||||
if (!$this->openfile($filename, $filesize, $fp)) {
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
|
@ -383,8 +551,8 @@ class getID3
|
|||
$header = fread($this->fp, 10);
|
||||
if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) {
|
||||
$this->info['id3v2']['header'] = true;
|
||||
$this->info['id3v2']['majorversion'] = ord($header{3});
|
||||
$this->info['id3v2']['minorversion'] = ord($header{4});
|
||||
$this->info['id3v2']['majorversion'] = ord($header[3]);
|
||||
$this->info['id3v2']['minorversion'] = ord($header[4]);
|
||||
$this->info['avdataoffset'] += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
|
||||
}
|
||||
}
|
||||
|
@ -497,7 +665,13 @@ class getID3
|
|||
}
|
||||
|
||||
|
||||
// private: error handling
|
||||
/**
|
||||
* Error handling.
|
||||
*
|
||||
* @param string $message
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function error($message) {
|
||||
$this->CleanUp();
|
||||
if (!isset($this->info['error'])) {
|
||||
|
@ -508,14 +682,22 @@ class getID3
|
|||
}
|
||||
|
||||
|
||||
// private: warning handling
|
||||
/**
|
||||
* Warning handling.
|
||||
*
|
||||
* @param string $message
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function warning($message) {
|
||||
$this->info['warning'][] = $message;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// private: CleanUp
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function CleanUp() {
|
||||
|
||||
// remove possible empty keys
|
||||
|
@ -562,8 +744,11 @@ class getID3
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
// return array containing information about all supported formats
|
||||
/**
|
||||
* Return array containing information about all supported formats.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function GetFileFormatArray() {
|
||||
static $format_info = array();
|
||||
if (empty($format_info)) {
|
||||
|
@ -584,7 +769,7 @@ class getID3
|
|||
'pattern' => '^ADIF',
|
||||
'group' => 'audio',
|
||||
'module' => 'aac',
|
||||
'mime_type' => 'application/octet-stream',
|
||||
'mime_type' => 'audio/aac',
|
||||
'fail_ape' => 'WARNING',
|
||||
),
|
||||
|
||||
|
@ -602,7 +787,7 @@ class getID3
|
|||
'pattern' => '^\\xFF[\\xF0-\\xF1\\xF8-\\xF9]',
|
||||
'group' => 'audio',
|
||||
'module' => 'aac',
|
||||
'mime_type' => 'application/octet-stream',
|
||||
'mime_type' => 'audio/aac',
|
||||
'fail_ape' => 'WARNING',
|
||||
),
|
||||
|
||||
|
@ -649,7 +834,7 @@ class getID3
|
|||
|
||||
// DSS - audio - Digital Speech Standard
|
||||
'dss' => array(
|
||||
'pattern' => '^[\\x02-\\x06]ds[s2]',
|
||||
'pattern' => '^[\\x02-\\x08]ds[s2]',
|
||||
'group' => 'audio',
|
||||
'module' => 'dss',
|
||||
'mime_type' => 'application/octet-stream',
|
||||
|
@ -668,7 +853,7 @@ class getID3
|
|||
'pattern' => '^fLaC',
|
||||
'group' => 'audio',
|
||||
'module' => 'flac',
|
||||
'mime_type' => 'audio/x-flac',
|
||||
'mime_type' => 'audio/flac',
|
||||
),
|
||||
|
||||
// LA - audio - Lossless Audio (LA)
|
||||
|
@ -700,7 +885,7 @@ class getID3
|
|||
'pattern' => '^MAC ',
|
||||
'group' => 'audio',
|
||||
'module' => 'monkey',
|
||||
'mime_type' => 'application/octet-stream',
|
||||
'mime_type' => 'audio/x-monkeys-audio',
|
||||
),
|
||||
|
||||
// has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available
|
||||
|
@ -889,7 +1074,7 @@ class getID3
|
|||
'pattern' => '^(RIFF|SDSS|FORM)',
|
||||
'group' => 'audio-video',
|
||||
'module' => 'riff',
|
||||
'mime_type' => 'audio/x-wav',
|
||||
'mime_type' => 'audio/wav',
|
||||
'fail_ape' => 'WARNING',
|
||||
),
|
||||
|
||||
|
@ -1053,7 +1238,7 @@ class getID3
|
|||
'pattern' => '^\\x1F\\x8B\\x08',
|
||||
'group' => 'archive',
|
||||
'module' => 'gzip',
|
||||
'mime_type' => 'application/x-gzip',
|
||||
'mime_type' => 'application/gzip',
|
||||
'fail_id3' => 'ERROR',
|
||||
'fail_ape' => 'ERROR',
|
||||
),
|
||||
|
@ -1068,6 +1253,16 @@ class getID3
|
|||
'fail_ape' => 'ERROR',
|
||||
),
|
||||
|
||||
// XZ - data - XZ compressed data
|
||||
'xz' => array(
|
||||
'pattern' => '^\\xFD7zXZ\\x00',
|
||||
'group' => 'archive',
|
||||
'module' => 'xz',
|
||||
'mime_type' => 'application/x-xz',
|
||||
'fail_id3' => 'ERROR',
|
||||
'fail_ape' => 'ERROR',
|
||||
),
|
||||
|
||||
|
||||
// Misc other formats
|
||||
|
||||
|
@ -1115,8 +1310,12 @@ class getID3
|
|||
return $format_info;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string $filedata
|
||||
* @param string $filename
|
||||
*
|
||||
* @return mixed|false
|
||||
*/
|
||||
public function GetFileFormat(&$filedata, $filename='') {
|
||||
// this function will determine the format of a file based on usually
|
||||
// the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG,
|
||||
|
@ -1135,7 +1334,7 @@ class getID3
|
|||
|
||||
|
||||
if (preg_match('#\\.mp[123a]$#i', $filename)) {
|
||||
// Too many mp3 encoders on the market put gabage in front of mpeg files
|
||||
// Too many mp3 encoders on the market put garbage in front of mpeg files
|
||||
// use assume format on these if format detection failed
|
||||
$GetFileFormatArray = $this->GetFileFormatArray();
|
||||
$info = $GetFileFormatArray['mp3'];
|
||||
|
@ -1154,8 +1353,12 @@ class getID3
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
// converts array to $encoding charset from $this->encoding
|
||||
/**
|
||||
* Converts array to $encoding charset from $this->encoding.
|
||||
*
|
||||
* @param array $array
|
||||
* @param string $encoding
|
||||
*/
|
||||
public function CharConvert(&$array, $encoding) {
|
||||
|
||||
// identical encoding - end here
|
||||
|
@ -1178,7 +1381,9 @@ class getID3
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function HandleAllTags() {
|
||||
|
||||
// key name => array (tag name, character encoding)
|
||||
|
@ -1233,6 +1438,7 @@ class getID3
|
|||
}
|
||||
}
|
||||
if ($tag_key == 'picture') {
|
||||
// pictures can take up a lot of space, and we don't need multiple copies of them; let there be a single copy in [comments][picture], and not elsewhere
|
||||
unset($this->info[$comment_name]['comments'][$tag_key]);
|
||||
}
|
||||
}
|
||||
|
@ -1246,6 +1452,11 @@ class getID3
|
|||
|
||||
if ($this->option_tags_html) {
|
||||
foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
|
||||
if ($tag_key == 'picture') {
|
||||
// Do not to try to convert binary picture data to HTML
|
||||
// https://github.com/JamesHeinrich/getID3/issues/178
|
||||
continue;
|
||||
}
|
||||
$this->info['tags_html'][$tag_name][$tag_key] = getid3_lib::recursiveMultiByteCharString2HTML($valuearray, $this->info[$comment_name]['encoding']);
|
||||
}
|
||||
}
|
||||
|
@ -1254,8 +1465,7 @@ class getID3
|
|||
|
||||
}
|
||||
|
||||
// pictures can take up a lot of space, and we don't need multiple copies of them
|
||||
// let there be a single copy in [comments][picture], and not elsewhere
|
||||
// pictures can take up a lot of space, and we don't need multiple copies of them; let there be a single copy in [comments][picture], and not elsewhere
|
||||
if (!empty($this->info['tags'])) {
|
||||
$unset_keys = array('tags', 'tags_html');
|
||||
foreach ($this->info['tags'] as $tagtype => $tagarray) {
|
||||
|
@ -1301,6 +1511,11 @@ class getID3
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $algorithm
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function getHashdata($algorithm) {
|
||||
switch ($algorithm) {
|
||||
case 'md5':
|
||||
|
@ -1365,7 +1580,6 @@ class getID3
|
|||
|
||||
} else {
|
||||
|
||||
$commandline = 'vorbiscomment -w -c "'.$empty.'" "'.$file.'" "'.$temp.'" 2>&1';
|
||||
$commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1';
|
||||
$VorbisCommentError = `$commandline`;
|
||||
|
||||
|
@ -1424,7 +1638,6 @@ class getID3
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function ChannelsBitratePlaytimeCalculations() {
|
||||
|
||||
// set channelmode on audio
|
||||
|
@ -1489,7 +1702,9 @@ class getID3
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function CalculateCompressionRatioVideo() {
|
||||
if (empty($this->info['video'])) {
|
||||
return false;
|
||||
|
@ -1537,7 +1752,9 @@ class getID3
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function CalculateCompressionRatioAudio() {
|
||||
if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate']) || !is_numeric($this->info['audio']['sample_rate'])) {
|
||||
return false;
|
||||
|
@ -1554,11 +1771,13 @@ class getID3
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function CalculateReplayGain() {
|
||||
if (isset($this->info['replay_gain'])) {
|
||||
if (!isset($this->info['replay_gain']['reference_volume'])) {
|
||||
$this->info['replay_gain']['reference_volume'] = (double) 89.0;
|
||||
$this->info['replay_gain']['reference_volume'] = 89.0;
|
||||
}
|
||||
if (isset($this->info['replay_gain']['track']['adjustment'])) {
|
||||
$this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment'];
|
||||
|
@ -1577,6 +1796,9 @@ class getID3
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function ProcessAudioStreams() {
|
||||
if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) {
|
||||
if (!isset($this->info['audio']['streams'])) {
|
||||
|
@ -1590,10 +1812,20 @@ class getID3
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|bool
|
||||
*/
|
||||
public function getid3_tempnam() {
|
||||
return tempnam($this->tempdir, 'gI3');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws getid3_exception
|
||||
*/
|
||||
public function include_module($name) {
|
||||
//if (!file_exists($this->include_path.'module.'.$name.'.php')) {
|
||||
if (!file_exists(GETID3_INCLUDEPATH.'module.'.$name.'.php')) {
|
||||
|
@ -1603,35 +1835,70 @@ class getID3
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_writable ($filename) {
|
||||
$ret = is_writable($filename);
|
||||
|
||||
if (!$ret) {
|
||||
$perms = fileperms($filename);
|
||||
$ret = ($perms & 0x0080) || ($perms & 0x0010) || ($perms & 0x0002);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
abstract class getid3_handler {
|
||||
abstract class getid3_handler
|
||||
{
|
||||
|
||||
/**
|
||||
* @var getID3
|
||||
*/
|
||||
protected $getid3; // pointer
|
||||
|
||||
protected $data_string_flag = false; // analyzing filepointer or string
|
||||
protected $data_string = ''; // string to analyze
|
||||
protected $data_string_position = 0; // seek position in string
|
||||
protected $data_string_length = 0; // string length
|
||||
/**
|
||||
* Analyzing filepointer or string.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $data_string_flag = false;
|
||||
|
||||
private $dependency_to = null;
|
||||
/**
|
||||
* String to analyze.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $data_string = '';
|
||||
|
||||
/**
|
||||
* Seek position in string.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $data_string_position = 0;
|
||||
|
||||
/**
|
||||
* String length.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $data_string_length = 0;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $dependency_to;
|
||||
|
||||
/**
|
||||
* getid3_handler constructor.
|
||||
*
|
||||
* @param getID3 $getid3
|
||||
* @param string $call_module
|
||||
*/
|
||||
public function __construct(getID3 $getid3, $call_module=null) {
|
||||
$this->getid3 = $getid3;
|
||||
|
||||
|
@ -1640,12 +1907,18 @@ abstract class getid3_handler {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Analyze from file pointer
|
||||
/**
|
||||
* Analyze from file pointer.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function Analyze();
|
||||
|
||||
|
||||
// Analyze from string instead
|
||||
/**
|
||||
* Analyze from string instead.
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function AnalyzeString($string) {
|
||||
// Enter string mode
|
||||
$this->setStringMode($string);
|
||||
|
@ -1671,12 +1944,18 @@ abstract class getid3_handler {
|
|||
$this->data_string_flag = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*/
|
||||
public function setStringMode($string) {
|
||||
$this->data_string_flag = true;
|
||||
$this->data_string = $string;
|
||||
$this->data_string_length = strlen($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|bool
|
||||
*/
|
||||
protected function ftell() {
|
||||
if ($this->data_string_flag) {
|
||||
return $this->data_string_position;
|
||||
|
@ -1684,6 +1963,13 @@ abstract class getid3_handler {
|
|||
return ftell($this->getid3->fp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $bytes
|
||||
*
|
||||
* @return string|false
|
||||
*
|
||||
* @throws getid3_exception
|
||||
*/
|
||||
protected function fread($bytes) {
|
||||
if ($this->data_string_flag) {
|
||||
$this->data_string_position += $bytes;
|
||||
|
@ -1696,7 +1982,7 @@ abstract class getid3_handler {
|
|||
|
||||
//return fread($this->getid3->fp, $bytes);
|
||||
/*
|
||||
* http://www.getid3.org/phpBB3/viewtopic.php?t=1930
|
||||
* https://www.getid3.org/phpBB3/viewtopic.php?t=1930
|
||||
* "I found out that the root cause for the problem was how getID3 uses the PHP system function fread().
|
||||
* It seems to assume that fread() would always return as many bytes as were requested.
|
||||
* However, according the PHP manual (http://php.net/manual/en/function.fread.php), this is the case only with regular local files, but not e.g. with Linux pipes.
|
||||
|
@ -1704,6 +1990,10 @@ abstract class getid3_handler {
|
|||
*/
|
||||
$contents = '';
|
||||
do {
|
||||
//if (($this->getid3->memory_limit > 0) && ($bytes > $this->getid3->memory_limit)) {
|
||||
if (($this->getid3->memory_limit > 0) && (($bytes / $this->getid3->memory_limit) > 0.99)) { // enable a more-fuzzy match to prevent close misses generating errors like "PHP Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 33554464 bytes)"
|
||||
throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') that is more than available PHP memory ('.$this->getid3->memory_limit.')', 10);
|
||||
}
|
||||
$part = fread($this->getid3->fp, $bytes);
|
||||
$partLength = strlen($part);
|
||||
$bytes -= $partLength;
|
||||
|
@ -1712,6 +2002,14 @@ abstract class getid3_handler {
|
|||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $bytes
|
||||
* @param int $whence
|
||||
*
|
||||
* @return int
|
||||
*
|
||||
* @throws getid3_exception
|
||||
*/
|
||||
protected function fseek($bytes, $whence=SEEK_SET) {
|
||||
if ($this->data_string_flag) {
|
||||
switch ($whence) {
|
||||
|
@ -1742,6 +2040,9 @@ abstract class getid3_handler {
|
|||
return fseek($this->getid3->fp, $bytes, $whence);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function feof() {
|
||||
if ($this->data_string_flag) {
|
||||
return $this->data_string_position >= $this->data_string_length;
|
||||
|
@ -1749,24 +2050,53 @@ abstract class getid3_handler {
|
|||
return feof($this->getid3->fp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $module
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
final protected function isDependencyFor($module) {
|
||||
return $this->dependency_to == $module;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function error($text) {
|
||||
$this->getid3->info['error'][] = $text;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function warning($text) {
|
||||
return $this->getid3->warning($text);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
*/
|
||||
protected function notice($text) {
|
||||
// does nothing for now
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param int $offset
|
||||
* @param int $length
|
||||
* @param string $image_mime
|
||||
*
|
||||
* @return string|null
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws getid3_exception
|
||||
*/
|
||||
public function saveAttachment($name, $offset, $length, $image_mime=null) {
|
||||
try {
|
||||
|
||||
|
@ -1820,6 +2150,9 @@ abstract class getid3_handler {
|
|||
// close and remove dest file if created
|
||||
if (isset($fp_dest) && is_resource($fp_dest)) {
|
||||
fclose($fp_dest);
|
||||
}
|
||||
|
||||
if (isset($dest) && file_exists($dest)) {
|
||||
unlink($dest);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// or https://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -18,9 +18,9 @@ GNU GPL: https://gnu.org/licenses/gpl.html (v3)
|
|||
|
||||
GNU LGPL: https://gnu.org/licenses/lgpl.html (v3)
|
||||
|
||||
Mozilla MPL: http://www.mozilla.org/MPL/2.0/ (v2)
|
||||
Mozilla MPL: https://www.mozilla.org/MPL/2.0/ (v2)
|
||||
|
||||
getID3 Commercial License: http://getid3.org/#gCL (payment required)
|
||||
getID3 Commercial License: https://www.getid3.org/#gCL (payment required)
|
||||
|
||||
*****************************************************************
|
||||
*****************************************************************
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio-video.asf.php //
|
||||
|
@ -16,8 +15,11 @@
|
|||
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
|
||||
|
||||
class getid3_asf extends getid3_handler {
|
||||
|
||||
class getid3_asf extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* @param getID3 $getid3
|
||||
*/
|
||||
public function __construct(getID3 $getid3) {
|
||||
parent::__construct($getid3); // extends getid3_handler::__construct()
|
||||
|
||||
|
@ -30,6 +32,9 @@ class getid3_asf extends getid3_handler {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -83,6 +88,8 @@ class getid3_asf extends getid3_handler {
|
|||
$NextObjectOffset = $this->ftell();
|
||||
$ASFHeaderData = $this->fread($thisfile_asf_headerobject['objectsize'] - 30);
|
||||
$offset = 0;
|
||||
$thisfile_asf_streambitratepropertiesobject = array();
|
||||
$thisfile_asf_codeclistobject = array();
|
||||
|
||||
for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) {
|
||||
$NextObjectGUID = substr($ASFHeaderData, $offset, 16);
|
||||
|
@ -790,17 +797,17 @@ class getid3_asf extends getid3_handler {
|
|||
case 'wm/tracknumber':
|
||||
case 'tracknumber':
|
||||
// be careful casting to int: casting unicode strings to int gives unexpected results (stops parsing at first non-numeric character)
|
||||
$thisfile_asf_comments['track'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
|
||||
foreach ($thisfile_asf_comments['track'] as $key => $value) {
|
||||
$thisfile_asf_comments['track_number'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
|
||||
foreach ($thisfile_asf_comments['track_number'] as $key => $value) {
|
||||
if (preg_match('/^[0-9\x00]+$/', $value)) {
|
||||
$thisfile_asf_comments['track'][$key] = intval(str_replace("\x00", '', $value));
|
||||
$thisfile_asf_comments['track_number'][$key] = intval(str_replace("\x00", '', $value));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'wm/track':
|
||||
if (empty($thisfile_asf_comments['track'])) {
|
||||
$thisfile_asf_comments['track'] = array(1 + $this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
|
||||
if (empty($thisfile_asf_comments['track_number'])) {
|
||||
$thisfile_asf_comments['track_number'] = array(1 + $this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -970,18 +977,18 @@ class getid3_asf extends getid3_handler {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (isset($thisfile_asf_streambitrateproperties['bitrate_records_count'])) {
|
||||
if (isset($thisfile_asf_streambitratepropertiesobject['bitrate_records_count'])) {
|
||||
$ASFbitrateAudio = 0;
|
||||
$ASFbitrateVideo = 0;
|
||||
for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitrateproperties['bitrate_records_count']; $BitrateRecordsCounter++) {
|
||||
for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) {
|
||||
if (isset($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter])) {
|
||||
switch ($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter]['type_raw']) {
|
||||
case 1:
|
||||
$ASFbitrateVideo += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate'];
|
||||
$ASFbitrateVideo += $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['bitrate'];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$ASFbitrateAudio += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate'];
|
||||
$ASFbitrateAudio += $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['bitrate'];
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1440,6 +1447,11 @@ class getid3_asf extends getid3_handler {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $CodecListType
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function codecListObjectTypeLookup($CodecListType) {
|
||||
static $lookup = array(
|
||||
0x0001 => 'Video Codec',
|
||||
|
@ -1450,6 +1462,9 @@ class getid3_asf extends getid3_handler {
|
|||
return (isset($lookup[$CodecListType]) ? $lookup[$CodecListType] : 'Invalid Codec Type');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function KnownGUIDs() {
|
||||
static $GUIDarray = array(
|
||||
'GETID3_ASF_Extended_Stream_Properties_Object' => '14E6A5CB-C672-4332-8399-A96952065B5A',
|
||||
|
@ -1564,6 +1579,11 @@ class getid3_asf extends getid3_handler {
|
|||
return $GUIDarray;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $GUIDstring
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function GUIDname($GUIDstring) {
|
||||
static $GUIDarray = array();
|
||||
if (empty($GUIDarray)) {
|
||||
|
@ -1572,6 +1592,11 @@ class getid3_asf extends getid3_handler {
|
|||
return array_search($GUIDstring, $GUIDarray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function ASFIndexObjectIndexTypeLookup($id) {
|
||||
static $ASFIndexObjectIndexTypeLookup = array();
|
||||
if (empty($ASFIndexObjectIndexTypeLookup)) {
|
||||
|
@ -1582,6 +1607,11 @@ class getid3_asf extends getid3_handler {
|
|||
return (isset($ASFIndexObjectIndexTypeLookup[$id]) ? $ASFIndexObjectIndexTypeLookup[$id] : 'invalid');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $GUIDstring
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function GUIDtoBytestring($GUIDstring) {
|
||||
// Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way:
|
||||
// first 4 bytes are in little-endian order
|
||||
|
@ -1617,31 +1647,42 @@ class getid3_asf extends getid3_handler {
|
|||
return $hexbytecharstring;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $Bytestring
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function BytestringToGUID($Bytestring) {
|
||||
$GUIDstring = str_pad(dechex(ord($Bytestring{3})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{2})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{1})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{0})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring = str_pad(dechex(ord($Bytestring[3])), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring[2])), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring[1])), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring[0])), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= '-';
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{5})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{4})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring[5])), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring[4])), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= '-';
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{7})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{6})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring[7])), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring[6])), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= '-';
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{8})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{9})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring[8])), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring[9])), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= '-';
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{10})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{11})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{12})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{13})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{14})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{15})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring[10])), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring[11])), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring[12])), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring[13])), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring[14])), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring[15])), 2, '0', STR_PAD_LEFT);
|
||||
|
||||
return strtoupper($GUIDstring);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $FILETIME
|
||||
* @param bool $round
|
||||
*
|
||||
* @return float|int
|
||||
*/
|
||||
public static function FILETIMEtoUNIXtime($FILETIME, $round=true) {
|
||||
// FILETIME is a 64-bit unsigned integer representing
|
||||
// the number of 100-nanosecond intervals since January 1, 1601
|
||||
|
@ -1653,6 +1694,11 @@ class getid3_asf extends getid3_handler {
|
|||
return ($FILETIME - 116444736000000000) / 10000000;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $WMpictureType
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function WMpictureTypeLookup($WMpictureType) {
|
||||
static $lookup = null;
|
||||
if ($lookup === null) {
|
||||
|
@ -1684,6 +1730,12 @@ class getid3_asf extends getid3_handler {
|
|||
return (isset($lookup[$WMpictureType]) ? $lookup[$WMpictureType] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $asf_header_extension_object_data
|
||||
* @param int $unhandled_sections
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) {
|
||||
// http://msdn.microsoft.com/en-us/library/bb643323.aspx
|
||||
|
||||
|
@ -1930,7 +1982,11 @@ class getid3_asf extends getid3_handler {
|
|||
return $HeaderExtensionObjectParsed;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function metadataLibraryObjectDataTypeLookup($id) {
|
||||
static $lookup = array(
|
||||
0x0000 => 'Unicode string', // The data consists of a sequence of Unicode characters
|
||||
|
@ -1944,6 +2000,11 @@ class getid3_asf extends getid3_handler {
|
|||
return (isset($lookup[$id]) ? $lookup[$id] : 'invalid');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function ASF_WMpicture(&$data) {
|
||||
//typedef struct _WMPicture{
|
||||
// LPWSTR pwszMIMEType;
|
||||
|
@ -1994,14 +2055,24 @@ class getid3_asf extends getid3_handler {
|
|||
return $WMpicture;
|
||||
}
|
||||
|
||||
|
||||
// Remove terminator 00 00 and convert UTF-16LE to Latin-1
|
||||
/**
|
||||
* Remove terminator 00 00 and convert UTF-16LE to Latin-1.
|
||||
*
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function TrimConvert($string) {
|
||||
return trim(getid3_lib::iconv_fallback('UTF-16LE', 'ISO-8859-1', self::TrimTerm($string)), ' ');
|
||||
}
|
||||
|
||||
|
||||
// Remove terminator 00 00
|
||||
/**
|
||||
* Remove terminator 00 00.
|
||||
*
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function TrimTerm($string) {
|
||||
// remove terminator, only if present (it should be, but...)
|
||||
if (substr($string, -2) === "\x00\x00") {
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio-video.flv.php //
|
||||
// module for analyzing Shockwave Flash Video files //
|
||||
// dependencies: NONE //
|
||||
// //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// FLV module by Seth Kaufman <sethØwhirl-i-gig*com> //
|
||||
// //
|
||||
// * version 0.1 (26 June 2005) //
|
||||
// //
|
||||
// //
|
||||
// * version 0.1.1 (15 July 2005) //
|
||||
// minor modifications by James Heinrich <info@getid3.org> //
|
||||
// //
|
||||
|
@ -43,12 +50,6 @@
|
|||
// handle GETID3_FLV_VIDEO_VP6FLV_ALPHA //
|
||||
// improved AVCSequenceParameterSetReader::readData() //
|
||||
// by Xander Schouwerwou <schouwerwouØgmail*com> //
|
||||
// //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio-video.flv.php //
|
||||
// module for analyzing Shockwave Flash Video files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -73,12 +74,21 @@ define('H264_PROFILE_HIGH422', 122);
|
|||
define('H264_PROFILE_HIGH444', 144);
|
||||
define('H264_PROFILE_HIGH444_PREDICTIVE', 244);
|
||||
|
||||
class getid3_flv extends getid3_handler {
|
||||
|
||||
class getid3_flv extends getid3_handler
|
||||
{
|
||||
const magic = 'FLV';
|
||||
|
||||
public $max_frames = 100000; // break out of the loop if too many frames have been scanned; only scan this many if meta frame does not contain useful duration
|
||||
/**
|
||||
* 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 $max_frames = 100000;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -332,7 +342,11 @@ class getid3_flv extends getid3_handler {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function audioFormatLookup($id) {
|
||||
static $lookup = array(
|
||||
0 => 'Linear PCM, platform endian',
|
||||
|
@ -355,6 +369,11 @@ class getid3_flv extends getid3_handler {
|
|||
return (isset($lookup[$id]) ? $lookup[$id] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public static function audioRateLookup($id) {
|
||||
static $lookup = array(
|
||||
0 => 5500,
|
||||
|
@ -365,6 +384,11 @@ class getid3_flv extends getid3_handler {
|
|||
return (isset($lookup[$id]) ? $lookup[$id] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public static function audioBitDepthLookup($id) {
|
||||
static $lookup = array(
|
||||
0 => 8,
|
||||
|
@ -373,6 +397,11 @@ class getid3_flv extends getid3_handler {
|
|||
return (isset($lookup[$id]) ? $lookup[$id] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function videoCodecLookup($id) {
|
||||
static $lookup = array(
|
||||
GETID3_FLV_VIDEO_H263 => 'Sorenson H.263',
|
||||
|
@ -386,47 +415,84 @@ class getid3_flv extends getid3_handler {
|
|||
}
|
||||
}
|
||||
|
||||
class AMFStream {
|
||||
class AMFStream
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $bytes;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $pos;
|
||||
|
||||
/**
|
||||
* @param string $bytes
|
||||
*/
|
||||
public function __construct(&$bytes) {
|
||||
$this->bytes =& $bytes;
|
||||
$this->pos = 0;
|
||||
}
|
||||
|
||||
public function readByte() {
|
||||
return getid3_lib::BigEndian2Int(substr($this->bytes, $this->pos++, 1));
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function readByte() { // 8-bit
|
||||
return ord(substr($this->bytes, $this->pos++, 1));
|
||||
}
|
||||
|
||||
public function readInt() {
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function readInt() { // 16-bit
|
||||
return ($this->readByte() << 8) + $this->readByte();
|
||||
}
|
||||
|
||||
public function readLong() {
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function readLong() { // 32-bit
|
||||
return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|false
|
||||
*/
|
||||
public function readDouble() {
|
||||
return getid3_lib::BigEndian2Float($this->read(8));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function readUTF() {
|
||||
$length = $this->readInt();
|
||||
return $this->read($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function readLongUTF() {
|
||||
$length = $this->readLong();
|
||||
return $this->read($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $length
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function read($length) {
|
||||
$val = substr($this->bytes, $this->pos, $length);
|
||||
$this->pos += $length;
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function peekByte() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readByte();
|
||||
|
@ -434,6 +500,9 @@ class AMFStream {
|
|||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function peekInt() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readInt();
|
||||
|
@ -441,6 +510,9 @@ class AMFStream {
|
|||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function peekLong() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readLong();
|
||||
|
@ -448,6 +520,9 @@ class AMFStream {
|
|||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|false
|
||||
*/
|
||||
public function peekDouble() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readDouble();
|
||||
|
@ -455,6 +530,9 @@ class AMFStream {
|
|||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function peekUTF() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readUTF();
|
||||
|
@ -462,6 +540,9 @@ class AMFStream {
|
|||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function peekLongUTF() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readLongUTF();
|
||||
|
@ -470,13 +551,23 @@ class AMFStream {
|
|||
}
|
||||
}
|
||||
|
||||
class AMFReader {
|
||||
class AMFReader
|
||||
{
|
||||
/**
|
||||
* @var AMFStream
|
||||
*/
|
||||
public $stream;
|
||||
|
||||
public function __construct(&$stream) {
|
||||
$this->stream =& $stream;
|
||||
/**
|
||||
* @param AMFStream $stream
|
||||
*/
|
||||
public function __construct(AMFStream $stream) {
|
||||
$this->stream = $stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function readData() {
|
||||
$value = null;
|
||||
|
||||
|
@ -547,23 +638,36 @@ class AMFReader {
|
|||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|false
|
||||
*/
|
||||
public function readDouble() {
|
||||
return $this->stream->readDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function readBoolean() {
|
||||
return $this->stream->readByte() == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function readString() {
|
||||
return $this->stream->readUTF();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function readObject() {
|
||||
// Get highest numerical index - ignored
|
||||
// $highestIndex = $this->stream->readLong();
|
||||
|
||||
$data = array();
|
||||
$key = null;
|
||||
|
||||
while ($key = $this->stream->readUTF()) {
|
||||
$data[$key] = $this->readData();
|
||||
|
@ -576,15 +680,19 @@ class AMFReader {
|
|||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function readMixedArray() {
|
||||
// Get highest numerical index - ignored
|
||||
$highestIndex = $this->stream->readLong();
|
||||
|
||||
$data = array();
|
||||
$key = null;
|
||||
|
||||
while ($key = $this->stream->readUTF()) {
|
||||
if (is_numeric($key)) {
|
||||
$key = (float) $key;
|
||||
$key = (int) $key;
|
||||
}
|
||||
$data[$key] = $this->readData();
|
||||
}
|
||||
|
@ -597,6 +705,9 @@ class AMFReader {
|
|||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function readArray() {
|
||||
$length = $this->stream->readLong();
|
||||
$data = array();
|
||||
|
@ -607,34 +718,61 @@ class AMFReader {
|
|||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|false
|
||||
*/
|
||||
public function readDate() {
|
||||
$timestamp = $this->stream->readDouble();
|
||||
$timezone = $this->stream->readInt();
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function readLongString() {
|
||||
return $this->stream->readLongUTF();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function readXML() {
|
||||
return $this->stream->readLongUTF();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function readTypedObject() {
|
||||
$className = $this->stream->readUTF();
|
||||
return $this->readObject();
|
||||
}
|
||||
}
|
||||
|
||||
class AVCSequenceParameterSetReader {
|
||||
class AVCSequenceParameterSetReader
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sps;
|
||||
public $start = 0;
|
||||
public $currentBytes = 0;
|
||||
public $currentBits = 0;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $width;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $height;
|
||||
|
||||
/**
|
||||
* @param string $sps
|
||||
*/
|
||||
public function __construct($sps) {
|
||||
$this->sps = $sps;
|
||||
}
|
||||
|
@ -691,18 +829,29 @@ class AVCSequenceParameterSetReader {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $bits
|
||||
*/
|
||||
public function skipBits($bits) {
|
||||
$newBits = $this->currentBits + $bits;
|
||||
$this->currentBytes += (int)floor($newBits / 8);
|
||||
$this->currentBits = $newBits % 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getBit() {
|
||||
$result = (getid3_lib::BigEndian2Int(substr($this->sps, $this->currentBytes, 1)) >> (7 - $this->currentBits)) & 0x01;
|
||||
$this->skipBits(1);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $bits
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getBits($bits) {
|
||||
$result = 0;
|
||||
for ($i = 0; $i < $bits; $i++) {
|
||||
|
@ -711,6 +860,9 @@ class AVCSequenceParameterSetReader {
|
|||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function expGolombUe() {
|
||||
$significantBits = 0;
|
||||
$bit = $this->getBit();
|
||||
|
@ -726,6 +878,9 @@ class AVCSequenceParameterSetReader {
|
|||
return (1 << $significantBits) + $this->getBits($significantBits) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function expGolombSe() {
|
||||
$result = $this->expGolombUe();
|
||||
if (($result & 0x01) == 0) {
|
||||
|
@ -735,10 +890,16 @@ class AVCSequenceParameterSetReader {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getWidth() {
|
||||
return $this->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getHeight() {
|
||||
return $this->height;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio-video.matriska.php //
|
||||
|
@ -72,7 +72,7 @@ define('EBML_ID_FILEREFERRAL', 0x0675); // [46][75] --
|
|||
define('EBML_ID_FILEDESCRIPTION', 0x067E); // [46][7E] -- A human-friendly name for the attached file.
|
||||
define('EBML_ID_FILEUID', 0x06AE); // [46][AE] -- Unique ID representing the file, as random as possible.
|
||||
define('EBML_ID_CONTENTENCALGO', 0x07E1); // [47][E1] -- The encryption algorithm used. The value '0' means that the contents have not been encrypted but only signed. Predefined values:
|
||||
define('EBML_ID_CONTENTENCKEYID', 0x07E2); // [47][E2] -- For public key algorithms this is the ID of the public key the the data was encrypted with.
|
||||
define('EBML_ID_CONTENTENCKEYID', 0x07E2); // [47][E2] -- For public key algorithms this is the ID of the public key the data was encrypted with.
|
||||
define('EBML_ID_CONTENTSIGNATURE', 0x07E3); // [47][E3] -- A cryptographic signature of the contents.
|
||||
define('EBML_ID_CONTENTSIGKEYID', 0x07E4); // [47][E4] -- This is the ID of the private key the data was signed with.
|
||||
define('EBML_ID_CONTENTSIGALGO', 0x07E5); // [47][E5] -- The algorithm used for the signature. A value of '0' means that the contents have not been signed but only encrypted. Predefined values:
|
||||
|
@ -215,17 +215,33 @@ define('EBML_ID_CLUSTERREFERENCEVIRTUAL', 0x7D); // [FD] --
|
|||
*/
|
||||
class getid3_matroska extends getid3_handler
|
||||
{
|
||||
// public options
|
||||
public static $hide_clusters = true; // if true, do not return information about CLUSTER chunks, since there's a lot of them and they're not usually useful [default: TRUE]
|
||||
public static $parse_whole_file = false; // true to parse the whole file, not only header [default: FALSE]
|
||||
/**
|
||||
* If true, do not return information about CLUSTER chunks, since there's a lot of them
|
||||
* and they're not usually useful [default: TRUE].
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $hide_clusters = true;
|
||||
|
||||
// private parser settings/placeholders
|
||||
/**
|
||||
* True to parse the whole file, not only header [default: FALSE].
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $parse_whole_file = false;
|
||||
|
||||
/*
|
||||
* Private parser settings/placeholders.
|
||||
*/
|
||||
private $EBMLbuffer = '';
|
||||
private $EBMLbuffer_offset = 0;
|
||||
private $EBMLbuffer_length = 0;
|
||||
private $current_offset = 0;
|
||||
private $unuseful_elements = array(EBML_ID_CRC32, EBML_ID_VOID);
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze()
|
||||
{
|
||||
$info = &$this->getid3->info;
|
||||
|
@ -366,8 +382,8 @@ class getid3_matroska extends getid3_handler
|
|||
if (!empty($getid3_temp->info[$header_data_key])) {
|
||||
$info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info[$header_data_key];
|
||||
if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
|
||||
foreach ($getid3_temp->info['audio'] as $key => $value) {
|
||||
$track_info[$key] = $value;
|
||||
foreach ($getid3_temp->info['audio'] as $sub_key => $value) {
|
||||
$track_info[$sub_key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -421,8 +437,8 @@ class getid3_matroska extends getid3_handler
|
|||
if (!empty($getid3_temp->info['ogg'])) {
|
||||
$info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['ogg'];
|
||||
if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
|
||||
foreach ($getid3_temp->info['audio'] as $key => $value) {
|
||||
$track_info[$key] = $value;
|
||||
foreach ($getid3_temp->info['audio'] as $sub_key => $value) {
|
||||
$track_info[$sub_key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -449,9 +465,9 @@ class getid3_matroska extends getid3_handler
|
|||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
|
||||
|
||||
$parsed = getid3_riff::parseWAVEFORMATex($trackarray['CodecPrivate']);
|
||||
foreach ($parsed as $key => $value) {
|
||||
if ($key != 'raw') {
|
||||
$track_info[$key] = $value;
|
||||
foreach ($parsed as $sub_key => $value) {
|
||||
if ($sub_key != 'raw') {
|
||||
$track_info[$sub_key] = $value;
|
||||
}
|
||||
}
|
||||
$info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
|
||||
|
@ -496,6 +512,9 @@ class getid3_matroska extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $info
|
||||
*/
|
||||
private function parseEBML(&$info) {
|
||||
// http://www.matroska.org/technical/specs/index.html#EBMLBasics
|
||||
$this->current_offset = $info['avdataoffset'];
|
||||
|
@ -1228,6 +1247,11 @@ class getid3_matroska extends getid3_handler
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $min_data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function EnsureBufferHasEnoughData($min_data=1024) {
|
||||
if (($this->current_offset - $this->EBMLbuffer_offset) >= ($this->EBMLbuffer_length - $min_data)) {
|
||||
$read_bytes = max($min_data, $this->getid3->fread_buffer_size());
|
||||
|
@ -1249,6 +1273,9 @@ class getid3_matroska extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|float|false
|
||||
*/
|
||||
private function readEBMLint() {
|
||||
$actual_offset = $this->current_offset - $this->EBMLbuffer_offset;
|
||||
|
||||
|
@ -1281,6 +1308,12 @@ class getid3_matroska extends getid3_handler
|
|||
return $int_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $length
|
||||
* @param bool $check_buffer
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
private function readEBMLelementData($length, $check_buffer=false) {
|
||||
if ($check_buffer && !$this->EnsureBufferHasEnoughData($length)) {
|
||||
return false;
|
||||
|
@ -1290,6 +1323,13 @@ class getid3_matroska extends getid3_handler
|
|||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $element
|
||||
* @param int $parent_end
|
||||
* @param array|bool $get_data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function getEBMLelement(&$element, $parent_end, $get_data=false) {
|
||||
if ($this->current_offset >= $parent_end) {
|
||||
return false;
|
||||
|
@ -1326,6 +1366,11 @@ class getid3_matroska extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param int $line
|
||||
* @param array $element
|
||||
*/
|
||||
private function unhandledElement($type, $line, $element) {
|
||||
// warn only about unknown and missed elements, not about unuseful
|
||||
if (!in_array($element['id'], $this->unuseful_elements)) {
|
||||
|
@ -1338,6 +1383,11 @@ class getid3_matroska extends getid3_handler
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $SimpleTagArray
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function ExtractCommentsSimpleTag($SimpleTagArray) {
|
||||
if (!empty($SimpleTagArray['SimpleTag'])) {
|
||||
foreach ($SimpleTagArray['SimpleTag'] as $SimpleTagKey => $SimpleTagData) {
|
||||
|
@ -1353,6 +1403,11 @@ class getid3_matroska extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $parent_end
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function HandleEMBLSimpleTag($parent_end) {
|
||||
$simpletag_entry = array();
|
||||
|
||||
|
@ -1383,6 +1438,13 @@ class getid3_matroska extends getid3_handler
|
|||
return $simpletag_entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $element
|
||||
* @param int $block_type
|
||||
* @param array $info
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function HandleEMBLClusterBlock($element, $block_type, &$info) {
|
||||
// http://www.matroska.org/technical/specs/index.html#block_structure
|
||||
// http://www.matroska.org/technical/specs/index.html#simpleblock_structure
|
||||
|
@ -1446,6 +1508,11 @@ class getid3_matroska extends getid3_handler
|
|||
return $block_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $EBMLstring
|
||||
*
|
||||
* @return int|float|false
|
||||
*/
|
||||
private static function EBML2Int($EBMLstring) {
|
||||
// http://matroska.org/specs/
|
||||
|
||||
|
@ -1488,12 +1555,22 @@ class getid3_matroska extends getid3_handler
|
|||
return getid3_lib::BigEndian2Int($EBMLstring);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $EBMLdatestamp
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private static function EBMLdate2unix($EBMLdatestamp) {
|
||||
// Date - signed 8 octets integer in nanoseconds with 0 indicating the precise beginning of the millennium (at 2001-01-01T00:00:00,000000000 UTC)
|
||||
// 978307200 == mktime(0, 0, 0, 1, 1, 2001) == January 1, 2001 12:00:00am UTC
|
||||
return round(($EBMLdatestamp / 1000000000) + 978307200);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $target_type
|
||||
*
|
||||
* @return string|int
|
||||
*/
|
||||
public static function TargetTypeValue($target_type) {
|
||||
// http://www.matroska.org/technical/specs/tagging/index.html
|
||||
static $TargetTypeValue = array();
|
||||
|
@ -1509,6 +1586,11 @@ class getid3_matroska extends getid3_handler
|
|||
return (isset($TargetTypeValue[$target_type]) ? $TargetTypeValue[$target_type] : $target_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $lacingtype
|
||||
*
|
||||
* @return string|int
|
||||
*/
|
||||
public static function BlockLacingType($lacingtype) {
|
||||
// http://matroska.org/technical/specs/index.html#block_structure
|
||||
static $BlockLacingType = array();
|
||||
|
@ -1521,6 +1603,11 @@ class getid3_matroska extends getid3_handler
|
|||
return (isset($BlockLacingType[$lacingtype]) ? $BlockLacingType[$lacingtype] : $lacingtype);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $codecid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function CodecIDtoCommonName($codecid) {
|
||||
// http://www.matroska.org/technical/specs/codecid/index.html
|
||||
static $CodecIDlist = array();
|
||||
|
@ -1557,6 +1644,11 @@ class getid3_matroska extends getid3_handler
|
|||
return (isset($CodecIDlist[$codecid]) ? $CodecIDlist[$codecid] : $codecid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function EBMLidName($value) {
|
||||
static $EBMLidList = array();
|
||||
if (empty($EBMLidList)) {
|
||||
|
@ -1755,6 +1847,11 @@ class getid3_matroska extends getid3_handler
|
|||
return (isset($EBMLidList[$value]) ? $EBMLidList[$value] : dechex($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function displayUnit($value) {
|
||||
// http://www.matroska.org/technical/specs/index.html#DisplayUnit
|
||||
static $units = array(
|
||||
|
@ -1766,8 +1863,14 @@ class getid3_matroska extends getid3_handler
|
|||
return (isset($units[$value]) ? $units[$value] : 'unknown');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $streams
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function getDefaultStreamInfo($streams)
|
||||
{
|
||||
$stream = array();
|
||||
foreach (array_reverse($streams) as $stream) {
|
||||
if ($stream['default']) {
|
||||
break;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio-video.quicktime.php //
|
||||
|
@ -24,6 +24,9 @@ class getid3_quicktime extends getid3_handler
|
|||
public $ReturnAtomData = true;
|
||||
public $ParseAllPossibleAtoms = false;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -35,7 +38,7 @@ class getid3_quicktime extends getid3_handler
|
|||
|
||||
$offset = 0;
|
||||
$atomcounter = 0;
|
||||
$atom_data_read_buffer_size = max($this->getid3->option_fread_buffer_size * 1024, ($info['php_memory_limit'] ? round($info['php_memory_limit'] / 4) : 1024)); // set read buffer to 25% of PHP memory limit (if one is specified), otherwise use option_fread_buffer_size [default: 32MB]
|
||||
$atom_data_read_buffer_size = $info['php_memory_limit'] ? round($info['php_memory_limit'] / 4) : $this->getid3->option_fread_buffer_size * 1024; // set read buffer to 25% of PHP memory limit (if one is specified), otherwise use option_fread_buffer_size [default: 32MB]
|
||||
while ($offset < $info['avdataend']) {
|
||||
if (!getid3_lib::intValueSupported($offset)) {
|
||||
$this->error('Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions');
|
||||
|
@ -162,6 +165,9 @@ class getid3_quicktime extends getid3_handler
|
|||
if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) {
|
||||
$info['audio']['bitrate'] = $info['bitrate'];
|
||||
}
|
||||
if (!empty($info['bitrate']) && !empty($info['audio']['bitrate']) && empty($info['video']['bitrate']) && !empty($info['video']['frame_rate']) && !empty($info['video']['resolution_x']) && ($info['bitrate'] > $info['audio']['bitrate'])) {
|
||||
$info['video']['bitrate'] = $info['bitrate'] - $info['audio']['bitrate'];
|
||||
}
|
||||
if (!empty($info['playtime_seconds']) && !isset($info['video']['frame_rate']) && !empty($info['quicktime']['stts_framecount'])) {
|
||||
foreach ($info['quicktime']['stts_framecount'] as $key => $samples_count) {
|
||||
$samples_per_second = $samples_count / $info['playtime_seconds'];
|
||||
|
@ -193,22 +199,41 @@ class getid3_quicktime extends getid3_handler
|
|||
if (empty($info['video']['dataformat']) && !empty($info['quicktime']['video'])) {
|
||||
$info['video']['dataformat'] = 'quicktime';
|
||||
}
|
||||
if (isset($info['video']) && ($info['mime_type'] == 'audio/mp4') && empty($info['video']['resolution_x']) && empty($info['video']['resolution_y'])) {
|
||||
unset($info['video']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $atomname
|
||||
* @param int $atomsize
|
||||
* @param string $atom_data
|
||||
* @param int $baseoffset
|
||||
* @param array $atomHierarchy
|
||||
* @param bool $ParseAllPossibleAtoms
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
|
||||
// http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
|
||||
// https://code.google.com/p/mp4v2/wiki/iTunesMetadata
|
||||
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$atom_parent = end($atomHierarchy); // not array_pop($atomHierarchy); see http://www.getid3.org/phpBB3/viewtopic.php?t=1717
|
||||
$atom_parent = end($atomHierarchy); // not array_pop($atomHierarchy); see https://www.getid3.org/phpBB3/viewtopic.php?t=1717
|
||||
array_push($atomHierarchy, $atomname);
|
||||
$atom_structure['hierarchy'] = implode(' ', $atomHierarchy);
|
||||
$atom_structure['name'] = $atomname;
|
||||
$atom_structure['size'] = $atomsize;
|
||||
$atom_structure['offset'] = $baseoffset;
|
||||
if (substr($atomname, 0, 3) == "\x00\x00\x00") {
|
||||
// https://github.com/JamesHeinrich/getID3/issues/139
|
||||
$atomname = getid3_lib::BigEndian2Int($atomname);
|
||||
$atom_structure['name'] = $atomname;
|
||||
$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
|
||||
} else {
|
||||
switch ($atomname) {
|
||||
case 'moov': // MOVie container atom
|
||||
case 'trak': // TRAcK container atom
|
||||
|
@ -252,16 +277,6 @@ class getid3_quicktime extends getid3_handler
|
|||
}
|
||||
break;
|
||||
|
||||
case "\x00\x00\x00\x01":
|
||||
case "\x00\x00\x00\x02":
|
||||
case "\x00\x00\x00\x03":
|
||||
case "\x00\x00\x00\x04":
|
||||
case "\x00\x00\x00\x05":
|
||||
$atomname = getid3_lib::BigEndian2Int($atomname);
|
||||
$atom_structure['name'] = $atomname;
|
||||
$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
|
||||
break;
|
||||
|
||||
case 'stbl': // Sample TaBLe container atom
|
||||
$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
|
||||
$isVideo = false;
|
||||
|
@ -687,13 +702,6 @@ class getid3_quicktime extends getid3_handler
|
|||
break;
|
||||
|
||||
|
||||
case 'rmla': // Reference Movie Language Atom
|
||||
$atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
|
||||
$atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
|
||||
$atom_structure['track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
|
||||
break;
|
||||
|
||||
|
||||
case 'ptv ': // Print To Video - defines a movie's full screen mode
|
||||
// http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm
|
||||
$atom_structure['display_size_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
|
||||
|
@ -806,7 +814,11 @@ class getid3_quicktime extends getid3_handler
|
|||
case 'yuv2':
|
||||
$info['fileformat'] = 'mp4';
|
||||
$info['video']['fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
|
||||
// http://www.getid3.org/phpBB3/viewtopic.php?t=1550
|
||||
if ($this->QuicktimeVideoCodecLookup($info['video']['fourcc'])) {
|
||||
$info['video']['fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($info['video']['fourcc']);
|
||||
}
|
||||
|
||||
// https://www.getid3.org/phpBB3/viewtopic.php?t=1550
|
||||
//if ((!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['width'])) && (empty($info['video']['resolution_x']) || empty($info['video']['resolution_y']) || (number_format($info['video']['resolution_x'], 6) != number_format(round($info['video']['resolution_x']), 6)) || (number_format($info['video']['resolution_y'], 6) != number_format(round($info['video']['resolution_y']), 6)))) { // ugly check for floating point numbers
|
||||
if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['height'])) {
|
||||
// assume that values stored here are more important than values stored in [tkhd] atom
|
||||
|
@ -834,7 +846,14 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
switch ($atom_structure['sample_description_table'][$i]['data_format']) {
|
||||
case 'raw ': // PCM
|
||||
case 'alac': // Apple Lossless Audio Codec
|
||||
$info['audio']['lossless'] = true;
|
||||
case 'sowt': // signed/two's complement (Little Endian)
|
||||
case 'twos': // signed/two's complement (Big Endian)
|
||||
case 'in24': // 24-bit Integer
|
||||
case 'in32': // 32-bit Integer
|
||||
case 'fl32': // 32-bit Floating Point
|
||||
case 'fl64': // 64-bit Floating Point
|
||||
$info['audio']['lossless'] = $info['quicktime']['audio']['lossless'] = true;
|
||||
$info['audio']['bitrate'] = $info['quicktime']['audio']['bitrate'] = $info['audio']['channels'] * $info['audio']['bits_per_sample'] * $info['audio']['sample_rate'];
|
||||
break;
|
||||
default:
|
||||
$info['audio']['lossless'] = false;
|
||||
|
@ -933,7 +952,7 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
|
||||
$max_stts_entries_to_scan = ($info['php_memory_limit'] ? min(floor($this->getid3->memory_limit / 10000), $atom_structure['number_entries']) : $atom_structure['number_entries']);
|
||||
if ($max_stts_entries_to_scan < $atom_structure['number_entries']) {
|
||||
$this->warning('QuickTime atom "stts" has '.$atom_structure['number_entries'].' but only scanning the first '.$max_stts_entries_to_scan.' entries due to limited PHP memory available ('.floor($atom_structure['number_entries'] / 1048576).'MB).');
|
||||
$this->warning('QuickTime atom "stts" has '.$atom_structure['number_entries'].' but only scanning the first '.$max_stts_entries_to_scan.' entries due to limited PHP memory available ('.floor($this->getid3->memory_limit / 1048576).'MB).');
|
||||
}
|
||||
for ($i = 0; $i < $max_stts_entries_to_scan; $i++) {
|
||||
$atom_structure['time_to_sample_table'][$i]['sample_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
|
||||
|
@ -1291,6 +1310,32 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
$atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
|
||||
$atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
|
||||
|
||||
// https://www.getid3.org/phpBB3/viewtopic.php?t=1908
|
||||
// attempt to compute rotation from matrix values
|
||||
// 2017-Dec-28: uncertain if 90/270 are correctly oriented; values returned by FixedPoint16_16 should perhaps be -1 instead of 65535(?)
|
||||
$matrixRotation = 0;
|
||||
switch ($atom_structure['matrix_a'].':'.$atom_structure['matrix_b'].':'.$atom_structure['matrix_c'].':'.$atom_structure['matrix_d']) {
|
||||
case '1:0:0:1': $matrixRotation = 0; break;
|
||||
case '0:1:65535:0': $matrixRotation = 90; break;
|
||||
case '65535:0:0:65535': $matrixRotation = 180; break;
|
||||
case '0:65535:1:0': $matrixRotation = 270; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
// https://www.getid3.org/phpBB3/viewtopic.php?t=2468
|
||||
// The rotation matrix can appear in the Quicktime file multiple times, at least once for each track,
|
||||
// and it's possible that only the video track (or, in theory, one of the video tracks) is flagged as
|
||||
// rotated while the other tracks (e.g. audio) is tagged as rotation=0 (behavior noted on iPhone 8 Plus)
|
||||
// The correct solution would be to check if the TrackID associated with the rotation matrix is indeed
|
||||
// a video track (or the main video track) and only set the rotation then, but since information about
|
||||
// what track is what is not trivially there to be examined, the lazy solution is to set the rotation
|
||||
// if it is found to be nonzero, on the assumption that tracks that don't need it will have rotation set
|
||||
// to zero (and be effectively ignored) and the video track will have rotation set correctly, which will
|
||||
// either be zero and automatically correct, or nonzero and be set correctly.
|
||||
if (!isset($info['video']['rotate']) || (($info['video']['rotate'] == 0) && ($matrixRotation > 0))) {
|
||||
$info['quicktime']['video']['rotate'] = $info['video']['rotate'] = $matrixRotation;
|
||||
}
|
||||
|
||||
if ($atom_structure['flags']['enabled'] == 1) {
|
||||
if (!isset($info['video']['resolution_x']) || !isset($info['video']['resolution_y'])) {
|
||||
$info['video']['resolution_x'] = $atom_structure['width'];
|
||||
|
@ -1301,7 +1346,7 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
$info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x'];
|
||||
$info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y'];
|
||||
} else {
|
||||
// see: http://www.getid3.org/phpBB3/viewtopic.php?t=1295
|
||||
// see: https://www.getid3.org/phpBB3/viewtopic.php?t=1295
|
||||
//if (isset($info['video']['resolution_x'])) { unset($info['video']['resolution_x']); }
|
||||
//if (isset($info['video']['resolution_y'])) { unset($info['video']['resolution_y']); }
|
||||
//if (isset($info['quicktime']['video'])) { unset($info['quicktime']['video']); }
|
||||
|
@ -1370,6 +1415,17 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (substr($atom_data, $mdat_offset, 4) == 'GPRO') {
|
||||
$GOPRO_chunk_length = getid3_lib::LittleEndian2Int(substr($atom_data, $mdat_offset + 4, 4));
|
||||
$GOPRO_offset = 8;
|
||||
$atom_structure['GPRO']['raw'] = substr($atom_data, $mdat_offset + 8, $GOPRO_chunk_length - 8);
|
||||
$atom_structure['GPRO']['firmware'] = substr($atom_structure['GPRO']['raw'], 0, 15);
|
||||
$atom_structure['GPRO']['unknown1'] = substr($atom_structure['GPRO']['raw'], 15, 16);
|
||||
$atom_structure['GPRO']['unknown2'] = substr($atom_structure['GPRO']['raw'], 31, 32);
|
||||
$atom_structure['GPRO']['unknown3'] = substr($atom_structure['GPRO']['raw'], 63, 16);
|
||||
$atom_structure['GPRO']['camera'] = substr($atom_structure['GPRO']['raw'], 79, 32);
|
||||
$info['quicktime']['camera']['model'] = rtrim($atom_structure['GPRO']['camera'], "\x00");
|
||||
}
|
||||
|
||||
// check to see if it looks like chapter titles, in the form of unterminated strings with a leading 16-bit size field
|
||||
while (($mdat_offset < (strlen($atom_data) - 8))
|
||||
|
@ -1387,7 +1443,6 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) {
|
||||
|
||||
$info['avdataoffset'] = $atom_structure['offset'] + 8; // $info['quicktime'][$atomname]['offset'] + 8;
|
||||
|
@ -1486,7 +1541,7 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
case 'code':
|
||||
case 'FIEL': // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html
|
||||
case 'tapt': // TrackApertureModeDimensionsAID - http://developer.apple.com/documentation/QuickTime/Reference/QT7-1_Update_Reference/Constants/Constants.html
|
||||
// tapt seems to be used to compute the video size [http://www.getid3.org/phpBB3/viewtopic.php?t=838]
|
||||
// tapt seems to be used to compute the video size [https://www.getid3.org/phpBB3/viewtopic.php?t=838]
|
||||
// * http://lists.apple.com/archives/quicktime-api/2006/Aug/msg00014.html
|
||||
// * http://handbrake.fr/irclogs/handbrake-dev/handbrake-dev20080128_pg2.html
|
||||
case 'ctts':// STCompositionOffsetAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
|
||||
|
@ -1676,10 +1731,10 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
$atom_structure['gps_entries'][$key] = $GPS_this_GPRMC;
|
||||
|
||||
@$info['quicktime']['gps_track'][$GPS_this_GPRMC['timestamp']] = array(
|
||||
'latitude' => $GPS_this_GPRMC['latitude'],
|
||||
'longitude' => $GPS_this_GPRMC['longitude'],
|
||||
'speed_kmh' => $GPS_this_GPRMC['speed_kmh'],
|
||||
'heading' => $GPS_this_GPRMC['heading'],
|
||||
'latitude' => (float) $GPS_this_GPRMC['latitude'],
|
||||
'longitude' => (float) $GPS_this_GPRMC['longitude'],
|
||||
'speed_kmh' => (float) $GPS_this_GPRMC['speed_kmh'],
|
||||
'heading' => (float) $GPS_this_GPRMC['heading'],
|
||||
);
|
||||
|
||||
} else {
|
||||
|
@ -1697,30 +1752,114 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
break;
|
||||
|
||||
case 'loci':// 3GP location (El Loco)
|
||||
$info['quicktime']['comments']['gps_flags'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
|
||||
$info['quicktime']['comments']['gps_lang'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
|
||||
$loffset = 0;
|
||||
$info['quicktime']['comments']['gps_location'] = $this->LociString(substr($atom_data, 6), $loffset);
|
||||
$info['quicktime']['comments']['gps_flags'] = array( getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)));
|
||||
$info['quicktime']['comments']['gps_lang'] = array( getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)));
|
||||
$info['quicktime']['comments']['gps_location'] = array( $this->LociString(substr($atom_data, 6), $loffset));
|
||||
$loci_data = substr($atom_data, 6 + $loffset);
|
||||
$info['quicktime']['comments']['gps_role'] = getid3_lib::BigEndian2Int(substr($loci_data, 0, 1));
|
||||
$info['quicktime']['comments']['gps_longitude'] = getid3_lib::FixedPoint16_16(substr($loci_data, 1, 4));
|
||||
$info['quicktime']['comments']['gps_latitude'] = getid3_lib::FixedPoint16_16(substr($loci_data, 5, 4));
|
||||
$info['quicktime']['comments']['gps_altitude'] = getid3_lib::FixedPoint16_16(substr($loci_data, 9, 4));
|
||||
$info['quicktime']['comments']['gps_body'] = $this->LociString(substr($loci_data, 13), $loffset);
|
||||
$info['quicktime']['comments']['gps_notes'] = $this->LociString(substr($loci_data, 13 + $loffset), $loffset);
|
||||
$info['quicktime']['comments']['gps_role'] = array( getid3_lib::BigEndian2Int(substr($loci_data, 0, 1)));
|
||||
$info['quicktime']['comments']['gps_longitude'] = array(getid3_lib::FixedPoint16_16(substr($loci_data, 1, 4)));
|
||||
$info['quicktime']['comments']['gps_latitude'] = array(getid3_lib::FixedPoint16_16(substr($loci_data, 5, 4)));
|
||||
$info['quicktime']['comments']['gps_altitude'] = array(getid3_lib::FixedPoint16_16(substr($loci_data, 9, 4)));
|
||||
$info['quicktime']['comments']['gps_body'] = array( $this->LociString(substr($loci_data, 13 ), $loffset));
|
||||
$info['quicktime']['comments']['gps_notes'] = array( $this->LociString(substr($loci_data, 13 + $loffset), $loffset));
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->warning('Unknown QuickTime atom type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" ('.trim(getid3_lib::PrintHexBytes($atomname)).') at offset '.$baseoffset);
|
||||
case 'chpl': // CHaPter List
|
||||
// https://www.adobe.com/content/dam/Adobe/en/devnet/flv/pdfs/video_file_format_spec_v10.pdf
|
||||
$chpl_version = getid3_lib::BigEndian2Int(substr($atom_data, 4, 1)); // Expected to be 0
|
||||
$chpl_flags = getid3_lib::BigEndian2Int(substr($atom_data, 5, 3)); // Reserved, set to 0
|
||||
$chpl_count = getid3_lib::BigEndian2Int(substr($atom_data, 8, 1));
|
||||
$chpl_offset = 9;
|
||||
for ($i = 0; $i < $chpl_count; $i++) {
|
||||
if (($chpl_offset + 9) >= strlen($atom_data)) {
|
||||
$this->warning('QuickTime chapter '.$i.' extends beyond end of "chpl" atom');
|
||||
break;
|
||||
}
|
||||
$info['quicktime']['chapters'][$i]['timestamp'] = getid3_lib::BigEndian2Int(substr($atom_data, $chpl_offset, 8)) / 10000000; // timestamps are stored as 100-nanosecond units
|
||||
$chpl_offset += 8;
|
||||
$chpl_title_size = getid3_lib::BigEndian2Int(substr($atom_data, $chpl_offset, 1));
|
||||
$chpl_offset += 1;
|
||||
$info['quicktime']['chapters'][$i]['title'] = substr($atom_data, $chpl_offset, $chpl_title_size);
|
||||
$chpl_offset += $chpl_title_size;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'FIRM': // FIRMware version(?), seen on GoPro Hero4
|
||||
$info['quicktime']['camera']['firmware'] = $atom_data;
|
||||
break;
|
||||
|
||||
case 'CAME': // FIRMware version(?), seen on GoPro Hero4
|
||||
$info['quicktime']['camera']['serial_hash'] = unpack('H*', $atom_data);
|
||||
break;
|
||||
|
||||
case 'dscp':
|
||||
case 'rcif':
|
||||
// https://www.getid3.org/phpBB3/viewtopic.php?t=1908
|
||||
if (substr($atom_data, 0, 7) == "\x00\x00\x00\x00\x55\xC4".'{') {
|
||||
if ($json_decoded = @json_decode(rtrim(substr($atom_data, 6), "\x00"), true)) {
|
||||
$info['quicktime']['camera'][$atomname] = $json_decoded;
|
||||
if (($atomname == 'rcif') && isset($info['quicktime']['camera']['rcif']['wxcamera']['rotate'])) {
|
||||
$info['video']['rotate'] = $info['quicktime']['video']['rotate'] = $info['quicktime']['camera']['rcif']['wxcamera']['rotate'];
|
||||
}
|
||||
} else {
|
||||
$this->warning('Failed to JSON decode atom "'.$atomname.'"');
|
||||
$atom_structure['data'] = $atom_data;
|
||||
}
|
||||
unset($json_decoded);
|
||||
} else {
|
||||
$this->warning('Expecting 55 C4 7B at start of atom "'.$atomname.'", found '.getid3_lib::PrintHexBytes(substr($atom_data, 4, 3)).' instead');
|
||||
$atom_structure['data'] = $atom_data;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'frea':
|
||||
// https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea
|
||||
// may contain "scra" (PreviewImage) and/or "thma" (ThumbnailImage)
|
||||
$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
|
||||
break;
|
||||
case 'tima': // subatom to "frea"
|
||||
// no idea what this does, the one sample file I've seen has a value of 0x00000027
|
||||
$atom_structure['data'] = $atom_data;
|
||||
break;
|
||||
case 'ver ': // subatom to "frea"
|
||||
// some kind of version number, the one sample file I've seen has a value of "3.00.073"
|
||||
$atom_structure['data'] = $atom_data;
|
||||
break;
|
||||
case 'thma': // subatom to "frea" -- "ThumbnailImage"
|
||||
// https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea
|
||||
if (strlen($atom_data) > 0) {
|
||||
$info['quicktime']['comments']['picture'][] = array('data'=>$atom_data, 'image_mime'=>'image/jpeg');
|
||||
}
|
||||
break;
|
||||
case 'scra': // subatom to "frea" -- "PreviewImage"
|
||||
// https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea
|
||||
// but the only sample file I've seen has no useful data here
|
||||
if (strlen($atom_data) > 0) {
|
||||
$info['quicktime']['comments']['picture'][] = array('data'=>$atom_data, 'image_mime'=>'image/jpeg');
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
$this->warning('Unknown QuickTime atom type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" ('.trim(getid3_lib::PrintHexBytes($atomname)).'), '.$atomsize.' bytes at offset '.$baseoffset);
|
||||
$atom_structure['data'] = $atom_data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
array_pop($atomHierarchy);
|
||||
return $atom_structure;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $atom_data
|
||||
* @param int $baseoffset
|
||||
* @param array $atomHierarchy
|
||||
* @param bool $ParseAllPossibleAtoms
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
|
||||
//echo 'QuicktimeParseContainerAtom('.substr($atom_data, 4, 4).') @ '.$baseoffset.'<br><br>';
|
||||
$atom_structure = false;
|
||||
$subatomoffset = 0;
|
||||
$subatomcounter = 0;
|
||||
|
@ -1741,16 +1880,18 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
}
|
||||
return $atom_structure;
|
||||
}
|
||||
|
||||
$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;
|
||||
$subatomcounter++;
|
||||
}
|
||||
return $atom_structure;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @param int $offset
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function quicktime_read_mp4_descr_length($data, &$offset) {
|
||||
// http://libquicktime.sourcearchive.com/documentation/2:1.0.2plus-pdebian-2build1/esds_8c-source.html
|
||||
$num_bytes = 0;
|
||||
|
@ -1762,7 +1903,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
return $length;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $languageid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function QuicktimeLanguageLookup($languageid) {
|
||||
// http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-34353
|
||||
static $QuicktimeLanguageLookup = array();
|
||||
|
@ -1900,6 +2045,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
return (isset($QuicktimeLanguageLookup[$languageid]) ? $QuicktimeLanguageLookup[$languageid] : 'invalid');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $codecid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function QuicktimeVideoCodecLookup($codecid) {
|
||||
static $QuicktimeVideoCodecLookup = array();
|
||||
if (empty($QuicktimeVideoCodecLookup)) {
|
||||
|
@ -1959,6 +2109,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
return (isset($QuicktimeVideoCodecLookup[$codecid]) ? $QuicktimeVideoCodecLookup[$codecid] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $codecid
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function QuicktimeAudioCodecLookup($codecid) {
|
||||
static $QuicktimeAudioCodecLookup = array();
|
||||
if (empty($QuicktimeAudioCodecLookup)) {
|
||||
|
@ -2004,6 +2159,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
return (isset($QuicktimeAudioCodecLookup[$codecid]) ? $QuicktimeAudioCodecLookup[$codecid] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $compressionid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function QuicktimeDCOMLookup($compressionid) {
|
||||
static $QuicktimeDCOMLookup = array();
|
||||
if (empty($QuicktimeDCOMLookup)) {
|
||||
|
@ -2013,6 +2173,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
return (isset($QuicktimeDCOMLookup[$compressionid]) ? $QuicktimeDCOMLookup[$compressionid] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $colordepthid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function QuicktimeColorNameLookup($colordepthid) {
|
||||
static $QuicktimeColorNameLookup = array();
|
||||
if (empty($QuicktimeColorNameLookup)) {
|
||||
|
@ -2031,6 +2196,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
return (isset($QuicktimeColorNameLookup[$colordepthid]) ? $QuicktimeColorNameLookup[$colordepthid] : 'invalid');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $stik
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function QuicktimeSTIKLookup($stik) {
|
||||
static $QuicktimeSTIKLookup = array();
|
||||
if (empty($QuicktimeSTIKLookup)) {
|
||||
|
@ -2048,6 +2218,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
return (isset($QuicktimeSTIKLookup[$stik]) ? $QuicktimeSTIKLookup[$stik] : 'invalid');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $audio_profile_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function QuicktimeIODSaudioProfileName($audio_profile_id) {
|
||||
static $QuicktimeIODSaudioProfileNameLookup = array();
|
||||
if (empty($QuicktimeIODSaudioProfileNameLookup)) {
|
||||
|
@ -2107,7 +2282,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
return (isset($QuicktimeIODSaudioProfileNameLookup[$audio_profile_id]) ? $QuicktimeIODSaudioProfileNameLookup[$audio_profile_id] : 'ISO Reserved / User Private');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $video_profile_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function QuicktimeIODSvideoProfileName($video_profile_id) {
|
||||
static $QuicktimeIODSvideoProfileNameLookup = array();
|
||||
if (empty($QuicktimeIODSvideoProfileNameLookup)) {
|
||||
|
@ -2179,7 +2358,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
return (isset($QuicktimeIODSvideoProfileNameLookup[$video_profile_id]) ? $QuicktimeIODSvideoProfileNameLookup[$video_profile_id] : 'ISO Reserved Profile');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $rtng
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function QuicktimeContentRatingLookup($rtng) {
|
||||
static $QuicktimeContentRatingLookup = array();
|
||||
if (empty($QuicktimeContentRatingLookup)) {
|
||||
|
@ -2190,6 +2373,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $akid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function QuicktimeStoreAccountTypeLookup($akid) {
|
||||
static $QuicktimeStoreAccountTypeLookup = array();
|
||||
if (empty($QuicktimeStoreAccountTypeLookup)) {
|
||||
|
@ -2199,6 +2387,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
return (isset($QuicktimeStoreAccountTypeLookup[$akid]) ? $QuicktimeStoreAccountTypeLookup[$akid] : 'invalid');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $sfid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function QuicktimeStoreFrontCodeLookup($sfid) {
|
||||
static $QuicktimeStoreFrontCodeLookup = array();
|
||||
if (empty($QuicktimeStoreFrontCodeLookup)) {
|
||||
|
@ -2228,6 +2421,11 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
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
|
||||
|
@ -2270,10 +2468,10 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
);
|
||||
|
||||
$offset = 0;
|
||||
$data = null;
|
||||
$datalength = strlen($atom_data);
|
||||
$parsed = array();
|
||||
while ($offset < $datalength) {
|
||||
//echo getid3_lib::PrintHexBytes(substr($atom_data, $offset, 4)).'<br>';
|
||||
$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;
|
||||
|
@ -2406,7 +2604,13 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
return $parsed;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $keyname
|
||||
* @param string|array $data
|
||||
* @param string $boxname
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function CopyToAppropriateCommentsSection($keyname, $data, $boxname='') {
|
||||
static $handyatomtranslatorarray = array();
|
||||
if (empty($handyatomtranslatorarray)) {
|
||||
|
@ -2450,7 +2654,7 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
$handyatomtranslatorarray["\xA9".'src'] = 'source_credit';
|
||||
$handyatomtranslatorarray["\xA9".'swr'] = 'software';
|
||||
$handyatomtranslatorarray["\xA9".'too'] = 'encoding_tool'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'trk'] = 'track';
|
||||
$handyatomtranslatorarray["\xA9".'trk'] = 'track_number';
|
||||
$handyatomtranslatorarray["\xA9".'url'] = 'url';
|
||||
$handyatomtranslatorarray["\xA9".'wrn'] = 'warning';
|
||||
$handyatomtranslatorarray["\xA9".'wrt'] = 'composer';
|
||||
|
@ -2503,8 +2707,8 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
$handyatomtranslatorarray['MusicBrainz Disc Id'] = 'MusicBrainz Disc Id';
|
||||
|
||||
// http://age.hobba.nl/audio/tag_frame_reference.html
|
||||
$handyatomtranslatorarray['PLAY_COUNTER'] = 'play_counter'; // Foobar2000 - http://www.getid3.org/phpBB3/viewtopic.php?t=1355
|
||||
$handyatomtranslatorarray['MEDIATYPE'] = 'mediatype'; // Foobar2000 - http://www.getid3.org/phpBB3/viewtopic.php?t=1355
|
||||
$handyatomtranslatorarray['PLAY_COUNTER'] = 'play_counter'; // Foobar2000 - https://www.getid3.org/phpBB3/viewtopic.php?t=1355
|
||||
$handyatomtranslatorarray['MEDIATYPE'] = 'mediatype'; // Foobar2000 - https://www.getid3.org/phpBB3/viewtopic.php?t=1355
|
||||
*/
|
||||
}
|
||||
$info = &$this->getid3->info;
|
||||
|
@ -2542,6 +2746,12 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $lstring
|
||||
* @param int $count
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function LociString($lstring, &$count) {
|
||||
// Loci strings are UTF-8 or UTF-16 and null (x00/x0000) terminated. UTF-16 has a BOM
|
||||
// Also need to return the number of bytes the string occupied so additional fields can be extracted
|
||||
|
@ -2555,7 +2765,7 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
return '';
|
||||
}
|
||||
// check for BOM
|
||||
if ($len > 2 && (($lstring[0] == "\xFE" && $lstring[1] == "\xFF") || ($lstring[0] == "\xFF" && $lstring[1] == "\xFE"))) {
|
||||
if (($len > 2) && ((($lstring[0] == "\xFE") && ($lstring[1] == "\xFF")) || (($lstring[0] == "\xFF") && ($lstring[1] == "\xFE")))) {
|
||||
// UTF-16
|
||||
if (preg_match('/(.*)\x00/', $lstring, $lmatches)) {
|
||||
$count = strlen($lmatches[1]) * 2 + 2; //account for 2 byte characters and trailing \x0000
|
||||
|
@ -2563,18 +2773,20 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
} else {
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
}
|
||||
// UTF-8
|
||||
if (preg_match('/(.*)\x00/', $lstring, $lmatches)) {
|
||||
$count = strlen($lmatches[1]) + 1; //account for trailing \x00
|
||||
return $lmatches[1];
|
||||
}else {
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $nullterminatedstring
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function NoNullString($nullterminatedstring) {
|
||||
// remove the single null terminator on null terminated strings
|
||||
if (substr($nullterminatedstring, strlen($nullterminatedstring) - 1, 1) === "\x00") {
|
||||
|
@ -2583,15 +2795,25 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
return $nullterminatedstring;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $pascalstring
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function Pascal2String($pascalstring) {
|
||||
// Pascal strings have 1 unsigned byte at the beginning saying how many chars (1-255) are in the string
|
||||
return substr($pascalstring, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// helper functions for m4b audiobook chapters
|
||||
// code by Steffen Hartmann 2015-Nov-08
|
||||
/**
|
||||
* Helper functions for m4b audiobook chapters
|
||||
* code by Steffen Hartmann 2015-Nov-08.
|
||||
*
|
||||
* @param array $info
|
||||
* @param string $tag
|
||||
* @param string $history
|
||||
* @param array $result
|
||||
*/
|
||||
public function search_tag_by_key($info, $tag, $history, &$result) {
|
||||
foreach ($info as $key => $value) {
|
||||
|
@ -2606,6 +2828,13 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $info
|
||||
* @param string $k
|
||||
* @param string $v
|
||||
* @param string $history
|
||||
* @param array $result
|
||||
*/
|
||||
public function search_tag_by_pair($info, $k, $v, $history, &$result) {
|
||||
foreach ($info as $key => $value) {
|
||||
$key_history = $history.'/'.$key;
|
||||
|
@ -2619,6 +2848,11 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $info
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function quicktime_time_to_sample_table($info) {
|
||||
$res = array();
|
||||
$this->search_tag_by_pair($info['quicktime']['moov'], 'name', 'stbl', 'quicktime/moov', $res);
|
||||
|
@ -2636,7 +2870,12 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
return array();
|
||||
}
|
||||
|
||||
function quicktime_bookmark_time_scale($info) {
|
||||
/**
|
||||
* @param array $info
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function quicktime_bookmark_time_scale($info) {
|
||||
$time_scale = '';
|
||||
$ts_prefix_len = 0;
|
||||
$res = array();
|
||||
|
@ -2647,10 +2886,10 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
if (count($stbl_res) > 0) {
|
||||
$ts_res = array();
|
||||
$this->search_tag_by_key($info['quicktime']['moov'], 'time_scale', 'quicktime/moov', $ts_res);
|
||||
foreach ($ts_res as $value) {
|
||||
$prefix = substr($value[0], 0, -12);
|
||||
foreach ($ts_res as $sub_value) {
|
||||
$prefix = substr($sub_value[0], 0, -12);
|
||||
if ((substr($stbl_res[0][0], 0, strlen($prefix)) === $prefix) && ($ts_prefix_len < strlen($prefix))) {
|
||||
$time_scale = $value[1]['time_scale'];
|
||||
$time_scale = $sub_value[1]['time_scale'];
|
||||
$ts_prefix_len = strlen($prefix);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio-video.riff.php //
|
||||
|
@ -27,10 +27,15 @@ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE_
|
|||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true);
|
||||
|
||||
class getid3_riff extends getid3_handler {
|
||||
|
||||
class getid3_riff extends getid3_handler
|
||||
{
|
||||
protected $container = 'riff'; // default
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*
|
||||
* @throws getid3_exception
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -46,6 +51,7 @@ class getid3_riff extends getid3_handler {
|
|||
$thisfile_audio_dataformat = &$thisfile_audio['dataformat'];
|
||||
$thisfile_riff_audio = &$thisfile_riff['audio'];
|
||||
$thisfile_riff_video = &$thisfile_riff['video'];
|
||||
$thisfile_riff_WAVE = array();
|
||||
|
||||
$Original['avdataoffset'] = $info['avdataoffset'];
|
||||
$Original['avdataend'] = $info['avdataend'];
|
||||
|
@ -357,6 +363,7 @@ class getid3_riff extends getid3_handler {
|
|||
}
|
||||
$thisfile_riff_WAVE_cart_0['url'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 748, 1024));
|
||||
$thisfile_riff_WAVE_cart_0['tag_text'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772)));
|
||||
$thisfile_riff['comments']['tag_text'][] = substr($thisfile_riff_WAVE_cart_0['data'], 1772);
|
||||
|
||||
$thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist'];
|
||||
$thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_cart_0['title'];
|
||||
|
@ -405,7 +412,6 @@ class getid3_riff extends getid3_handler {
|
|||
'tracktitle'=>'title',
|
||||
'category' =>'genre',
|
||||
'cdtitle' =>'album',
|
||||
'tracktitle'=>'title',
|
||||
);
|
||||
foreach ($tagmapping as $fromkey => $tokey) {
|
||||
if (isset($thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey])) {
|
||||
|
@ -613,6 +619,8 @@ class getid3_riff extends getid3_handler {
|
|||
$thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably
|
||||
$thisfile_video['dataformat'] = 'avi';
|
||||
|
||||
$thisfile_riff_video_current = array();
|
||||
|
||||
if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) {
|
||||
$info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8;
|
||||
if (isset($thisfile_riff['AVIX'])) {
|
||||
|
@ -701,6 +709,7 @@ class getid3_riff extends getid3_handler {
|
|||
|
||||
// shortcut
|
||||
$thisfile_riff_video[$streamindex] = array();
|
||||
/** @var array $thisfile_riff_video_current */
|
||||
$thisfile_riff_video_current = &$thisfile_riff_video[$streamindex];
|
||||
|
||||
if ($thisfile_riff_raw_avih['dwWidth'] > 0) {
|
||||
|
@ -867,7 +876,7 @@ class getid3_riff extends getid3_handler {
|
|||
}
|
||||
}
|
||||
|
||||
if (isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
|
||||
if (isset($thisfile_riff_raw_strf_strhfccType_streamindex) && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
|
||||
|
||||
$thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
|
||||
if (self::fourccLookup($thisfile_video['fourcc'])) {
|
||||
|
@ -934,7 +943,7 @@ class getid3_riff extends getid3_handler {
|
|||
|
||||
$thisfile_riff_CDDA_fmt_0['start_offset_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['start_offset_frame'] / 75;
|
||||
$thisfile_riff_CDDA_fmt_0['playtime_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75;
|
||||
$info['comments']['track'] = $thisfile_riff_CDDA_fmt_0['track_num'];
|
||||
$info['comments']['track_number'] = $thisfile_riff_CDDA_fmt_0['track_num'];
|
||||
$info['playtime_seconds'] = $thisfile_riff_CDDA_fmt_0['playtime_seconds'];
|
||||
|
||||
// hardcoded data for CD-audio
|
||||
|
@ -1057,7 +1066,7 @@ class getid3_riff extends getid3_handler {
|
|||
if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) {
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
|
||||
$getid3_id3v2 = new getid3_id3v2($getid3_temp);
|
||||
$getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8;
|
||||
if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
|
||||
|
@ -1077,6 +1086,7 @@ class getid3_riff extends getid3_handler {
|
|||
$thisfile_audio_dataformat = '8svx';
|
||||
$thisfile_audio['bits_per_sample'] = 8;
|
||||
$thisfile_audio['channels'] = 1; // overridden below, if need be
|
||||
$ActualBitsPerSample = 0;
|
||||
|
||||
if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) {
|
||||
$info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8;
|
||||
|
@ -1114,7 +1124,7 @@ class getid3_riff extends getid3_handler {
|
|||
break;
|
||||
|
||||
default:
|
||||
$this->warning('Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.sCompression.'"');
|
||||
$this->warning('Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.$thisfile_riff_RIFFsubtype_VHDR_0['sCompression'].'"');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1159,7 +1169,7 @@ class getid3_riff extends getid3_handler {
|
|||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, true);
|
||||
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
|
||||
$getid3_mpeg = new getid3_mpeg($getid3_temp);
|
||||
$getid3_mpeg->Analyze();
|
||||
if (empty($getid3_temp->info['error'])) {
|
||||
|
@ -1245,7 +1255,7 @@ class getid3_riff extends getid3_handler {
|
|||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
|
||||
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
|
||||
$getid3_id3v2 = new getid3_id3v2($getid3_temp);
|
||||
$getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8;
|
||||
if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
|
||||
|
@ -1372,6 +1382,15 @@ class getid3_riff extends getid3_handler {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $startoffset
|
||||
* @param int $maxoffset
|
||||
*
|
||||
* @return array|false
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws getid3_exception
|
||||
*/
|
||||
public function ParseRIFFAMV($startoffset, $maxoffset) {
|
||||
// AMV files are RIFF-AVI files with parts of the spec deliberately broken, such as chunk size fields hardcoded to zero (because players known in hardware that these fields are always a certain size
|
||||
|
||||
|
@ -1480,7 +1499,13 @@ class getid3_riff extends getid3_handler {
|
|||
return $RIFFchunk;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $startoffset
|
||||
* @param int $maxoffset
|
||||
*
|
||||
* @return array|false
|
||||
* @throws getid3_exception
|
||||
*/
|
||||
public function ParseRIFF($startoffset, $maxoffset) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -1529,7 +1554,7 @@ class getid3_riff extends getid3_handler {
|
|||
// MP3
|
||||
if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
|
||||
$getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
|
||||
$getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
|
||||
$getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
|
||||
|
@ -1551,7 +1576,7 @@ class getid3_riff extends getid3_handler {
|
|||
|
||||
// AC3
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
|
||||
$getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
|
||||
$getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
|
||||
$getid3_ac3 = new getid3_ac3($getid3_temp);
|
||||
|
@ -1612,7 +1637,7 @@ class getid3_riff extends getid3_handler {
|
|||
// Probably is MP3 data
|
||||
if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
|
||||
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
|
||||
$getid3_temp->info['avdataend'] = $info['avdataend'];
|
||||
$getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
|
||||
|
@ -1629,7 +1654,7 @@ class getid3_riff extends getid3_handler {
|
|||
// This is probably AC-3 data
|
||||
$getid3_temp = new getID3();
|
||||
if ($isRegularAC3) {
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
|
||||
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
|
||||
$getid3_temp->info['avdataend'] = $info['avdataend'];
|
||||
}
|
||||
|
@ -1663,7 +1688,7 @@ class getid3_riff extends getid3_handler {
|
|||
|
||||
// This is probably DTS data
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
|
||||
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
|
||||
$getid3_dts = new getid3_dts($getid3_temp);
|
||||
$getid3_dts->Analyze();
|
||||
|
@ -1731,8 +1756,77 @@ class getid3_riff extends getid3_handler {
|
|||
// $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunksize));
|
||||
// break;
|
||||
|
||||
case 'scot':
|
||||
// https://cmsdk.com/node-js/adding-scot-chunk-to-wav-file.html
|
||||
$RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['alter'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 0, 1);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['attrib'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 1, 1);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['artnum'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 2, 2));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['title'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 4, 43); // "name" in other documentation
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['copy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 47, 4);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['padd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 51, 1);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['asclen'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 52, 5);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['startseconds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 57, 2));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['starthundredths'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 59, 2));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['endseconds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 61, 2));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['endhundreths'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 63, 2));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['sdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 65, 6);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['kdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 71, 6);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['start_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 77, 1);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['kill_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 78, 1);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['digital'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 79, 1);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 80, 2));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['stereo'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 82, 1);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['compress'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 83, 1);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['eomstrt'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 84, 4));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['eomlen'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 88, 2));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['attrib2'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 90, 4));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['future1'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 94, 12);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['catfontcolor'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 106, 4));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['catcolor'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 110, 4));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['segeompos'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 114, 4));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['vt_startsecs'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 118, 2));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['vt_starthunds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 120, 2));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['priorcat'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 122, 3);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['priorcopy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 125, 4);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['priorpadd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 129, 1);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['postcat'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 130, 3);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['postcopy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 133, 4);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['postpadd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 137, 1);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['hrcanplay'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 138, 21);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['future2'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 159, 108);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['artist'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 267, 34);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['comment'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 301, 34); // "trivia" in other documentation
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['intro'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 335, 2);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['end'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 337, 1);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['year'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 338, 4);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['obsolete2'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 342, 1);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['rec_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 343, 1);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['rdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 344, 6);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['mpeg_bitrate'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 350, 2));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['pitch'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 352, 2));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['playlevel'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 354, 2));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['lenvalid'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 356, 1);
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 357, 4));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['newplaylevel'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 361, 2));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['chopsize'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 363, 4));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['vteomovr'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 367, 4));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['desiredlen'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 371, 4));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['triggers'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 375, 4));
|
||||
$RIFFchunk[$chunkname][$thisindex]['parsed']['fillout'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 379, 33);
|
||||
|
||||
foreach (array('title', 'artist', 'comment') as $key) {
|
||||
if (trim($RIFFchunk[$chunkname][$thisindex]['parsed'][$key])) {
|
||||
$info['riff']['comments'][$key] = array($RIFFchunk[$chunkname][$thisindex]['parsed'][$key]);
|
||||
}
|
||||
}
|
||||
if ($RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] && !empty($info['filesize']) && ($RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] != $info['filesize'])) {
|
||||
$this->warning('RIFF.WAVE.scot.filelength ('.$RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'].') different from actual filesize ('.$info['filesize'].')');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!empty($LISTchunkParent) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) {
|
||||
if (!empty($LISTchunkParent) && isset($LISTchunkMaxOffset) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) {
|
||||
$RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset'];
|
||||
$RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['size'] = $RIFFchunk[$chunkname][$thisindex]['size'];
|
||||
unset($RIFFchunk[$chunkname][$thisindex]['offset']);
|
||||
|
@ -1767,6 +1861,11 @@ class getid3_riff extends getid3_handler {
|
|||
return $RIFFchunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $RIFFdata
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ParseRIFFdata(&$RIFFdata) {
|
||||
$info = &$this->getid3->info;
|
||||
if ($RIFFdata) {
|
||||
|
@ -1804,6 +1903,12 @@ class getid3_riff extends getid3_handler {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $RIFFinfoArray
|
||||
* @param array $CommentsTargetArray
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) {
|
||||
$RIFFinfoKeyLookup = array(
|
||||
'IARL'=>'archivallocation',
|
||||
|
@ -1863,8 +1968,14 @@ class getid3_riff extends getid3_handler {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $WaveFormatExData
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function parseWAVEFORMATex($WaveFormatExData) {
|
||||
// shortcut
|
||||
$WaveFormatEx = array();
|
||||
$WaveFormatEx['raw'] = array();
|
||||
$WaveFormatEx_raw = &$WaveFormatEx['raw'];
|
||||
|
||||
|
@ -1888,6 +1999,11 @@ class getid3_riff extends getid3_handler {
|
|||
return $WaveFormatEx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $WavPackChunkData
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function parseWavPackHeader($WavPackChunkData) {
|
||||
// typedef struct {
|
||||
// char ckID [4];
|
||||
|
@ -1949,6 +2065,12 @@ class getid3_riff extends getid3_handler {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $BITMAPINFOHEADER
|
||||
* @param bool $littleEndian
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) {
|
||||
|
||||
$parsed['biSize'] = substr($BITMAPINFOHEADER, 0, 4); // number of bytes required by the BITMAPINFOHEADER structure
|
||||
|
@ -1968,6 +2090,12 @@ class getid3_riff extends getid3_handler {
|
|||
return $parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $DIVXTAG
|
||||
* @param bool $raw
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function ParseDIVXTAG($DIVXTAG, $raw=false) {
|
||||
// structure from "IDivX" source, Form1.frm, by "Greg Frazier of Daemonic Software Group", email: gfrazier@icestorm.net, web: http://dsg.cjb.net/
|
||||
// source available at http://files.divx-digest.com/download/c663efe7ef8ad2e90bf4af4d3ea6188a/on0SWN2r/edit/IDivX.zip
|
||||
|
@ -2014,6 +2142,7 @@ class getid3_riff extends getid3_handler {
|
|||
5 => 'NC-17',
|
||||
);
|
||||
|
||||
$parsed = array();
|
||||
$parsed['title'] = trim(substr($DIVXTAG, 0, 32));
|
||||
$parsed['artist'] = trim(substr($DIVXTAG, 32, 28));
|
||||
$parsed['year'] = intval(trim(substr($DIVXTAG, 60, 4)));
|
||||
|
@ -2029,8 +2158,8 @@ class getid3_riff extends getid3_handler {
|
|||
if (!$raw) {
|
||||
unset($parsed['genre_id'], $parsed['rating_id']);
|
||||
foreach ($parsed as $key => $value) {
|
||||
if (!$value === '') {
|
||||
unset($parsed['key']);
|
||||
if (empty($value)) {
|
||||
unset($parsed[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2042,6 +2171,11 @@ class getid3_riff extends getid3_handler {
|
|||
return $parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tagshortname
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function waveSNDMtagLookup($tagshortname) {
|
||||
$begin = __LINE__;
|
||||
|
||||
|
@ -2065,6 +2199,11 @@ class getid3_riff extends getid3_handler {
|
|||
return getid3_lib::EmbeddedLookup($tagshortname, $begin, __LINE__, __FILE__, 'riff-sndm');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $wFormatTag
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function wFormatTagLookup($wFormatTag) {
|
||||
|
||||
$begin = __LINE__;
|
||||
|
@ -2234,6 +2373,11 @@ class getid3_riff extends getid3_handler {
|
|||
return getid3_lib::EmbeddedLookup('0x'.str_pad(strtoupper(dechex($wFormatTag)), 4, '0', STR_PAD_LEFT), $begin, __LINE__, __FILE__, 'riff-wFormatTag');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fourcc
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function fourccLookup($fourcc) {
|
||||
|
||||
$begin = __LINE__;
|
||||
|
@ -2628,6 +2772,12 @@ class getid3_riff extends getid3_handler {
|
|||
return getid3_lib::EmbeddedLookup($fourcc, $begin, __LINE__, __FILE__, 'riff-fourcc');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $byteword
|
||||
* @param bool $signed
|
||||
*
|
||||
* @return int|float|false
|
||||
*/
|
||||
private function EitherEndian2Int($byteword, $signed=false) {
|
||||
if ($this->container == 'riff') {
|
||||
return getid3_lib::LittleEndian2Int($byteword, $signed);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.ac3.php //
|
||||
|
@ -17,11 +17,21 @@
|
|||
|
||||
class getid3_ac3 extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $AC3header = array();
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $BSIoffset = 0;
|
||||
|
||||
const syncword = 0x0B77;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -439,7 +449,9 @@ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16
|
|||
}
|
||||
$info['audio']['bitrate'] = $thisfile_ac3['bitrate'];
|
||||
|
||||
if (isset($thisfile_ac3_raw_bsi['bsmod']) && isset($thisfile_ac3_raw_bsi['acmod'])) {
|
||||
$thisfile_ac3['service_type'] = self::serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']);
|
||||
}
|
||||
$ac3_coding_mode = self::audioCodingModeLookup($thisfile_ac3_raw_bsi['acmod']);
|
||||
foreach($ac3_coding_mode as $key => $value) {
|
||||
$thisfile_ac3[$key] = $value;
|
||||
|
@ -470,6 +482,11 @@ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $length
|
||||
*
|
||||
* @return float|int
|
||||
*/
|
||||
private function readHeaderBSI($length) {
|
||||
$data = substr($this->AC3header['bsi'], $this->BSIoffset, $length);
|
||||
$this->BSIoffset += $length;
|
||||
|
@ -477,6 +494,11 @@ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16
|
|||
return bindec($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $fscod
|
||||
*
|
||||
* @return int|string|false
|
||||
*/
|
||||
public static function sampleRateCodeLookup($fscod) {
|
||||
static $sampleRateCodeLookup = array(
|
||||
0 => 48000,
|
||||
|
@ -487,6 +509,11 @@ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16
|
|||
return (isset($sampleRateCodeLookup[$fscod]) ? $sampleRateCodeLookup[$fscod] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $fscod2
|
||||
*
|
||||
* @return int|string|false
|
||||
*/
|
||||
public static function sampleRateCodeLookup2($fscod2) {
|
||||
static $sampleRateCodeLookup2 = array(
|
||||
0 => 24000,
|
||||
|
@ -497,6 +524,12 @@ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16
|
|||
return (isset($sampleRateCodeLookup2[$fscod2]) ? $sampleRateCodeLookup2[$fscod2] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $bsmod
|
||||
* @param int $acmod
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function serviceTypeLookup($bsmod, $acmod) {
|
||||
static $serviceTypeLookup = array();
|
||||
if (empty($serviceTypeLookup)) {
|
||||
|
@ -518,6 +551,11 @@ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16
|
|||
return (isset($serviceTypeLookup[$bsmod][$acmod]) ? $serviceTypeLookup[$bsmod][$acmod] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $acmod
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public static function audioCodingModeLookup($acmod) {
|
||||
// array(channel configuration, # channels (not incl LFE), channel order)
|
||||
static $audioCodingModeLookup = array (
|
||||
|
@ -533,6 +571,11 @@ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16
|
|||
return (isset($audioCodingModeLookup[$acmod]) ? $audioCodingModeLookup[$acmod] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $cmixlev
|
||||
*
|
||||
* @return int|float|string|false
|
||||
*/
|
||||
public static function centerMixLevelLookup($cmixlev) {
|
||||
static $centerMixLevelLookup;
|
||||
if (empty($centerMixLevelLookup)) {
|
||||
|
@ -546,6 +589,11 @@ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16
|
|||
return (isset($centerMixLevelLookup[$cmixlev]) ? $centerMixLevelLookup[$cmixlev] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $surmixlev
|
||||
*
|
||||
* @return int|float|string|false
|
||||
*/
|
||||
public static function surroundMixLevelLookup($surmixlev) {
|
||||
static $surroundMixLevelLookup;
|
||||
if (empty($surroundMixLevelLookup)) {
|
||||
|
@ -559,6 +607,11 @@ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16
|
|||
return (isset($surroundMixLevelLookup[$surmixlev]) ? $surroundMixLevelLookup[$surmixlev] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $dsurmod
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function dolbySurroundModeLookup($dsurmod) {
|
||||
static $dolbySurroundModeLookup = array(
|
||||
0 => 'not indicated',
|
||||
|
@ -569,12 +622,18 @@ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16
|
|||
return (isset($dolbySurroundModeLookup[$dsurmod]) ? $dolbySurroundModeLookup[$dsurmod] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $acmod
|
||||
* @param bool $lfeon
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function channelsEnabledLookup($acmod, $lfeon) {
|
||||
$lookup = array(
|
||||
'ch1'=>(bool) ($acmod == 0),
|
||||
'ch2'=>(bool) ($acmod == 0),
|
||||
'left'=>(bool) ($acmod > 1),
|
||||
'right'=>(bool) ($acmod > 1),
|
||||
'ch1'=>($acmod == 0),
|
||||
'ch2'=>($acmod == 0),
|
||||
'left'=>($acmod > 1),
|
||||
'right'=>($acmod > 1),
|
||||
'center'=>(bool) ($acmod & 0x01),
|
||||
'surround_mono'=>false,
|
||||
'surround_left'=>false,
|
||||
|
@ -594,6 +653,11 @@ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16
|
|||
return $lookup;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $compre
|
||||
*
|
||||
* @return float|int
|
||||
*/
|
||||
public static function heavyCompression($compre) {
|
||||
// The first four bits indicate gain changes in 6.02dB increments which can be
|
||||
// implemented with an arithmetic shift operation. The following four bits
|
||||
|
@ -623,7 +687,7 @@ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16
|
|||
// -8 -42.14 dB
|
||||
|
||||
$fourbit = str_pad(decbin(($compre & 0xF0) >> 4), 4, '0', STR_PAD_LEFT);
|
||||
if ($fourbit{0} == '1') {
|
||||
if ($fourbit[0] == '1') {
|
||||
$log_gain = -8 + bindec(substr($fourbit, 1));
|
||||
} else {
|
||||
$log_gain = bindec(substr($fourbit, 1));
|
||||
|
@ -644,6 +708,11 @@ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16
|
|||
return $log_gain - $lin_gain;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $roomtyp
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function roomTypeLookup($roomtyp) {
|
||||
static $roomTypeLookup = array(
|
||||
0 => 'not indicated',
|
||||
|
@ -654,6 +723,12 @@ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16
|
|||
return (isset($roomTypeLookup[$roomtyp]) ? $roomTypeLookup[$roomtyp] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $frmsizecod
|
||||
* @param int $fscod
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public static function frameSizeLookup($frmsizecod, $fscod) {
|
||||
// LSB is whether padding is used or not
|
||||
$padding = (bool) ($frmsizecod & 0x01);
|
||||
|
@ -683,13 +758,20 @@ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16
|
|||
18 => array(2560, 2786, 3840) // 640 kbps
|
||||
);
|
||||
}
|
||||
$paddingBytes = 0;
|
||||
if (($fscod == 1) && $padding) {
|
||||
// frame lengths are padded by 1 word (16 bits) at 44100
|
||||
$frameSizeLookup[$frmsizecod] += 2;
|
||||
// (fscode==1) means 44100Hz (see sampleRateCodeLookup)
|
||||
$paddingBytes = 2;
|
||||
}
|
||||
return (isset($frameSizeLookup[$framesizeid][$fscod]) ? $frameSizeLookup[$framesizeid][$fscod] : false);
|
||||
return (isset($frameSizeLookup[$framesizeid][$fscod]) ? $frameSizeLookup[$framesizeid][$fscod] + $paddingBytes : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $frmsizecod
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public static function bitrateLookup($frmsizecod) {
|
||||
// LSB is whether padding is used or not
|
||||
$padding = (bool) ($frmsizecod & 0x01);
|
||||
|
@ -719,6 +801,11 @@ $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16
|
|||
return (isset($bitrateLookup[$framesizeid]) ? $bitrateLookup[$framesizeid] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $numblkscod
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public static function blocksPerSyncFrame($numblkscod) {
|
||||
static $blocksPerSyncFrameLookup = array(
|
||||
0 => 1,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.dts.php //
|
||||
|
@ -21,14 +21,17 @@
|
|||
class getid3_dts extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* Default DTS syncword used in native .cpt or .dts formats
|
||||
* Default DTS syncword used in native .cpt or .dts formats.
|
||||
*/
|
||||
const syncword = "\x7F\xFE\x80\x01";
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $readBinDataOffset = 0;
|
||||
|
||||
/**
|
||||
* Possible syncwords indicating bitstream encoding
|
||||
* Possible syncwords indicating bitstream encoding.
|
||||
*/
|
||||
public static $syncwords = array(
|
||||
0 => "\x7F\xFE\x80\x01", // raw big-endian
|
||||
|
@ -36,6 +39,9 @@ class getid3_dts extends getid3_handler
|
|||
2 => "\x1F\xFF\xE8\x00", // 14-bit big-endian
|
||||
3 => "\xFF\x1F\x00\xE8"); // 14-bit little-endian
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
$info['fileformat'] = 'dts';
|
||||
|
@ -139,6 +145,12 @@ class getid3_dts extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $bin
|
||||
* @param int $length
|
||||
*
|
||||
* @return float|int
|
||||
*/
|
||||
private function readBinData($bin, $length) {
|
||||
$data = substr($bin, $this->readBinDataOffset, $length);
|
||||
$this->readBinDataOffset += $length;
|
||||
|
@ -146,6 +158,11 @@ class getid3_dts extends getid3_handler
|
|||
return bindec($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return int|string|false
|
||||
*/
|
||||
public static function bitrateLookup($index) {
|
||||
static $lookup = array(
|
||||
0 => 32000,
|
||||
|
@ -184,6 +201,11 @@ class getid3_dts extends getid3_handler
|
|||
return (isset($lookup[$index]) ? $lookup[$index] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return int|string|false
|
||||
*/
|
||||
public static function sampleRateLookup($index) {
|
||||
static $lookup = array(
|
||||
0 => 'invalid',
|
||||
|
@ -206,6 +228,11 @@ class getid3_dts extends getid3_handler
|
|||
return (isset($lookup[$index]) ? $lookup[$index] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public static function bitPerSampleLookup($index) {
|
||||
static $lookup = array(
|
||||
0 => 16,
|
||||
|
@ -216,6 +243,11 @@ class getid3_dts extends getid3_handler
|
|||
return (isset($lookup[$index]) ? $lookup[$index] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public static function numChannelsLookup($index) {
|
||||
switch ($index) {
|
||||
case 0:
|
||||
|
@ -254,6 +286,11 @@ class getid3_dts extends getid3_handler
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function channelArrangementLookup($index) {
|
||||
static $lookup = array(
|
||||
0 => 'A',
|
||||
|
@ -276,6 +313,12 @@ class getid3_dts extends getid3_handler
|
|||
return (isset($lookup[$index]) ? $lookup[$index] : 'user-defined');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
* @param int $version
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public static function dialogNormalization($index, $version) {
|
||||
switch ($version) {
|
||||
case 7:
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.flac.php //
|
||||
|
@ -24,6 +24,9 @@ class getid3_flac extends getid3_handler
|
|||
{
|
||||
const syncword = 'fLaC';
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -41,22 +44,30 @@ class getid3_flac extends getid3_handler
|
|||
return $this->parseMETAdata();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function parseMETAdata() {
|
||||
$info = &$this->getid3->info;
|
||||
do {
|
||||
$BlockOffset = $this->ftell();
|
||||
$BlockHeader = $this->fread(4);
|
||||
$LBFBT = getid3_lib::BigEndian2Int(substr($BlockHeader, 0, 1));
|
||||
$LBFBT = getid3_lib::BigEndian2Int(substr($BlockHeader, 0, 1)); // LBFBT = LastBlockFlag + BlockType
|
||||
$LastBlockFlag = (bool) ($LBFBT & 0x80);
|
||||
$BlockType = ($LBFBT & 0x7F);
|
||||
$BlockLength = getid3_lib::BigEndian2Int(substr($BlockHeader, 1, 3));
|
||||
$BlockTypeText = self::metaBlockTypeLookup($BlockType);
|
||||
|
||||
if (($BlockOffset + 4 + $BlockLength) > $info['avdataend']) {
|
||||
$this->error('METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockTypeText.') at offset '.$BlockOffset.' extends beyond end of file');
|
||||
$this->warning('METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockTypeText.') at offset '.$BlockOffset.' extends beyond end of file');
|
||||
break;
|
||||
}
|
||||
if ($BlockLength < 1) {
|
||||
if ($BlockTypeText != 'reserved') {
|
||||
// probably supposed to be zero-length
|
||||
$this->warning('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockTypeText.') at offset '.$BlockOffset.' is zero bytes');
|
||||
continue;
|
||||
}
|
||||
$this->error('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockLength.') at offset '.$BlockOffset.' is invalid');
|
||||
break;
|
||||
}
|
||||
|
@ -194,12 +205,14 @@ class getid3_flac extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
private function parseSTREAMINFO($BlockData) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['flac']['STREAMINFO'] = array();
|
||||
$streaminfo = &$info['flac']['STREAMINFO'];
|
||||
|
||||
/**
|
||||
* @param string $BlockData
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function parseSTREAMINFOdata($BlockData) {
|
||||
$streaminfo = array();
|
||||
$streaminfo['min_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 0, 2));
|
||||
$streaminfo['max_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 2, 2));
|
||||
$streaminfo['min_frame_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 4, 3));
|
||||
|
@ -213,13 +226,26 @@ class getid3_flac extends getid3_handler
|
|||
|
||||
$streaminfo['audio_signature'] = substr($BlockData, 18, 16);
|
||||
|
||||
if (!empty($streaminfo['sample_rate'])) {
|
||||
return $streaminfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $BlockData
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function parseSTREAMINFO($BlockData) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['flac']['STREAMINFO'] = self::parseSTREAMINFOdata($BlockData);
|
||||
|
||||
if (!empty($info['flac']['STREAMINFO']['sample_rate'])) {
|
||||
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
$info['audio']['sample_rate'] = $streaminfo['sample_rate'];
|
||||
$info['audio']['channels'] = $streaminfo['channels'];
|
||||
$info['audio']['bits_per_sample'] = $streaminfo['bits_per_sample'];
|
||||
$info['playtime_seconds'] = $streaminfo['samples_stream'] / $streaminfo['sample_rate'];
|
||||
$info['audio']['sample_rate'] = $info['flac']['STREAMINFO']['sample_rate'];
|
||||
$info['audio']['channels'] = $info['flac']['STREAMINFO']['channels'];
|
||||
$info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample'];
|
||||
$info['playtime_seconds'] = $info['flac']['STREAMINFO']['samples_stream'] / $info['flac']['STREAMINFO']['sample_rate'];
|
||||
if ($info['playtime_seconds'] > 0) {
|
||||
if (!$this->isDependencyFor('matroska')) {
|
||||
$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
|
@ -236,6 +262,11 @@ class getid3_flac extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $BlockData
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function parseAPPLICATION($BlockData) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -246,6 +277,11 @@ class getid3_flac extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $BlockData
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function parseSEEKTABLE($BlockData) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -275,6 +311,11 @@ class getid3_flac extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $BlockData
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function parseVORBIS_COMMENT($BlockData) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -294,6 +335,11 @@ class getid3_flac extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $BlockData
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function parseCUESHEET($BlockData) {
|
||||
$info = &$this->getid3->info;
|
||||
$offset = 0;
|
||||
|
@ -348,6 +394,8 @@ class getid3_flac extends getid3_handler
|
|||
/**
|
||||
* Parse METADATA_BLOCK_PICTURE flac structure and extract attachment
|
||||
* External usage: audio.ogg
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function parsePICTURE() {
|
||||
$info = &$this->getid3->info;
|
||||
|
@ -380,6 +428,11 @@ class getid3_flac extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $blocktype
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function metaBlockTypeLookup($blocktype) {
|
||||
static $lookup = array(
|
||||
0 => 'STREAMINFO',
|
||||
|
@ -393,6 +446,11 @@ class getid3_flac extends getid3_handler
|
|||
return (isset($lookup[$blocktype]) ? $lookup[$blocktype] : 'reserved');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $applicationid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function applicationIDLookup($applicationid) {
|
||||
// http://flac.sourceforge.net/id.html
|
||||
static $lookup = array(
|
||||
|
@ -423,6 +481,11 @@ class getid3_flac extends getid3_handler
|
|||
return (isset($lookup[$applicationid]) ? $lookup[$applicationid] : 'reserved');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $type_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function pictureTypeLookup($type_id) {
|
||||
static $lookup = array (
|
||||
0 => 'Other',
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.mp3.php //
|
||||
|
@ -24,9 +24,17 @@ define('GETID3_MP3_VALID_CHECK_FRAMES', 35);
|
|||
|
||||
class getid3_mp3 extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* 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 $allow_bruteforce = false;
|
||||
|
||||
public $allow_bruteforce = false; // 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-unusuable files
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -35,7 +43,7 @@ class getid3_mp3 extends getid3_handler
|
|||
if (!$this->getOnlyMPEGaudioInfo($info['avdataoffset'])) {
|
||||
if ($this->allow_bruteforce) {
|
||||
$this->error('Rescanning file in BruteForce mode');
|
||||
$this->getOnlyMPEGaudioInfoBruteForce($this->getid3->fp, $info);
|
||||
$this->getOnlyMPEGaudioInfoBruteForce();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,7 +160,11 @@ class getid3_mp3 extends getid3_handler
|
|||
|
||||
// Calculate playtime
|
||||
if (!isset($info['playtime_seconds']) && isset($info['audio']['bitrate']) && ($info['audio']['bitrate'] > 0)) {
|
||||
$info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['audio']['bitrate'];
|
||||
// https://github.com/JamesHeinrich/getID3/issues/161
|
||||
// VBR header frame contains ~0.026s of silent audio data, but is not actually part of the original encoding and should be ignored
|
||||
$xingVBRheaderFrameLength = ((isset($info['mpeg']['audio']['VBR_frames']) && isset($info['mpeg']['audio']['framelength'])) ? $info['mpeg']['audio']['framelength'] : 0);
|
||||
|
||||
$info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset'] - $xingVBRheaderFrameLength) * 8 / $info['audio']['bitrate'];
|
||||
}
|
||||
|
||||
$info['audio']['encoder_options'] = $this->GuessEncoderOptions();
|
||||
|
@ -160,10 +172,14 @@ class getid3_mp3 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GuessEncoderOptions() {
|
||||
// shortcuts
|
||||
$info = &$this->getid3->info;
|
||||
$thisfile_mpeg_audio = array();
|
||||
$thisfile_mpeg_audio_lame = array();
|
||||
if (!empty($info['mpeg']['audio'])) {
|
||||
$thisfile_mpeg_audio = &$info['mpeg']['audio'];
|
||||
if (!empty($thisfile_mpeg_audio['LAME'])) {
|
||||
|
@ -178,7 +194,7 @@ class getid3_mp3 extends getid3_handler
|
|||
|
||||
$encoder_options = 'VBR q'.$thisfile_mpeg_audio['VBR_quality'];
|
||||
|
||||
} elseif (!empty($thisfile_mpeg_audio_lame['preset_used']) && (!in_array($thisfile_mpeg_audio_lame['preset_used_id'], $NamedPresetBitrates))) {
|
||||
} elseif (!empty($thisfile_mpeg_audio_lame['preset_used']) && isset($thisfile_mpeg_audio_lame['preset_used_id']) && (!in_array($thisfile_mpeg_audio_lame['preset_used_id'], $NamedPresetBitrates))) {
|
||||
|
||||
$encoder_options = $thisfile_mpeg_audio_lame['preset_used'];
|
||||
|
||||
|
@ -404,7 +420,15 @@ class getid3_mp3 extends getid3_handler
|
|||
return $encoder_options;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
* @param array $info
|
||||
* @param bool $recursivesearch
|
||||
* @param bool $ScanAsCBR
|
||||
* @param bool $FastMPEGheaderScan
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function decodeMPEGaudioHeader($offset, &$info, $recursivesearch=true, $ScanAsCBR=false, $FastMPEGheaderScan=false) {
|
||||
static $MPEGaudioVersionLookup;
|
||||
static $MPEGaudioLayerLookup;
|
||||
|
@ -458,7 +482,6 @@ class getid3_mp3 extends getid3_handler
|
|||
}
|
||||
$thisfile_mpeg_audio = &$info['mpeg']['audio'];
|
||||
|
||||
|
||||
if ($MPEGaudioHeaderValidCache[$head4_key]) {
|
||||
$thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray;
|
||||
} else {
|
||||
|
@ -655,7 +678,7 @@ class getid3_mp3 extends getid3_handler
|
|||
$used_filesize = $thisfile_mpeg_audio['VBR_bytes'];
|
||||
} elseif (!empty($info['filesize'])) {
|
||||
$used_filesize = $info['filesize'];
|
||||
$used_filesize -= intval(@$info['id3v2']['headerlength']);
|
||||
$used_filesize -= (isset($info['id3v2']['headerlength']) ? intval($info['id3v2']['headerlength']) : 0);
|
||||
$used_filesize -= (isset($info['id3v1']) ? 128 : 0);
|
||||
$used_filesize -= (isset($info['tag_offset_end']) ? $info['tag_offset_end'] - $info['tag_offset_start'] : 0);
|
||||
$this->warning('MP3.Xing header missing VBR_bytes, assuming MPEG audio portion of file is '.number_format($used_filesize).' bytes');
|
||||
|
@ -678,7 +701,7 @@ class getid3_mp3 extends getid3_handler
|
|||
if ($thisfile_mpeg_audio['xing_flags']['toc']) {
|
||||
$LAMEtocData = substr($headerstring, $VBRidOffset + 16, 100);
|
||||
for ($i = 0; $i < 100; $i++) {
|
||||
$thisfile_mpeg_audio['toc'][$i] = ord($LAMEtocData{$i});
|
||||
$thisfile_mpeg_audio['toc'][$i] = ord($LAMEtocData[$i]);
|
||||
}
|
||||
}
|
||||
if ($thisfile_mpeg_audio['xing_flags']['vbr_scale']) {
|
||||
|
@ -1083,6 +1106,13 @@ class getid3_mp3 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
* @param int $nextframetestoffset
|
||||
* @param bool $ScanAsCBR
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function RecursiveFrameScanning(&$offset, &$nextframetestoffset, $ScanAsCBR) {
|
||||
$info = &$this->getid3->info;
|
||||
$firstframetestarray = array('error' => array(), 'warning'=> array(), 'avdataend' => $info['avdataend'], 'avdataoffset' => $info['avdataoffset']);
|
||||
|
@ -1129,6 +1159,12 @@ class getid3_mp3 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
* @param bool $deepscan
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public function FreeFormatFrameLength($offset, $deepscan=false) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -1137,9 +1173,9 @@ class getid3_mp3 extends getid3_handler
|
|||
|
||||
$SyncPattern1 = substr($MPEGaudioData, 0, 4);
|
||||
// may be different pattern due to padding
|
||||
$SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) | 0x02).$SyncPattern1{3};
|
||||
$SyncPattern2 = $SyncPattern1[0].$SyncPattern1[1].chr(ord($SyncPattern1[2]) | 0x02).$SyncPattern1[3];
|
||||
if ($SyncPattern2 === $SyncPattern1) {
|
||||
$SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) & 0xFD).$SyncPattern1{3};
|
||||
$SyncPattern2 = $SyncPattern1[0].$SyncPattern1[1].chr(ord($SyncPattern1[2]) & 0xFD).$SyncPattern1[3];
|
||||
}
|
||||
|
||||
$framelength = false;
|
||||
|
@ -1206,6 +1242,9 @@ class getid3_mp3 extends getid3_handler
|
|||
return $framelength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getOnlyMPEGaudioInfoBruteForce() {
|
||||
$MPEGaudioHeaderDecodeCache = array();
|
||||
$MPEGaudioHeaderValidCache = array();
|
||||
|
@ -1241,9 +1280,9 @@ class getid3_mp3 extends getid3_handler
|
|||
if (strlen($head4) < 4) {
|
||||
break;
|
||||
}
|
||||
if ($head4{0} != "\xFF") {
|
||||
if ($head4[0] != "\xFF") {
|
||||
for ($i = 1; $i < 4; $i++) {
|
||||
if ($head4{$i} == "\xFF") {
|
||||
if ($head4[$i] == "\xFF") {
|
||||
$this->fseek($i - 4, SEEK_CUR);
|
||||
continue 2;
|
||||
}
|
||||
|
@ -1275,7 +1314,7 @@ class getid3_mp3 extends getid3_handler
|
|||
$WhereWeWere = $this->ftell();
|
||||
$this->fseek($MPEGaudioHeaderLengthCache[$head4] - 4, SEEK_CUR);
|
||||
$next4 = $this->fread(4);
|
||||
if ($next4{0} == "\xFF") {
|
||||
if ($next4[0] == "\xFF") {
|
||||
if (!isset($MPEGaudioHeaderDecodeCache[$next4])) {
|
||||
$MPEGaudioHeaderDecodeCache[$next4] = self::MPEGaudioHeaderDecode($next4);
|
||||
}
|
||||
|
@ -1353,7 +1392,12 @@ class getid3_mp3 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $avdataoffset
|
||||
* @param bool $BitrateHistogram
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getOnlyMPEGaudioInfo($avdataoffset, $BitrateHistogram=false) {
|
||||
// looks for synch, decodes MPEG audio header
|
||||
|
||||
|
@ -1366,7 +1410,6 @@ class getid3_mp3 extends getid3_handler
|
|||
$MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
|
||||
$MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
|
||||
$MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
|
||||
|
||||
}
|
||||
|
||||
$this->fseek($avdataoffset);
|
||||
|
@ -1416,7 +1459,8 @@ class getid3_mp3 extends getid3_handler
|
|||
return false;
|
||||
}
|
||||
|
||||
if (($header{$SynchSeekOffset} == "\xFF") && ($header{($SynchSeekOffset + 1)} > "\xE0")) { // synch detected
|
||||
if (($header[$SynchSeekOffset] == "\xFF") && ($header[($SynchSeekOffset + 1)] > "\xE0")) { // synch detected
|
||||
$FirstFrameAVDataOffset = null;
|
||||
if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) {
|
||||
$FirstFrameThisfileInfo = $info;
|
||||
$FirstFrameAVDataOffset = $avdataoffset + $SynchSeekOffset;
|
||||
|
@ -1440,7 +1484,7 @@ class getid3_mp3 extends getid3_handler
|
|||
$info['audio']['dataformat'] = 'mp3';
|
||||
break;
|
||||
}
|
||||
if (isset($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode']) && ($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr')) {
|
||||
if (isset($FirstFrameThisfileInfo) && isset($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode']) && ($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr')) {
|
||||
if (!(abs($info['audio']['bitrate'] - $FirstFrameThisfileInfo['audio']['bitrate']) <= 1)) {
|
||||
// If there is garbage data between a valid VBR header frame and a sequence
|
||||
// of valid MPEG-audio frames the VBR data is no longer discarded.
|
||||
|
@ -1510,7 +1554,7 @@ class getid3_mp3 extends getid3_handler
|
|||
$this->fseek($scan_start_offset[$current_segment]);
|
||||
$buffer_4k = $this->fread(4096);
|
||||
for ($j = 0; $j < (strlen($buffer_4k) - 4); $j++) {
|
||||
if (($buffer_4k{$j} == "\xFF") && ($buffer_4k{($j + 1)} > "\xE0")) { // synch detected
|
||||
if (($buffer_4k[$j] == "\xFF") && ($buffer_4k[($j + 1)] > "\xE0")) { // synch detected
|
||||
if ($this->decodeMPEGaudioHeader($scan_start_offset[$current_segment] + $j, $dummy, false, false, $FastMode)) {
|
||||
$calculated_next_offset = $scan_start_offset[$current_segment] + $j + $dummy['mpeg']['audio']['framelength'];
|
||||
if ($this->decodeMPEGaudioHeader($calculated_next_offset, $dummy, false, false, $FastMode)) {
|
||||
|
@ -1522,7 +1566,7 @@ class getid3_mp3 extends getid3_handler
|
|||
}
|
||||
}
|
||||
$synchstartoffset = $scan_start_offset[$current_segment];
|
||||
while ($this->decodeMPEGaudioHeader($synchstartoffset, $dummy, false, false, $FastMode)) {
|
||||
while (($synchstartoffset < $info['avdataend']) && $this->decodeMPEGaudioHeader($synchstartoffset, $dummy, false, false, $FastMode)) {
|
||||
$FastMode = true;
|
||||
$thisframebitrate = $MPEGaudioBitrateLookup[$MPEGaudioVersionLookup[$dummy['mpeg']['audio']['raw']['version']]][$MPEGaudioLayerLookup[$dummy['mpeg']['audio']['raw']['layer']]][$dummy['mpeg']['audio']['raw']['bitrate']];
|
||||
|
||||
|
@ -1633,17 +1677,25 @@ class getid3_mp3 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function MPEGaudioVersionArray() {
|
||||
static $MPEGaudioVersion = array('2.5', false, '2', '1');
|
||||
return $MPEGaudioVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function MPEGaudioLayerArray() {
|
||||
static $MPEGaudioLayer = array(false, 3, 2, 1);
|
||||
return $MPEGaudioLayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function MPEGaudioBitrateArray() {
|
||||
static $MPEGaudioBitrate;
|
||||
if (empty($MPEGaudioBitrate)) {
|
||||
|
@ -1663,6 +1715,9 @@ class getid3_mp3 extends getid3_handler
|
|||
return $MPEGaudioBitrate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function MPEGaudioFrequencyArray() {
|
||||
static $MPEGaudioFrequency;
|
||||
if (empty($MPEGaudioFrequency)) {
|
||||
|
@ -1675,11 +1730,17 @@ class getid3_mp3 extends getid3_handler
|
|||
return $MPEGaudioFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function MPEGaudioChannelModeArray() {
|
||||
static $MPEGaudioChannelMode = array('stereo', 'joint stereo', 'dual channel', 'mono');
|
||||
return $MPEGaudioChannelMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function MPEGaudioModeExtensionArray() {
|
||||
static $MPEGaudioModeExtension;
|
||||
if (empty($MPEGaudioModeExtension)) {
|
||||
|
@ -1692,15 +1753,31 @@ class getid3_mp3 extends getid3_handler
|
|||
return $MPEGaudioModeExtension;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function MPEGaudioEmphasisArray() {
|
||||
static $MPEGaudioEmphasis = array('none', '50/15ms', false, 'CCIT J.17');
|
||||
return $MPEGaudioEmphasis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $head4
|
||||
* @param bool $allowBitrate15
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function MPEGaudioHeaderBytesValid($head4, $allowBitrate15=false) {
|
||||
return self::MPEGaudioHeaderValid(self::MPEGaudioHeaderDecode($head4), false, $allowBitrate15);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $rawarray
|
||||
* @param bool $echoerrors
|
||||
* @param bool $allowBitrate15
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function MPEGaudioHeaderValid($rawarray, $echoerrors=false, $allowBitrate15=false) {
|
||||
if (($rawarray['synch'] & 0x0FFE) != 0x0FFE) {
|
||||
return false;
|
||||
|
@ -1773,6 +1850,11 @@ class getid3_mp3 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $Header4Bytes
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public static function MPEGaudioHeaderDecode($Header4Bytes) {
|
||||
// AAAA AAAA AAAB BCCD EEEE FFGH IIJJ KLMM
|
||||
// A - Frame sync (all bits set)
|
||||
|
@ -1794,22 +1876,31 @@ class getid3_mp3 extends getid3_handler
|
|||
}
|
||||
|
||||
$MPEGrawHeader['synch'] = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4;
|
||||
$MPEGrawHeader['version'] = (ord($Header4Bytes{1}) & 0x18) >> 3; // BB
|
||||
$MPEGrawHeader['layer'] = (ord($Header4Bytes{1}) & 0x06) >> 1; // CC
|
||||
$MPEGrawHeader['protection'] = (ord($Header4Bytes{1}) & 0x01); // D
|
||||
$MPEGrawHeader['bitrate'] = (ord($Header4Bytes{2}) & 0xF0) >> 4; // EEEE
|
||||
$MPEGrawHeader['sample_rate'] = (ord($Header4Bytes{2}) & 0x0C) >> 2; // FF
|
||||
$MPEGrawHeader['padding'] = (ord($Header4Bytes{2}) & 0x02) >> 1; // G
|
||||
$MPEGrawHeader['private'] = (ord($Header4Bytes{2}) & 0x01); // H
|
||||
$MPEGrawHeader['channelmode'] = (ord($Header4Bytes{3}) & 0xC0) >> 6; // II
|
||||
$MPEGrawHeader['modeextension'] = (ord($Header4Bytes{3}) & 0x30) >> 4; // JJ
|
||||
$MPEGrawHeader['copyright'] = (ord($Header4Bytes{3}) & 0x08) >> 3; // K
|
||||
$MPEGrawHeader['original'] = (ord($Header4Bytes{3}) & 0x04) >> 2; // L
|
||||
$MPEGrawHeader['emphasis'] = (ord($Header4Bytes{3}) & 0x03); // MM
|
||||
$MPEGrawHeader['version'] = (ord($Header4Bytes[1]) & 0x18) >> 3; // BB
|
||||
$MPEGrawHeader['layer'] = (ord($Header4Bytes[1]) & 0x06) >> 1; // CC
|
||||
$MPEGrawHeader['protection'] = (ord($Header4Bytes[1]) & 0x01); // D
|
||||
$MPEGrawHeader['bitrate'] = (ord($Header4Bytes[2]) & 0xF0) >> 4; // EEEE
|
||||
$MPEGrawHeader['sample_rate'] = (ord($Header4Bytes[2]) & 0x0C) >> 2; // FF
|
||||
$MPEGrawHeader['padding'] = (ord($Header4Bytes[2]) & 0x02) >> 1; // G
|
||||
$MPEGrawHeader['private'] = (ord($Header4Bytes[2]) & 0x01); // H
|
||||
$MPEGrawHeader['channelmode'] = (ord($Header4Bytes[3]) & 0xC0) >> 6; // II
|
||||
$MPEGrawHeader['modeextension'] = (ord($Header4Bytes[3]) & 0x30) >> 4; // JJ
|
||||
$MPEGrawHeader['copyright'] = (ord($Header4Bytes[3]) & 0x08) >> 3; // K
|
||||
$MPEGrawHeader['original'] = (ord($Header4Bytes[3]) & 0x04) >> 2; // L
|
||||
$MPEGrawHeader['emphasis'] = (ord($Header4Bytes[3]) & 0x03); // MM
|
||||
|
||||
return $MPEGrawHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|string $bitrate
|
||||
* @param string $version
|
||||
* @param string $layer
|
||||
* @param bool $padding
|
||||
* @param int $samplerate
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public static function MPEGaudioFrameLength(&$bitrate, &$version, &$layer, $padding, &$samplerate) {
|
||||
static $AudioFrameLengthCache = array();
|
||||
|
||||
|
@ -1871,6 +1962,11 @@ class getid3_mp3 extends getid3_handler
|
|||
return $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float|int $bit_rate
|
||||
*
|
||||
* @return int|float|string
|
||||
*/
|
||||
public static function ClosestStandardMP3Bitrate($bit_rate) {
|
||||
static $standard_bit_rates = array (320000, 256000, 224000, 192000, 160000, 128000, 112000, 96000, 80000, 64000, 56000, 48000, 40000, 32000, 24000, 16000, 8000);
|
||||
static $bit_rate_table = array (0=>'-');
|
||||
|
@ -1891,10 +1987,16 @@ class getid3_mp3 extends getid3_handler
|
|||
return $bit_rate_table[$round_bit_rate];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $version
|
||||
* @param string $channelmode
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function XingVBRidOffset($version, $channelmode) {
|
||||
static $XingVBRidOffsetCache = array();
|
||||
if (empty($XingVBRidOffset)) {
|
||||
$XingVBRidOffset = array (
|
||||
if (empty($XingVBRidOffsetCache)) {
|
||||
$XingVBRidOffsetCache = array (
|
||||
'1' => array ('mono' => 0x15, // 4 + 17 = 21
|
||||
'stereo' => 0x24, // 4 + 32 = 36
|
||||
'joint stereo' => 0x24,
|
||||
|
@ -1914,9 +2016,14 @@ class getid3_mp3 extends getid3_handler
|
|||
)
|
||||
);
|
||||
}
|
||||
return $XingVBRidOffset[$version][$channelmode];
|
||||
return $XingVBRidOffsetCache[$version][$channelmode];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $VBRmethodID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function LAMEvbrMethodLookup($VBRmethodID) {
|
||||
static $LAMEvbrMethodLookup = array(
|
||||
0x00 => 'unknown',
|
||||
|
@ -1933,6 +2040,11 @@ class getid3_mp3 extends getid3_handler
|
|||
return (isset($LAMEvbrMethodLookup[$VBRmethodID]) ? $LAMEvbrMethodLookup[$VBRmethodID] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $StereoModeID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function LAMEmiscStereoModeLookup($StereoModeID) {
|
||||
static $LAMEmiscStereoModeLookup = array(
|
||||
0 => 'mono',
|
||||
|
@ -1947,6 +2059,11 @@ class getid3_mp3 extends getid3_handler
|
|||
return (isset($LAMEmiscStereoModeLookup[$StereoModeID]) ? $LAMEmiscStereoModeLookup[$StereoModeID] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $SourceSampleFrequencyID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function LAMEmiscSourceSampleFrequencyLookup($SourceSampleFrequencyID) {
|
||||
static $LAMEmiscSourceSampleFrequencyLookup = array(
|
||||
0 => '<= 32 kHz',
|
||||
|
@ -1957,6 +2074,11 @@ class getid3_mp3 extends getid3_handler
|
|||
return (isset($LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID]) ? $LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $SurroundInfoID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function LAMEsurroundInfoLookup($SurroundInfoID) {
|
||||
static $LAMEsurroundInfoLookup = array(
|
||||
0 => 'no surround info',
|
||||
|
@ -1967,6 +2089,11 @@ class getid3_mp3 extends getid3_handler
|
|||
return (isset($LAMEsurroundInfoLookup[$SurroundInfoID]) ? $LAMEsurroundInfoLookup[$SurroundInfoID] : 'reserved');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $LAMEtag
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function LAMEpresetUsedLookup($LAMEtag) {
|
||||
|
||||
if ($LAMEtag['preset_used_id'] == 0) {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.ogg.php //
|
||||
|
@ -18,7 +18,11 @@ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.flac.php', __FILE
|
|||
|
||||
class getid3_ogg extends getid3_handler
|
||||
{
|
||||
// http://xiph.org/vorbis/doc/Vorbis_I_spec.html
|
||||
/**
|
||||
* @link http://xiph.org/vorbis/doc/Vorbis_I_spec.html
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -65,7 +69,7 @@ class getid3_ogg extends getid3_handler
|
|||
|
||||
} elseif (substr($filedata, 0, 8) == 'OpusHead') {
|
||||
|
||||
if( $this->ParseOpusPageHeader($filedata, $filedataoffset, $oggpageinfo) == false ) {
|
||||
if ($this->ParseOpusPageHeader($filedata, $filedataoffset, $oggpageinfo) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -259,9 +263,34 @@ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['
|
|||
$this->error('Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().']');
|
||||
//return false;
|
||||
|
||||
} elseif (substr($filedata, 0, 5) == "\x7F".'FLAC') {
|
||||
// https://xiph.org/flac/ogg_mapping.html
|
||||
|
||||
$info['audio']['dataformat'] = 'flac';
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
$info['audio']['lossless'] = true;
|
||||
|
||||
$info['ogg']['flac']['header']['version_major'] = ord(substr($filedata, 5, 1));
|
||||
$info['ogg']['flac']['header']['version_minor'] = ord(substr($filedata, 6, 1));
|
||||
$info['ogg']['flac']['header']['header_packets'] = getid3_lib::BigEndian2Int(substr($filedata, 7, 2)) + 1; // "A two-byte, big-endian binary number signifying the number of header (non-audio) packets, not including this one. This number may be zero (0x0000) to signify 'unknown' but be aware that some decoders may not be able to handle such streams."
|
||||
$info['ogg']['flac']['header']['magic'] = substr($filedata, 9, 4);
|
||||
if ($info['ogg']['flac']['header']['magic'] != 'fLaC') {
|
||||
$this->error('Ogg-FLAC expecting "fLaC", found "'.$info['ogg']['flac']['header']['magic'].'" ('.trim(getid3_lib::PrintHexBytes($info['ogg']['flac']['header']['magic'])).')');
|
||||
return false;
|
||||
}
|
||||
$info['ogg']['flac']['header']['STREAMINFO_bytes'] = getid3_lib::BigEndian2Int(substr($filedata, 13, 4));
|
||||
$info['flac']['STREAMINFO'] = getid3_flac::parseSTREAMINFOdata(substr($filedata, 17, 34));
|
||||
if (!empty($info['flac']['STREAMINFO']['sample_rate'])) {
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
$info['audio']['sample_rate'] = $info['flac']['STREAMINFO']['sample_rate'];
|
||||
$info['audio']['channels'] = $info['flac']['STREAMINFO']['channels'];
|
||||
$info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample'];
|
||||
$info['playtime_seconds'] = $info['flac']['STREAMINFO']['samples_stream'] / $info['flac']['STREAMINFO']['sample_rate'];
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$this->error('Expecting either "Speex ", "OpusHead" or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"');
|
||||
$this->error('Expecting one of "vorbis", "Speex", "OpusHead", "vorbis", "fishhead", "theora", "fLaC" identifier strings, found "'.substr($filedata, 0, 8).'"');
|
||||
unset($info['ogg']);
|
||||
unset($info['mime_type']);
|
||||
return false;
|
||||
|
@ -378,6 +407,13 @@ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filedata
|
||||
* @param int $filedataoffset
|
||||
* @param array $oggpageinfo
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ParseVorbisPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) {
|
||||
$info = &$this->getid3->info;
|
||||
$info['audio']['dataformat'] = 'vorbis';
|
||||
|
@ -426,7 +462,15 @@ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['
|
|||
return true;
|
||||
}
|
||||
|
||||
// http://tools.ietf.org/html/draft-ietf-codec-oggopus-03
|
||||
/**
|
||||
* @link http://tools.ietf.org/html/draft-ietf-codec-oggopus-03
|
||||
*
|
||||
* @param string $filedata
|
||||
* @param int $filedataoffset
|
||||
* @param array $oggpageinfo
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ParseOpusPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) {
|
||||
$info = &$this->getid3->info;
|
||||
$info['audio']['dataformat'] = 'opus';
|
||||
|
@ -458,7 +502,7 @@ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['
|
|||
$info['ogg']['pageheader']['opus']['pre_skip'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2));
|
||||
$filedataoffset += 2;
|
||||
|
||||
$info['ogg']['pageheader']['opus']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$info['ogg']['pageheader']['opus']['input_sample_rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
|
||||
//$info['ogg']['pageheader']['opus']['output_gain'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2));
|
||||
|
@ -468,15 +512,18 @@ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['
|
|||
//$filedataoffset += 1;
|
||||
|
||||
$info['opus']['opus_version'] = $info['ogg']['pageheader']['opus']['version'];
|
||||
$info['opus']['sample_rate'] = $info['ogg']['pageheader']['opus']['sample_rate'];
|
||||
$info['opus']['sample_rate_input'] = $info['ogg']['pageheader']['opus']['input_sample_rate'];
|
||||
$info['opus']['out_channel_count'] = $info['ogg']['pageheader']['opus']['out_channel_count'];
|
||||
|
||||
$info['audio']['channels'] = $info['opus']['out_channel_count'];
|
||||
$info['audio']['sample_rate'] = $info['opus']['sample_rate'];
|
||||
$info['audio']['sample_rate_input'] = $info['opus']['sample_rate_input'];
|
||||
$info['audio']['sample_rate'] = 48000; // "All Opus audio is coded at 48 kHz, and should also be decoded at 48 kHz for playback (unless the target hardware does not support this sampling rate). However, this field may be used to resample the audio back to the original sampling rate, for example, when saving the output to a file." -- https://mf4.xiph.org/jenkins/view/opus/job/opusfile-unix/ws/doc/html/structOpusHead.html
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array|false
|
||||
*/
|
||||
public function ParseOggPageHeader() {
|
||||
// http://xiph.org/ogg/vorbis/doc/framing.html
|
||||
$oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file
|
||||
|
@ -489,7 +536,7 @@ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['
|
|||
return false;
|
||||
}
|
||||
if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) {
|
||||
if ($this->feof() || (($filedata .= $this->fread($this->getid3->fread_buffer_size())) === false)) {
|
||||
if ($this->feof() || (($filedata .= $this->fread($this->getid3->fread_buffer_size())) === '')) {
|
||||
// get some more data, unless eof, in which case fail
|
||||
return false;
|
||||
}
|
||||
|
@ -528,13 +575,19 @@ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['
|
|||
return $oggheader;
|
||||
}
|
||||
|
||||
// http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810005
|
||||
/**
|
||||
* @link http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810005
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ParseVorbisComments() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$OriginalOffset = $this->ftell();
|
||||
$commentdata = null;
|
||||
$commentdataoffset = 0;
|
||||
$VorbisCommentPage = 1;
|
||||
$CommentStartOffset = 0;
|
||||
|
||||
switch ($info['audio']['dataformat']) {
|
||||
case 'vorbis':
|
||||
|
@ -765,6 +818,11 @@ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $mode
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function SpeexBandModeLookup($mode) {
|
||||
static $SpeexBandModeLookup = array();
|
||||
if (empty($SpeexBandModeLookup)) {
|
||||
|
@ -775,8 +833,14 @@ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['
|
|||
return (isset($SpeexBandModeLookup[$mode]) ? $SpeexBandModeLookup[$mode] : null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $OggInfoArray
|
||||
* @param int $SegmentNumber
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function OggPageSegmentLength($OggInfoArray, $SegmentNumber=1) {
|
||||
$segmentlength = 0;
|
||||
for ($i = 0; $i < $SegmentNumber; $i++) {
|
||||
$segmentlength = 0;
|
||||
foreach ($OggInfoArray['segment_table'] as $key => $value) {
|
||||
|
@ -789,7 +853,11 @@ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['
|
|||
return $segmentlength;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $nominal_bitrate
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function get_quality_from_nominal_bitrate($nominal_bitrate) {
|
||||
|
||||
// decrease precision
|
||||
|
@ -813,6 +881,11 @@ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['
|
|||
return round($qval, 1); // 5 or 4.9
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $colorspace_id
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function TheoraColorSpace($colorspace_id) {
|
||||
// http://www.theora.org/doc/Theora.pdf (table 6.3)
|
||||
static $TheoraColorSpaceLookup = array();
|
||||
|
@ -825,6 +898,11 @@ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['
|
|||
return (isset($TheoraColorSpaceLookup[$colorspace_id]) ? $TheoraColorSpaceLookup[$colorspace_id] : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $pixelformat_id
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function TheoraPixelFormat($pixelformat_id) {
|
||||
// http://www.theora.org/doc/Theora.pdf (table 6.4)
|
||||
static $TheoraPixelFormatLookup = array();
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.tag.apetag.php //
|
||||
|
@ -16,9 +16,21 @@
|
|||
|
||||
class getid3_apetag extends getid3_handler
|
||||
{
|
||||
public $inline_attachments = true; // true: return full data for all attachments; false: return no data for all attachments; integer: return data for attachments <= than this; string: save as file to this directory
|
||||
/**
|
||||
* true: return full data for all attachments;
|
||||
* false: return no data for all attachments;
|
||||
* integer: return data for attachments <= than this;
|
||||
* string: save as file to this directory.
|
||||
*
|
||||
* @var int|bool|string
|
||||
*/
|
||||
public $inline_attachments = true;
|
||||
|
||||
public $overrideendoffset = 0;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -150,8 +162,8 @@ class getid3_apetag extends getid3_handler
|
|||
switch (strtolower($item_key)) {
|
||||
// http://wiki.hydrogenaud.io/index.php?title=ReplayGain#MP3Gain
|
||||
case 'replaygain_track_gain':
|
||||
if (preg_match('#^[\\-\\+][0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) {
|
||||
$thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
|
||||
if (preg_match('#^([\\-\\+][0-9\\.,]{8})( dB)?$#', $thisfile_ape_items_current['data'][0], $matches)) {
|
||||
$thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $matches[1]); // float casting will see "0,95" as zero!
|
||||
$thisfile_replaygain['track']['originator'] = 'unspecified';
|
||||
} else {
|
||||
$this->warning('MP3gainTrackGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"');
|
||||
|
@ -159,8 +171,8 @@ class getid3_apetag extends getid3_handler
|
|||
break;
|
||||
|
||||
case 'replaygain_track_peak':
|
||||
if (preg_match('#^[0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) {
|
||||
$thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
|
||||
if (preg_match('#^([0-9\\.,]{8})$#', $thisfile_ape_items_current['data'][0], $matches)) {
|
||||
$thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $matches[1]); // float casting will see "0,95" as zero!
|
||||
$thisfile_replaygain['track']['originator'] = 'unspecified';
|
||||
if ($thisfile_replaygain['track']['peak'] <= 0) {
|
||||
$this->warning('ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")');
|
||||
|
@ -171,8 +183,8 @@ class getid3_apetag extends getid3_handler
|
|||
break;
|
||||
|
||||
case 'replaygain_album_gain':
|
||||
if (preg_match('#^[\\-\\+][0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) {
|
||||
$thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
|
||||
if (preg_match('#^([\\-\\+][0-9\\.,]{8})( dB)?$#', $thisfile_ape_items_current['data'][0], $matches)) {
|
||||
$thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $matches[1]); // float casting will see "0,95" as zero!
|
||||
$thisfile_replaygain['album']['originator'] = 'unspecified';
|
||||
} else {
|
||||
$this->warning('MP3gainAlbumGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"');
|
||||
|
@ -180,8 +192,8 @@ class getid3_apetag extends getid3_handler
|
|||
break;
|
||||
|
||||
case 'replaygain_album_peak':
|
||||
if (preg_match('#^[0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) {
|
||||
$thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
|
||||
if (preg_match('#^([0-9\\.,]{8})$#', $thisfile_ape_items_current['data'][0], $matches)) {
|
||||
$thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $matches[1]); // float casting will see "0,95" as zero!
|
||||
$thisfile_replaygain['album']['originator'] = 'unspecified';
|
||||
if ($thisfile_replaygain['album']['peak'] <= 0) {
|
||||
$this->warning('ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")');
|
||||
|
@ -225,7 +237,7 @@ class getid3_apetag extends getid3_handler
|
|||
case 'tracknumber':
|
||||
if (is_array($thisfile_ape_items_current['data'])) {
|
||||
foreach ($thisfile_ape_items_current['data'] as $comment) {
|
||||
$thisfile_ape['comments']['track'][] = $comment;
|
||||
$thisfile_ape['comments']['track_number'][] = $comment;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -335,6 +347,11 @@ class getid3_apetag extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $APEheaderFooterData
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public function parseAPEheaderFooter($APEheaderFooterData) {
|
||||
// http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html
|
||||
|
||||
|
@ -359,6 +376,11 @@ class getid3_apetag extends getid3_handler
|
|||
return $headerfooterinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $rawflagint
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function parseAPEtagFlags($rawflagint) {
|
||||
// "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."
|
||||
|
@ -374,6 +396,11 @@ class getid3_apetag extends getid3_handler
|
|||
return $flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $contenttypeid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function APEcontentTypeFlagLookup($contenttypeid) {
|
||||
static $APEcontentTypeFlagLookup = array(
|
||||
0 => 'utf-8',
|
||||
|
@ -384,6 +411,11 @@ class getid3_apetag extends getid3_handler
|
|||
return (isset($APEcontentTypeFlagLookup[$contenttypeid]) ? $APEcontentTypeFlagLookup[$contenttypeid] : 'invalid');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $itemkey
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function APEtagItemIsUTF8Lookup($itemkey) {
|
||||
static $APEtagItemIsUTF8Lookup = array(
|
||||
'title',
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.tag.id3v1.php //
|
||||
|
@ -17,7 +17,9 @@
|
|||
|
||||
class getid3_id3v1 extends getid3_handler
|
||||
{
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -43,8 +45,8 @@ class getid3_id3v1 extends getid3_handler
|
|||
|
||||
// If second-last byte of comment field is null and last byte of comment field is non-null
|
||||
// then this is ID3v1.1 and the comment field is 28 bytes long and the 30th byte is the track number
|
||||
if (($id3v1tag{125} === "\x00") && ($id3v1tag{126} !== "\x00")) {
|
||||
$ParsedID3v1['track'] = ord(substr($ParsedID3v1['comment'], 29, 1));
|
||||
if (($id3v1tag[125] === "\x00") && ($id3v1tag[126] !== "\x00")) {
|
||||
$ParsedID3v1['track_number'] = ord(substr($ParsedID3v1['comment'], 29, 1));
|
||||
$ParsedID3v1['comment'] = substr($ParsedID3v1['comment'], 0, 28);
|
||||
}
|
||||
$ParsedID3v1['comment'] = $this->cutfield($ParsedID3v1['comment']);
|
||||
|
@ -66,7 +68,7 @@ class getid3_id3v1 extends getid3_handler
|
|||
$ID3v1encoding = 'ISO-8859-1';
|
||||
foreach ($ParsedID3v1['comments'] as $tag_key => $valuearray) {
|
||||
foreach ($valuearray as $key => $value) {
|
||||
if (preg_match('#^[\\x00-\\x40\\xA8\\B8\\x80-\\xFF]+$#', $value)) {
|
||||
if (preg_match('#^[\\x00-\\x40\\xA8\\xB8\\x80-\\xFF]+$#', $value)) {
|
||||
foreach (array('Windows-1251', 'KOI8-R') as $id3v1_bad_encoding) {
|
||||
if (function_exists('mb_convert_encoding') && @mb_convert_encoding($value, $id3v1_bad_encoding, $id3v1_bad_encoding) === $value) {
|
||||
$ID3v1encoding = $id3v1_bad_encoding;
|
||||
|
@ -89,7 +91,7 @@ class getid3_id3v1 extends getid3_handler
|
|||
$ParsedID3v1['year'],
|
||||
(isset($ParsedID3v1['genre']) ? $this->LookupGenreID($ParsedID3v1['genre']) : false),
|
||||
$ParsedID3v1['comment'],
|
||||
(!empty($ParsedID3v1['track']) ? $ParsedID3v1['track'] : ''));
|
||||
(!empty($ParsedID3v1['track_number']) ? $ParsedID3v1['track_number'] : ''));
|
||||
$ParsedID3v1['padding_valid'] = true;
|
||||
if ($id3v1tag !== $GoodFormatID3v1tag) {
|
||||
$ParsedID3v1['padding_valid'] = false;
|
||||
|
@ -124,10 +126,20 @@ class getid3_id3v1 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function cutfield($str) {
|
||||
return trim(substr($str, 0, strcspn($str, "\x00")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $allowSCMPXextended
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function ArrayOfGenres($allowSCMPXextended=false) {
|
||||
static $GenreLookup = array(
|
||||
0 => 'Blues',
|
||||
|
@ -312,6 +324,12 @@ class getid3_id3v1 extends getid3_handler
|
|||
return ($allowSCMPXextended ? $GenreLookupSCMPX : $GenreLookup);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $genreid
|
||||
* @param bool $allowSCMPXextended
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function LookupGenreName($genreid, $allowSCMPXextended=true) {
|
||||
switch ($genreid) {
|
||||
case 'RX':
|
||||
|
@ -328,6 +346,12 @@ class getid3_id3v1 extends getid3_handler
|
|||
return (isset($GenreLookup[$genreid]) ? $GenreLookup[$genreid] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $genre
|
||||
* @param bool $allowSCMPXextended
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function LookupGenreID($genre, $allowSCMPXextended=false) {
|
||||
$GenreLookup = self::ArrayOfGenres($allowSCMPXextended);
|
||||
$LowerCaseNoSpaceSearchTerm = strtolower(str_replace(' ', '', $genre));
|
||||
|
@ -339,6 +363,11 @@ class getid3_id3v1 extends getid3_handler
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $OriginalGenre
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function StandardiseID3v1GenreName($OriginalGenre) {
|
||||
if (($GenreID = self::LookupGenreID($OriginalGenre)) !== false) {
|
||||
return self::LookupGenreName($GenreID);
|
||||
|
@ -346,6 +375,17 @@ class getid3_id3v1 extends getid3_handler
|
|||
return $OriginalGenre;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $title
|
||||
* @param string $artist
|
||||
* @param string $album
|
||||
* @param string $year
|
||||
* @param int $genreid
|
||||
* @param string $comment
|
||||
* @param int|string $track
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function GenerateID3v1Tag($title, $artist, $album, $year, $genreid, $comment, $track='') {
|
||||
$ID3v1Tag = 'TAG';
|
||||
$ID3v1Tag .= str_pad(trim(substr($title, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// //
|
||||
// module.tag.id3v2.php //
|
||||
|
@ -20,6 +20,9 @@ class getid3_id3v2 extends getid3_handler
|
|||
{
|
||||
public $StartingOffset = 0;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -56,8 +59,8 @@ class getid3_id3v2 extends getid3_handler
|
|||
$header = $this->fread(10);
|
||||
if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) {
|
||||
|
||||
$thisfile_id3v2['majorversion'] = ord($header{3});
|
||||
$thisfile_id3v2['minorversion'] = ord($header{4});
|
||||
$thisfile_id3v2['majorversion'] = ord($header[3]);
|
||||
$thisfile_id3v2['minorversion'] = ord($header[4]);
|
||||
|
||||
// shortcut
|
||||
$id3v2_majorversion = &$thisfile_id3v2['majorversion'];
|
||||
|
@ -76,7 +79,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
|
||||
}
|
||||
|
||||
$id3_flags = ord($header{5});
|
||||
$id3_flags = ord($header[5]);
|
||||
switch ($id3v2_majorversion) {
|
||||
case 2:
|
||||
// %ab000000 in v2.2
|
||||
|
@ -257,7 +260,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
$thisfile_id3v2['padding']['length'] = strlen($framedata);
|
||||
$thisfile_id3v2['padding']['valid'] = true;
|
||||
for ($i = 0; $i < $thisfile_id3v2['padding']['length']; $i++) {
|
||||
if ($framedata{$i} != "\x00") {
|
||||
if ($framedata[$i] != "\x00") {
|
||||
$thisfile_id3v2['padding']['valid'] = false;
|
||||
$thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
|
||||
$this->warning('Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)');
|
||||
|
@ -266,6 +269,10 @@ class getid3_id3v2 extends getid3_handler
|
|||
}
|
||||
break; // skip rest of ID3v2 header
|
||||
}
|
||||
$frame_header = null;
|
||||
$frame_name = null;
|
||||
$frame_size = null;
|
||||
$frame_flags = null;
|
||||
if ($id3v2_majorversion == 2) {
|
||||
// Frame ID $xx xx xx (three characters)
|
||||
// Size $xx xx xx (24-bit integer)
|
||||
|
@ -319,7 +326,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
|
||||
$len = strlen($framedata);
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
if ($framedata{$i} != "\x00") {
|
||||
if ($framedata[$i] != "\x00") {
|
||||
$thisfile_id3v2['padding']['valid'] = false;
|
||||
$thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
|
||||
$this->warning('Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)');
|
||||
|
@ -427,11 +434,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
$footer = $this->fread(10);
|
||||
if (substr($footer, 0, 3) == '3DI') {
|
||||
$thisfile_id3v2['footer'] = true;
|
||||
$thisfile_id3v2['majorversion_footer'] = ord($footer{3});
|
||||
$thisfile_id3v2['minorversion_footer'] = ord($footer{4});
|
||||
$thisfile_id3v2['majorversion_footer'] = ord($footer[3]);
|
||||
$thisfile_id3v2['minorversion_footer'] = ord($footer[4]);
|
||||
}
|
||||
if ($thisfile_id3v2['majorversion_footer'] <= 4) {
|
||||
$id3_flags = ord(substr($footer{5}));
|
||||
$id3_flags = ord($footer[5]);
|
||||
$thisfile_id3v2_flags['unsynch_footer'] = (bool) ($id3_flags & 0x80);
|
||||
$thisfile_id3v2_flags['extfoot_footer'] = (bool) ($id3_flags & 0x40);
|
||||
$thisfile_id3v2_flags['experim_footer'] = (bool) ($id3_flags & 0x20);
|
||||
|
@ -452,10 +459,10 @@ class getid3_id3v2 extends getid3_handler
|
|||
unset($key, $value, $genres, $genre);
|
||||
}
|
||||
|
||||
if (isset($thisfile_id3v2['comments']['track'])) {
|
||||
foreach ($thisfile_id3v2['comments']['track'] as $key => $value) {
|
||||
if (isset($thisfile_id3v2['comments']['track_number'])) {
|
||||
foreach ($thisfile_id3v2['comments']['track_number'] as $key => $value) {
|
||||
if (strstr($value, '/')) {
|
||||
list($thisfile_id3v2['comments']['tracknum'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track'][$key]);
|
||||
list($thisfile_id3v2['comments']['track_number'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track_number'][$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -498,7 +505,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $genrestring
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function ParseID3v2GenreString($genrestring) {
|
||||
// Parse genres into arrays of genreName and genreID
|
||||
// ID3v2.2.x, ID3v2.3.x: '(21)' or '(4)Eurodisco' or '(51)(39)' or '(55)((I think...)'
|
||||
|
@ -530,7 +541,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
foreach ($genre_elements as $element) {
|
||||
$element = trim($element);
|
||||
if ($element) {
|
||||
if (preg_match('#^[0-9]{1,3}#', $element)) {
|
||||
if (preg_match('#^[0-9]{1,3}$#', $element)) {
|
||||
$clean_genres[] = getid3_id3v1::LookupGenreName($element);
|
||||
} else {
|
||||
$clean_genres[] = str_replace('((', '(', $element);
|
||||
|
@ -540,7 +551,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
return $clean_genres;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $parsedFrame
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ParseID3v2Frame(&$parsedFrame) {
|
||||
|
||||
// shortcuts
|
||||
|
@ -657,16 +672,14 @@ class getid3_id3v2 extends getid3_handler
|
|||
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
|
||||
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
|
||||
}
|
||||
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
|
||||
if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
|
||||
// if description only contains a BOM or terminator then make it blank
|
||||
$frame_description = '';
|
||||
}
|
||||
$parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
|
||||
$parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
|
||||
$parsedFrame['encodingid'] = $frame_textencoding;
|
||||
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
|
||||
|
||||
$parsedFrame['description'] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $frame_description));
|
||||
$parsedFrame['description'] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['description']));
|
||||
$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
|
||||
$parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $frame_textencoding_terminator);
|
||||
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
|
||||
$commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0));
|
||||
if (!isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) || !array_key_exists($commentkey, $info['id3v2']['comments'][$parsedFrame['framenameshort']])) {
|
||||
|
@ -678,7 +691,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
//unset($parsedFrame['data']); do not unset, may be needed elsewhere, e.g. for replaygain
|
||||
|
||||
|
||||
} elseif ($parsedFrame['frame_name']{0} == 'T') { // 4.2. T??[?] Text information frame
|
||||
} elseif ($parsedFrame['frame_name'][0] == 'T') { // 4.2. T??[?] Text information frame
|
||||
// There may only be one text information frame of its kind in an tag.
|
||||
// <Header for 'Text information frame', ID: 'T000' - 'TZZZ',
|
||||
// excluding 'TXXX' described in 4.2.6.>
|
||||
|
@ -692,10 +705,10 @@ class getid3_id3v2 extends getid3_handler
|
|||
}
|
||||
|
||||
$parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
|
||||
$parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding));
|
||||
|
||||
$parsedFrame['encodingid'] = $frame_textencoding;
|
||||
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
|
||||
|
||||
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
|
||||
// ID3v2.3 specs say that TPE1 (and others) can contain multiple artist values separated with /
|
||||
// This of course breaks when an artist name contains slash character, e.g. "AC/DC"
|
||||
|
@ -751,47 +764,29 @@ class getid3_id3v2 extends getid3_handler
|
|||
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
|
||||
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
|
||||
}
|
||||
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
|
||||
if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
|
||||
// if description only contains a BOM or terminator then make it blank
|
||||
$frame_description = '';
|
||||
}
|
||||
$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
|
||||
|
||||
$frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator);
|
||||
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
|
||||
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
|
||||
}
|
||||
if ($frame_terminatorpos) {
|
||||
// there are null bytes after the data - this is not according to spec
|
||||
// only use data up to first null byte
|
||||
$frame_urldata = (string) substr($parsedFrame['data'], 0, $frame_terminatorpos);
|
||||
} else {
|
||||
// no null bytes following data, just use all data
|
||||
$frame_urldata = (string) $parsedFrame['data'];
|
||||
}
|
||||
|
||||
$parsedFrame['encodingid'] = $frame_textencoding;
|
||||
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
|
||||
$parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); // according to the frame text encoding
|
||||
$parsedFrame['url'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator)); // always ISO-8859-1
|
||||
$parsedFrame['description'] = $this->RemoveStringTerminator($parsedFrame['description'], $frame_textencoding_terminator);
|
||||
$parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
|
||||
|
||||
$parsedFrame['url'] = $frame_urldata;
|
||||
$parsedFrame['description'] = $frame_description;
|
||||
if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
|
||||
$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['url']);
|
||||
$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback('ISO-8859-1', $info['id3v2']['encoding'], $parsedFrame['url']);
|
||||
}
|
||||
unset($parsedFrame['data']);
|
||||
|
||||
|
||||
} elseif ($parsedFrame['frame_name']{0} == 'W') { // 4.3. W??? URL link frames
|
||||
} elseif ($parsedFrame['frame_name'][0] == 'W') { // 4.3. W??? URL link frames
|
||||
// There may only be one URL link frame of its kind in a tag,
|
||||
// except when stated otherwise in the frame description
|
||||
// <Header for 'URL link frame', ID: 'W000' - 'WZZZ', excluding 'WXXX'
|
||||
// described in 4.3.2.>
|
||||
// URL <text string>
|
||||
|
||||
$parsedFrame['url'] = trim($parsedFrame['data']);
|
||||
$parsedFrame['url'] = trim($parsedFrame['data']); // always ISO-8859-1
|
||||
if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
|
||||
$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['url'];
|
||||
$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback('ISO-8859-1', $info['id3v2']['encoding'], $parsedFrame['url']);
|
||||
}
|
||||
unset($parsedFrame['data']);
|
||||
|
||||
|
@ -813,7 +808,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($parsedFrame['encodingid']);
|
||||
$parsedFrame['data_raw'] = (string) substr($parsedFrame['data'], $frame_offset);
|
||||
|
||||
// http://www.getid3.org/phpBB3/viewtopic.php?t=1369
|
||||
// https://www.getid3.org/phpBB3/viewtopic.php?t=1369
|
||||
// "this tag typically contains null terminated strings, which are associated in pairs"
|
||||
// "there are users that use the tag incorrectly"
|
||||
$IPLS_parts = array();
|
||||
|
@ -933,6 +928,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
$parsedFrame['bitsforbytesdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 8, 1));
|
||||
$parsedFrame['bitsformsdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 9, 1));
|
||||
$parsedFrame['data'] = substr($parsedFrame['data'], 10);
|
||||
$deviationbitstream = '';
|
||||
while ($frame_offset < strlen($parsedFrame['data'])) {
|
||||
$deviationbitstream .= getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
|
||||
}
|
||||
|
@ -994,19 +990,16 @@ class getid3_id3v2 extends getid3_handler
|
|||
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
|
||||
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
|
||||
}
|
||||
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
|
||||
if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
|
||||
// if description only contains a BOM or terminator then make it blank
|
||||
$frame_description = '';
|
||||
}
|
||||
$parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
|
||||
$parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
|
||||
$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
|
||||
$parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $frame_textencoding_terminator);
|
||||
|
||||
$parsedFrame['encodingid'] = $frame_textencoding;
|
||||
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
|
||||
|
||||
$parsedFrame['language'] = $frame_language;
|
||||
$parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
|
||||
$parsedFrame['description'] = $frame_description;
|
||||
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
|
||||
$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
|
||||
}
|
||||
|
@ -1061,7 +1054,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
$parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset);
|
||||
|
||||
$frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($frame_textencoding_terminator));
|
||||
if (($timestampindex == 0) && (ord($frame_remainingdata{0}) != 0)) {
|
||||
if (($timestampindex == 0) && (ord($frame_remainingdata[0]) != 0)) {
|
||||
// timestamp probably omitted for first data item
|
||||
} else {
|
||||
$parsedFrame['lyrics'][$timestampindex]['timestamp'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 4));
|
||||
|
@ -1102,19 +1095,16 @@ class getid3_id3v2 extends getid3_handler
|
|||
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
|
||||
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
|
||||
}
|
||||
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
|
||||
if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
|
||||
// if description only contains a BOM or terminator then make it blank
|
||||
$frame_description = '';
|
||||
}
|
||||
$parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
|
||||
$parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
|
||||
$frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
|
||||
$frame_text = $this->RemoveStringTerminator($frame_text, $frame_textencoding_terminator);
|
||||
|
||||
$parsedFrame['encodingid'] = $frame_textencoding;
|
||||
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
|
||||
|
||||
$parsedFrame['language'] = $frame_language;
|
||||
$parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
|
||||
$parsedFrame['description'] = $frame_description;
|
||||
$parsedFrame['data'] = $frame_text;
|
||||
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
|
||||
$commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (!empty($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0));
|
||||
|
@ -1407,22 +1397,18 @@ class getid3_id3v2 extends getid3_handler
|
|||
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
|
||||
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
|
||||
}
|
||||
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
|
||||
if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
|
||||
// if description only contains a BOM or terminator then make it blank
|
||||
$frame_description = '';
|
||||
}
|
||||
$parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
|
||||
$parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
|
||||
$parsedFrame['encodingid'] = $frame_textencoding;
|
||||
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
|
||||
|
||||
if ($id3v2_majorversion == 2) {
|
||||
$parsedFrame['imagetype'] = $frame_imagetype;
|
||||
$parsedFrame['imagetype'] = isset($frame_imagetype) ? $frame_imagetype : null;
|
||||
} else {
|
||||
$parsedFrame['mime'] = $frame_mimetype;
|
||||
$parsedFrame['mime'] = isset($frame_mimetype) ? $frame_mimetype : null;
|
||||
}
|
||||
$parsedFrame['picturetypeid'] = $frame_picturetype;
|
||||
$parsedFrame['picturetype'] = $this->APICPictureTypeLookup($frame_picturetype);
|
||||
$parsedFrame['description'] = $frame_description;
|
||||
$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
|
||||
$parsedFrame['datalength'] = strlen($parsedFrame['data']);
|
||||
|
||||
|
@ -1430,7 +1416,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
$imageinfo = array();
|
||||
if ($imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data'], $imageinfo)) {
|
||||
if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
|
||||
$parsedFrame['image_mime'] = 'image/'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]);
|
||||
$parsedFrame['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
|
||||
if ($imagechunkcheck[0]) {
|
||||
$parsedFrame['image_width'] = $imagechunkcheck[0];
|
||||
}
|
||||
|
@ -1446,6 +1432,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
unset($parsedFrame['data']);
|
||||
break;
|
||||
}
|
||||
$dir = '';
|
||||
if ($this->getid3->option_save_attachments === true) {
|
||||
// great
|
||||
/*
|
||||
|
@ -1533,11 +1520,8 @@ class getid3_id3v2 extends getid3_handler
|
|||
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
|
||||
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
|
||||
}
|
||||
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
|
||||
if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
|
||||
// if description only contains a BOM or terminator then make it blank
|
||||
$frame_description = '';
|
||||
}
|
||||
$parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
|
||||
$parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
|
||||
$frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
|
||||
|
||||
$parsedFrame['objectdata'] = (string) substr($parsedFrame['data'], $frame_offset);
|
||||
|
@ -1546,7 +1530,6 @@ class getid3_id3v2 extends getid3_handler
|
|||
|
||||
$parsedFrame['mime'] = $frame_mimetype;
|
||||
$parsedFrame['filename'] = $frame_filename;
|
||||
$parsedFrame['description'] = $frame_description;
|
||||
unset($parsedFrame['data']);
|
||||
|
||||
|
||||
|
@ -1616,16 +1599,12 @@ class getid3_id3v2 extends getid3_handler
|
|||
$frame_offset = $frame_terminatorpos + strlen("\x00");
|
||||
|
||||
$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
|
||||
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
|
||||
if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
|
||||
// if description only contains a BOM or terminator then make it blank
|
||||
$frame_description = '';
|
||||
}
|
||||
$parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
|
||||
$parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
|
||||
$frame_offset = $frame_terminatorpos + strlen("\x00");
|
||||
|
||||
$parsedFrame['ownerid'] = $frame_ownerid;
|
||||
$parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
|
||||
$parsedFrame['description'] = $frame_description;
|
||||
unset($parsedFrame['data']);
|
||||
|
||||
|
||||
|
@ -1722,6 +1701,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
|
||||
|
||||
$parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
|
||||
$parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding));
|
||||
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
|
||||
$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
|
||||
}
|
||||
|
@ -1759,6 +1739,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
$frame_offset += 8;
|
||||
|
||||
$parsedFrame['seller'] = (string) substr($parsedFrame['data'], $frame_offset);
|
||||
$parsedFrame['seller'] = $this->RemoveStringTerminator($parsedFrame['seller'], $this->TextEncodingTerminatorLookup($frame_textencoding));
|
||||
unset($parsedFrame['data']);
|
||||
|
||||
|
||||
|
@ -1817,11 +1798,8 @@ class getid3_id3v2 extends getid3_handler
|
|||
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
|
||||
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
|
||||
}
|
||||
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
|
||||
if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
|
||||
// if description only contains a BOM or terminator then make it blank
|
||||
$frame_description = '';
|
||||
}
|
||||
$parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
|
||||
$parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
|
||||
$frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
|
||||
|
||||
$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
|
||||
|
@ -1838,7 +1816,6 @@ class getid3_id3v2 extends getid3_handler
|
|||
$parsedFrame['receivedasid'] = $frame_receivedasid;
|
||||
$parsedFrame['receivedas'] = $this->COMRReceivedAsLookup($frame_receivedasid);
|
||||
$parsedFrame['sellername'] = $frame_sellername;
|
||||
$parsedFrame['description'] = $frame_description;
|
||||
$parsedFrame['mime'] = $frame_mimetype;
|
||||
$parsedFrame['logo'] = $frame_sellerlogo;
|
||||
unset($parsedFrame['data']);
|
||||
|
@ -2045,7 +2022,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
$subframe['encodingid'] = ord(substr($subframe_rawdata, 0, 1));
|
||||
$subframe['text'] = substr($subframe_rawdata, 1);
|
||||
$subframe['encoding'] = $this->TextEncodingNameLookup($subframe['encodingid']);
|
||||
$encoding_converted_text = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe['text']));;
|
||||
$encoding_converted_text = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe['text']));
|
||||
switch (substr($encoding_converted_text, 0, 2)) {
|
||||
case "\xFF\xFE":
|
||||
case "\xFE\xFF":
|
||||
|
@ -2065,22 +2042,51 @@ class getid3_id3v2 extends getid3_handler
|
|||
break;
|
||||
}
|
||||
|
||||
if (($subframe['name'] == 'TIT2') || ($subframe['name'] == 'TIT3')) {
|
||||
if ($subframe['name'] == 'TIT2') {
|
||||
switch ($subframe['name']) {
|
||||
case 'TIT2':
|
||||
$parsedFrame['chapter_name'] = $encoding_converted_text;
|
||||
} elseif ($subframe['name'] == 'TIT3') {
|
||||
$parsedFrame['chapter_description'] = $encoding_converted_text;
|
||||
}
|
||||
$parsedFrame['subframes'][] = $subframe;
|
||||
break;
|
||||
case 'TIT3':
|
||||
$parsedFrame['chapter_description'] = $encoding_converted_text;
|
||||
$parsedFrame['subframes'][] = $subframe;
|
||||
break;
|
||||
case 'WXXX':
|
||||
list($subframe['chapter_url_description'], $subframe['chapter_url']) = explode("\x00", $encoding_converted_text, 2);
|
||||
$parsedFrame['chapter_url'][$subframe['chapter_url_description']] = $subframe['chapter_url'];
|
||||
$parsedFrame['subframes'][] = $subframe;
|
||||
break;
|
||||
case 'APIC':
|
||||
if (preg_match('#^([^\\x00]+)*\\x00(.)([^\\x00]+)*\\x00(.+)$#s', $subframe['text'], $matches)) {
|
||||
list($dummy, $subframe_apic_mime, $subframe_apic_picturetype, $subframe_apic_description, $subframe_apic_picturedata) = $matches;
|
||||
$subframe['image_mime'] = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe_apic_mime));
|
||||
$subframe['picture_type'] = $this->APICPictureTypeLookup($subframe_apic_picturetype);
|
||||
$subframe['description'] = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe_apic_description));
|
||||
if (strlen($this->TextEncodingTerminatorLookup($subframe['encoding'])) == 2) {
|
||||
// the null terminator between "description" and "picture data" could be either 1 byte (ISO-8859-1, UTF-8) or two bytes (UTF-16)
|
||||
// the above regex assumes one byte, if it's actually two then strip the second one here
|
||||
$subframe_apic_picturedata = substr($subframe_apic_picturedata, 1);
|
||||
}
|
||||
$subframe['data'] = $subframe_apic_picturedata;
|
||||
unset($dummy, $subframe_apic_mime, $subframe_apic_picturetype, $subframe_apic_description, $subframe_apic_picturedata);
|
||||
unset($subframe['text'], $parsedFrame['text']);
|
||||
$parsedFrame['subframes'][] = $subframe;
|
||||
$parsedFrame['picture_present'] = true;
|
||||
} else {
|
||||
$this->warning('ID3v2.CHAP subframe "'.$subframe['name'].'" not handled (only TIT2 and TIT3)');
|
||||
$this->warning('ID3v2.CHAP subframe #'.(count($parsedFrame['subframes']) + 1).' "'.$subframe['name'].'" not in expected format');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$this->warning('ID3v2.CHAP subframe "'.$subframe['name'].'" not handled (supported: TIT2, TIT3, WXXX, APIC)');
|
||||
break;
|
||||
}
|
||||
}
|
||||
unset($subframe_rawdata, $subframe, $encoding_converted_text);
|
||||
unset($parsedFrame['data']); // debatable whether this this be here, without it the returned structure may contain a large amount of duplicate data if chapters contain APIC
|
||||
}
|
||||
|
||||
$id3v2_chapter_entry = array();
|
||||
foreach (array('id', 'time_begin', 'time_end', 'offset_begin', 'offset_end', 'chapter_name', 'chapter_description') as $id3v2_chapter_key) {
|
||||
foreach (array('id', 'time_begin', 'time_end', 'offset_begin', 'offset_end', 'chapter_name', 'chapter_description', 'chapter_url', 'picture_present') as $id3v2_chapter_key) {
|
||||
if (isset($parsedFrame[$id3v2_chapter_key])) {
|
||||
$id3v2_chapter_entry[$id3v2_chapter_key] = $parsedFrame[$id3v2_chapter_key];
|
||||
}
|
||||
|
@ -2181,11 +2187,20 @@ class getid3_id3v2 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function DeUnsynchronise($data) {
|
||||
return str_replace("\xFF\x00", "\xFF", $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function LookupExtendedHeaderRestrictionsTagSizeLimits($index) {
|
||||
static $LookupExtendedHeaderRestrictionsTagSizeLimits = array(
|
||||
0x00 => 'No more than 128 frames and 1 MB total tag size',
|
||||
|
@ -2196,6 +2211,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
return (isset($LookupExtendedHeaderRestrictionsTagSizeLimits[$index]) ? $LookupExtendedHeaderRestrictionsTagSizeLimits[$index] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function LookupExtendedHeaderRestrictionsTextEncodings($index) {
|
||||
static $LookupExtendedHeaderRestrictionsTextEncodings = array(
|
||||
0x00 => 'No restrictions',
|
||||
|
@ -2204,6 +2224,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
return (isset($LookupExtendedHeaderRestrictionsTextEncodings[$index]) ? $LookupExtendedHeaderRestrictionsTextEncodings[$index] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function LookupExtendedHeaderRestrictionsTextFieldSize($index) {
|
||||
static $LookupExtendedHeaderRestrictionsTextFieldSize = array(
|
||||
0x00 => 'No restrictions',
|
||||
|
@ -2214,6 +2239,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
return (isset($LookupExtendedHeaderRestrictionsTextFieldSize[$index]) ? $LookupExtendedHeaderRestrictionsTextFieldSize[$index] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function LookupExtendedHeaderRestrictionsImageEncoding($index) {
|
||||
static $LookupExtendedHeaderRestrictionsImageEncoding = array(
|
||||
0x00 => 'No restrictions',
|
||||
|
@ -2222,6 +2252,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
return (isset($LookupExtendedHeaderRestrictionsImageEncoding[$index]) ? $LookupExtendedHeaderRestrictionsImageEncoding[$index] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function LookupExtendedHeaderRestrictionsImageSizeSize($index) {
|
||||
static $LookupExtendedHeaderRestrictionsImageSizeSize = array(
|
||||
0x00 => 'No restrictions',
|
||||
|
@ -2232,6 +2267,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
return (isset($LookupExtendedHeaderRestrictionsImageSizeSize[$index]) ? $LookupExtendedHeaderRestrictionsImageSizeSize[$index] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $currencyid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function LookupCurrencyUnits($currencyid) {
|
||||
|
||||
$begin = __LINE__;
|
||||
|
@ -2428,7 +2468,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-units');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $currencyid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function LookupCurrencyCountry($currencyid) {
|
||||
|
||||
$begin = __LINE__;
|
||||
|
@ -2624,8 +2668,12 @@ class getid3_id3v2 extends getid3_handler
|
|||
return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-country');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string $languagecode
|
||||
* @param bool $casesensitive
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function LanguageLookup($languagecode, $casesensitive=false) {
|
||||
|
||||
if (!$casesensitive) {
|
||||
|
@ -3081,7 +3129,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
return getid3_lib::EmbeddedLookup($languagecode, $begin, __LINE__, __FILE__, 'id3v2-languagecode');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function ETCOEventLookup($index) {
|
||||
if (($index >= 0x17) && ($index <= 0xDF)) {
|
||||
return 'reserved for future use';
|
||||
|
@ -3125,6 +3177,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
return (isset($EventLookup[$index]) ? $EventLookup[$index] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function SYTLContentTypeLookup($index) {
|
||||
static $SYTLContentTypeLookup = array(
|
||||
0x00 => 'other',
|
||||
|
@ -3141,6 +3198,12 @@ class getid3_id3v2 extends getid3_handler
|
|||
return (isset($SYTLContentTypeLookup[$index]) ? $SYTLContentTypeLookup[$index] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
* @param bool $returnarray
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
public static function APICPictureTypeLookup($index, $returnarray=false) {
|
||||
static $APICPictureTypeLookup = array(
|
||||
0x00 => 'Other',
|
||||
|
@ -3171,6 +3234,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
return (isset($APICPictureTypeLookup[$index]) ? $APICPictureTypeLookup[$index] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function COMRReceivedAsLookup($index) {
|
||||
static $COMRReceivedAsLookup = array(
|
||||
0x00 => 'Other',
|
||||
|
@ -3187,6 +3255,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
return (isset($COMRReceivedAsLookup[$index]) ? $COMRReceivedAsLookup[$index] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function RVA2ChannelTypeLookup($index) {
|
||||
static $RVA2ChannelTypeLookup = array(
|
||||
0x00 => 'Other',
|
||||
|
@ -3203,6 +3276,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
return (isset($RVA2ChannelTypeLookup[$index]) ? $RVA2ChannelTypeLookup[$index] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $framename
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function FrameNameLongLookup($framename) {
|
||||
|
||||
$begin = __LINE__;
|
||||
|
@ -3354,7 +3432,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
TYER Year
|
||||
UFI Unique file identifier
|
||||
UFID Unique file identifier
|
||||
ULT Unsychronised lyric/text transcription
|
||||
ULT Unsynchronised lyric/text transcription
|
||||
USER Terms of use
|
||||
USLT Unsynchronised lyric/text transcription
|
||||
WAF Official audio file webpage
|
||||
|
@ -3386,7 +3464,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
// from http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $framename
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function FrameNameShortLookup($framename) {
|
||||
|
||||
$begin = __LINE__;
|
||||
|
@ -3538,7 +3620,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
TYER year
|
||||
UFI unique_file_identifier
|
||||
UFID unique_file_identifier
|
||||
ULT unsychronised_lyric
|
||||
ULT unsynchronised_lyric
|
||||
USER terms_of_use
|
||||
USLT unsynchronised_lyric
|
||||
WAF url_file
|
||||
|
@ -3566,6 +3648,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_short');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoding
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function TextEncodingTerminatorLookup($encoding) {
|
||||
// http://www.id3.org/id3v2.4.0-structure.txt
|
||||
// Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings:
|
||||
|
@ -3579,6 +3666,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
return (isset($TextEncodingTerminatorLookup[$encoding]) ? $TextEncodingTerminatorLookup[$encoding] : "\x00");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $encoding
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function TextEncodingNameLookup($encoding) {
|
||||
// http://www.id3.org/id3v2.4.0-structure.txt
|
||||
// Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings:
|
||||
|
@ -3592,6 +3684,41 @@ class getid3_id3v2 extends getid3_handler
|
|||
return (isset($TextEncodingNameLookup[$encoding]) ? $TextEncodingNameLookup[$encoding] : 'ISO-8859-1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
* @param string $terminator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function RemoveStringTerminator($string, $terminator) {
|
||||
// Null terminator at end of comment string is somewhat ambiguous in the specification, may or may not be implemented by various taggers. Remove terminator only if present.
|
||||
// https://github.com/JamesHeinrich/getID3/issues/121
|
||||
// https://community.mp3tag.de/t/x-trailing-nulls-in-id3v2-comments/19227
|
||||
if (substr($string, -strlen($terminator), strlen($terminator)) === $terminator) {
|
||||
$string = substr($string, 0, -strlen($terminator));
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function MakeUTF16emptyStringEmpty($string) {
|
||||
if (in_array($string, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
|
||||
// if string only contains a BOM or terminator then make it actually an empty string
|
||||
$string = '';
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $framename
|
||||
* @param int $id3v2majorversion
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
public static function IsValidID3v2FrameName($framename, $id3v2majorversion) {
|
||||
switch ($id3v2majorversion) {
|
||||
case 2:
|
||||
|
@ -3606,12 +3733,19 @@ class getid3_id3v2 extends getid3_handler
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $numberstring
|
||||
* @param bool $allowdecimal
|
||||
* @param bool $allownegative
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function IsANumber($numberstring, $allowdecimal=false, $allownegative=false) {
|
||||
for ($i = 0; $i < strlen($numberstring); $i++) {
|
||||
if ((chr($numberstring{$i}) < chr('0')) || (chr($numberstring{$i}) > chr('9'))) {
|
||||
if (($numberstring{$i} == '.') && $allowdecimal) {
|
||||
if ((chr($numberstring[$i]) < chr('0')) || (chr($numberstring[$i]) > chr('9'))) {
|
||||
if (($numberstring[$i] == '.') && $allowdecimal) {
|
||||
// allowed
|
||||
} elseif (($numberstring{$i} == '-') && $allownegative && ($i == 0)) {
|
||||
} elseif (($numberstring[$i] == '-') && $allownegative && ($i == 0)) {
|
||||
// allowed
|
||||
} else {
|
||||
return false;
|
||||
|
@ -3621,6 +3755,11 @@ class getid3_id3v2 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $datestamp
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function IsValidDateStampString($datestamp) {
|
||||
if (strlen($datestamp) != 8) {
|
||||
return false;
|
||||
|
@ -3649,10 +3788,20 @@ class getid3_id3v2 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $majorversion
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function ID3v2HeaderLength($majorversion) {
|
||||
return (($majorversion == 2) ? 6 : 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $frame_name
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function ID3v22iTunesBrokenFrameName($frame_name) {
|
||||
// iTunes (multiple versions) has been known to write ID3v2.3 style frames
|
||||
// but use ID3v2.2 frame names, right-padded using either [space] or [null]
|
||||
|
@ -3739,3 +3888,4 @@ class getid3_id3v2 extends getid3_handler
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// //
|
||||
// module.tag.lyrics3.php //
|
||||
|
@ -17,7 +17,9 @@
|
|||
|
||||
class getid3_lyrics3 extends getid3_handler
|
||||
{
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -61,7 +63,7 @@ class getid3_lyrics3 extends getid3_handler
|
|||
|
||||
// Lyrics3v2, no ID3v1, no APE
|
||||
|
||||
$lyrics3size = strrev(substr(strrev($lyrics3_id3v1), 9, 6)) + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
|
||||
$lyrics3size = (int) strrev(substr(strrev($lyrics3_id3v1), 9, 6)) + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
|
||||
$lyrics3offset = $info['filesize'] - $lyrics3size;
|
||||
$lyrics3version = 2;
|
||||
|
||||
|
@ -96,7 +98,7 @@ class getid3_lyrics3 extends getid3_handler
|
|||
|
||||
}
|
||||
|
||||
if (isset($lyrics3offset)) {
|
||||
if (isset($lyrics3offset) && isset($lyrics3version) && isset($lyrics3size)) {
|
||||
$info['avdataend'] = $lyrics3offset;
|
||||
$this->getLyrics3Data($lyrics3offset, $lyrics3version, $lyrics3size);
|
||||
|
||||
|
@ -126,6 +128,13 @@ class getid3_lyrics3 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $endoffset
|
||||
* @param int $version
|
||||
* @param int $length
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getLyrics3Data($endoffset, $version, $length) {
|
||||
// http://www.volweb.cz/str/tags.htm
|
||||
|
||||
|
@ -142,6 +151,8 @@ class getid3_lyrics3 extends getid3_handler
|
|||
}
|
||||
$rawdata = $this->fread($length);
|
||||
|
||||
$ParsedLyrics3 = array();
|
||||
|
||||
$ParsedLyrics3['raw']['lyrics3version'] = $version;
|
||||
$ParsedLyrics3['raw']['lyrics3tagsize'] = $length;
|
||||
$ParsedLyrics3['tag_offset_start'] = $endoffset;
|
||||
|
@ -250,6 +261,11 @@ class getid3_lyrics3 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $rawtimestamp
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public function Lyrics3Timestamp2Seconds($rawtimestamp) {
|
||||
if (preg_match('#^\\[([0-9]{2}):([0-9]{2})\\]$#', $rawtimestamp, $regs)) {
|
||||
return (int) (($regs[1] * 60) + $regs[2]);
|
||||
|
@ -257,8 +273,14 @@ class getid3_lyrics3 extends getid3_handler
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $Lyrics3data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function Lyrics3LyricsTimestampParse(&$Lyrics3data) {
|
||||
$lyricsarray = explode("\r\n", $Lyrics3data['raw']['LYR']);
|
||||
$notimestamplyricsarray = array();
|
||||
foreach ($lyricsarray as $key => $lyricline) {
|
||||
$regs = array();
|
||||
unset($thislinetimestamps);
|
||||
|
@ -287,6 +309,11 @@ class getid3_lyrics3 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $char
|
||||
*
|
||||
* @return bool|null
|
||||
*/
|
||||
public function IntString2Bool($char) {
|
||||
if ($char == '1') {
|
||||
return true;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// or https://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -18,9 +18,9 @@ GNU GPL: https://gnu.org/licenses/gpl.html (v3)
|
|||
|
||||
GNU LGPL: https://gnu.org/licenses/lgpl.html (v3)
|
||||
|
||||
Mozilla MPL: http://www.mozilla.org/MPL/2.0/ (v2)
|
||||
Mozilla MPL: https://www.mozilla.org/MPL/2.0/ (v2)
|
||||
|
||||
getID3 Commercial License: http://getid3.org/#gCL (payment required)
|
||||
getID3 Commercial License: https://www.getid3.org/#gCL (payment required)
|
||||
|
||||
*****************************************************************
|
||||
*****************************************************************
|
||||
|
@ -28,10 +28,10 @@ Copies of each of the above licenses are included in the 'licenses'
|
|||
directory of the getID3 distribution.
|
||||
|
||||
|
||||
+---------------------------------------------+
|
||||
+----------------------------------------------+
|
||||
| If you want to donate, there is a link on |
|
||||
| http://www.getid3.org for PayPal donations. |
|
||||
+---------------------------------------------+
|
||||
| https://www.getid3.org for PayPal donations. |
|
||||
+----------------------------------------------+
|
||||
|
||||
|
||||
Quick Start
|
||||
|
@ -77,7 +77,7 @@ Reads & parses (to varying degrees):
|
|||
¤ audio-lossy:
|
||||
* MP3/MP2/MP1
|
||||
* MPC / Musepack
|
||||
* Ogg (Vorbis, OggFLAC, Speex)
|
||||
* Ogg (Vorbis, OggFLAC, Speex, Opus)
|
||||
* AAC / MP4
|
||||
* AC3
|
||||
* DTS
|
||||
|
@ -147,7 +147,8 @@ Requirements
|
|||
|
||||
* PHP 4.2.0 up to 5.2.x for getID3() 1.7.x (and earlier)
|
||||
* PHP 5.0.5 (or higher) for getID3() 1.8.x (and up)
|
||||
* PHP 5.0.5 (or higher) for getID3() 2.0.x (and up)
|
||||
* PHP 5.3.0 (or higher) for getID3() 1.9.17 (and up)
|
||||
* PHP 5.3.0 (or higher) for getID3() 2.0.x (and up)
|
||||
* at least 4MB memory for PHP. 8MB or more is highly recommended.
|
||||
12MB is required with all modules loaded.
|
||||
|
||||
|
@ -179,15 +180,18 @@ $remotefilename = 'http://www.example.com/filename.mp3';
|
|||
if ($fp_remote = fopen($remotefilename, 'rb')) {
|
||||
$localtempfilename = tempnam('/tmp', 'getID3');
|
||||
if ($fp_local = fopen($localtempfilename, 'wb')) {
|
||||
while ($buffer = fread($fp_remote, 8192)) {
|
||||
while ($buffer = fread($fp_remote, 32768)) {
|
||||
fwrite($fp_local, $buffer);
|
||||
}
|
||||
fclose($fp_local);
|
||||
|
||||
$remote_headers = array_change_key_case(get_headers($remotefilename, 1), CASE_LOWER);
|
||||
$remote_filesize = (isset($remote_headers['content-length']) ? (is_array($remote_headers['content-length']) ? $remote_headers['content-length'][count($remote_headers['content-length']) - 1] : $remote_headers['content-length']) : null);
|
||||
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
|
||||
$ThisFileInfo = $getID3->analyze($filename);
|
||||
$ThisFileInfo = $getID3->analyze($localtempfilename, $remote_filesize, basename($remotefilename));
|
||||
|
||||
// Delete temporary file
|
||||
unlink($localtempfilename);
|
||||
|
@ -195,6 +199,11 @@ if ($fp_remote = fopen($remotefilename, 'rb')) {
|
|||
fclose($fp_remote);
|
||||
}
|
||||
|
||||
Note: since v1.9.9-20150212 it is possible a second and third parameter
|
||||
to $getID3->analyze(), for original filesize and original filename
|
||||
respectively. This permits you to download only a portion of a large remote
|
||||
file but get accurate playtime estimates, assuming the format only requires
|
||||
the beginning of the file for correct format analysis.
|
||||
|
||||
See /demos/demo.write.php for how to write tags.
|
||||
|
||||
|
@ -292,7 +301,7 @@ could essentially write it today with a one-line function:
|
|||
|
||||
Future Plans
|
||||
===========================================================================
|
||||
http://www.getid3.org/phpBB3/viewforum.php?f=7
|
||||
https://www.getid3.org/phpBB3/viewforum.php?f=7
|
||||
|
||||
* Better support for MP4 container format
|
||||
* Scan for appended ID3v2 tag at end of file per ID3v2.4 specs (Section 5.0)
|
||||
|
@ -334,11 +343,11 @@ http://www.getid3.org/phpBB3/viewforum.php?f=7
|
|||
* Optional scan-through-frames for AVI verification
|
||||
(thanks rockcohenØmassive-interactive*nl)
|
||||
* Support for TTF (thanks infoØbutterflyx*com)
|
||||
* Support for DSS (http://www.getid3.org/phpBB3/viewtopic.php?t=171)
|
||||
* Support for DSS (https://www.getid3.org/phpBB3/viewtopic.php?t=171)
|
||||
* Support for SMAF (http://smaf-yamaha.com/what/demo.html)
|
||||
http://www.getid3.org/phpBB3/viewtopic.php?t=182
|
||||
* Support for AMR (http://www.getid3.org/phpBB3/viewtopic.php?t=195)
|
||||
* Support for 3gpp (http://www.getid3.org/phpBB3/viewtopic.php?t=195)
|
||||
https://www.getid3.org/phpBB3/viewtopic.php?t=182
|
||||
* Support for AMR (https://www.getid3.org/phpBB3/viewtopic.php?t=195)
|
||||
* Support for 3gpp (https://www.getid3.org/phpBB3/viewtopic.php?t=195)
|
||||
* Support for ID4 (http://www.wackysoft.cjb.net grizlyY2KØhotmail*com)
|
||||
* Parse XML data returned in Ogg comments
|
||||
* Parse XML data from Quicktime SMIL metafiles (klausrathØmac*com)
|
||||
|
@ -374,7 +383,7 @@ http://www.getid3.org/phpBB3/viewforum.php?f=7
|
|||
|
||||
Known Bugs/Issues in getID3() that may be fixed eventually
|
||||
===========================================================================
|
||||
http://www.getid3.org/phpBB3/viewtopic.php?t=25
|
||||
https://www.getid3.org/phpBB3/viewtopic.php?t=25
|
||||
|
||||
* Cannot determine bitrate for MPEG video with VBR video data
|
||||
(need documentation)
|
||||
|
@ -400,7 +409,7 @@ http://www.getid3.org/phpBB3/viewtopic.php?t=25
|
|||
|
||||
Known Bugs/Issues in getID3() that cannot be fixed
|
||||
--------------------------------------------------
|
||||
http://www.getid3.org/phpBB3/viewtopic.php?t=25
|
||||
https://www.getid3.org/phpBB3/viewtopic.php?t=25
|
||||
|
||||
* 32-bit PHP installations only:
|
||||
Files larger than 2GB cannot always be parsed fully by getID3()
|
||||
|
@ -430,8 +439,15 @@ http://www.getid3.org/phpBB3/viewtopic.php?t=25
|
|||
|
||||
Known Bugs/Issues in other programs
|
||||
-----------------------------------
|
||||
http://www.getid3.org/phpBB3/viewtopic.php?t=25
|
||||
https://www.getid3.org/phpBB3/viewtopic.php?t=25
|
||||
|
||||
* MusicBrainz Picard (at least up to v1.3.2) writes multiple
|
||||
ID3v2.3 genres in non-standard forward-slash separated text
|
||||
rather than parenthesis-numeric+refinement style per the ID3v2.3
|
||||
specs. Tags written in ID3v2.4 mode are written correctly.
|
||||
(detected and worked around by getID3())
|
||||
* PZ TagEditor v4.53.408 has been known to insert ID3v2.3 frames
|
||||
into an existing ID3v2.2 tag which, of course, breaks things
|
||||
* Windows Media Player (up to v11) and iTunes (up to v10+) do
|
||||
not correctly handle ID3v2.3 tags with UTF-16BE+BOM
|
||||
encoding (they assume the data is UTF-16LE+BOM and either
|
||||
|
@ -451,6 +467,11 @@ http://www.getid3.org/phpBB3/viewtopic.php?t=25
|
|||
written just "value" (detected by getID3())
|
||||
* Oggenc 0.9-rc3 flags the encoded file as ABR whether it's
|
||||
actually ABR or VBR.
|
||||
* iTunes (versions "v7.0.0.70" is known-guilty, probably
|
||||
other versions are too) writes ID3v2.3 comment tags using an
|
||||
ID3v2.2 frame name (3-bytes) null-padded to 4 bytes which is
|
||||
not valid for ID3v2.3+
|
||||
(detected by getID3() since 1.9.12-201603221746)
|
||||
* iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably
|
||||
other versions are too) writes ID3v2.3 comment tags using a
|
||||
frame name 'COM ' which is not valid for ID3v2.3+ (it's an
|
||||
|
@ -602,3 +623,5 @@ Reference material:
|
|||
* http://trac.musepack.net/trac/wiki/SV8Specification
|
||||
* http://wyday.com/cuesharp/specification.php
|
||||
* http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
|
||||
* http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header
|
||||
* http://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
*
|
||||
* @global string $wp_version
|
||||
*/
|
||||
$wp_version = '5.3-alpha-46111';
|
||||
$wp_version = '5.3-alpha-46112';
|
||||
|
||||
/**
|
||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||
|
|
Loading…
Reference in New Issue