Update getID3 library to 1.9.8.
Changes: https://github.com/JamesHeinrich/getID3/compare/1.9.7...v1.9.8 Fixes #29627. Built from https://develop.svn.wordpress.org/trunk@29734 git-svn-id: http://core.svn.wordpress.org/trunk@29508 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
293e344490
commit
ac02e9951e
|
@ -3,6 +3,7 @@
|
|||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// getid3.lib.php - part of getID3() //
|
||||
|
@ -282,7 +283,6 @@ class getid3_lib
|
|||
}
|
||||
} else {
|
||||
throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits ('.strlen($byteword).') in self::BigEndian2Int()');
|
||||
break;
|
||||
}
|
||||
}
|
||||
return self::CastAsInt($intvalue);
|
||||
|
@ -635,7 +635,7 @@ class getid3_lib
|
|||
}
|
||||
if (is_readable($filename_source) && is_file($filename_source) && ($fp_src = fopen($filename_source, 'rb'))) {
|
||||
if (($fp_dest = fopen($filename_dest, 'wb'))) {
|
||||
if (fseek($fp_src, $offset, SEEK_SET) == 0) {
|
||||
if (fseek($fp_src, $offset) == 0) {
|
||||
$byteslefttowrite = $length;
|
||||
while (($byteslefttowrite > 0) && ($buffer = fread($fp_src, min($byteslefttowrite, getID3::FREAD_BUFFER_SIZE)))) {
|
||||
$byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite);
|
||||
|
@ -986,6 +986,19 @@ class getid3_lib
|
|||
throw new Exception('PHP does not have iconv() support - cannot convert from '.$in_charset.' to '.$out_charset);
|
||||
}
|
||||
|
||||
public static function recursiveMultiByteCharString2HTML($data, $charset='ISO-8859-1') {
|
||||
if (is_string($data)) {
|
||||
return self::MultiByteCharString2HTML($data, $charset);
|
||||
} elseif (is_array($data)) {
|
||||
$return_data = array();
|
||||
foreach ($data as $key => $value) {
|
||||
$return_data[$key] = self::recursiveMultiByteCharString2HTML($value, $charset);
|
||||
}
|
||||
return $return_data;
|
||||
}
|
||||
// integer, float, objects, resources, etc
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function MultiByteCharString2HTML($string, $charset='ISO-8859-1') {
|
||||
$string = (string) $string; // in case trying to pass a numeric (float, int) string, would otherwise return an empty string
|
||||
|
@ -1210,16 +1223,21 @@ class getid3_lib
|
|||
$newvaluelength = strlen(trim($value));
|
||||
foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) {
|
||||
$oldvaluelength = strlen(trim($existingvalue));
|
||||
if (($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) {
|
||||
if ((strlen($existingvalue) > 10) && ($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) {
|
||||
$ThisFileInfo['comments'][$tagname][$existingkey] = trim($value);
|
||||
break 2;
|
||||
//break 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) {
|
||||
$value = (is_string($value) ? trim($value) : $value);
|
||||
$ThisFileInfo['comments'][$tagname][] = $value;
|
||||
if (!is_numeric($key)) {
|
||||
$ThisFileInfo['comments'][$tagname][$key] = $value;
|
||||
} else {
|
||||
$ThisFileInfo['comments'][$tagname][] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1227,20 +1245,23 @@ class getid3_lib
|
|||
}
|
||||
|
||||
// Copy to ['comments_html']
|
||||
foreach ($ThisFileInfo['comments'] as $field => $values) {
|
||||
if ($field == '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
|
||||
continue;
|
||||
}
|
||||
foreach ($values as $index => $value) {
|
||||
if (is_array($value)) {
|
||||
$ThisFileInfo['comments_html'][$field][$index] = $value;
|
||||
} else {
|
||||
$ThisFileInfo['comments_html'][$field][$index] = str_replace('�', '', self::MultiByteCharString2HTML($value, $ThisFileInfo['encoding']));
|
||||
if (!empty($ThisFileInfo['comments'])) {
|
||||
foreach ($ThisFileInfo['comments'] as $field => $values) {
|
||||
if ($field == '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
|
||||
continue;
|
||||
}
|
||||
foreach ($values as $index => $value) {
|
||||
if (is_array($value)) {
|
||||
$ThisFileInfo['comments_html'][$field][$index] = $value;
|
||||
} else {
|
||||
$ThisFileInfo['comments_html'][$field][$index] = str_replace('�', '', self::MultiByteCharString2HTML($value, $ThisFileInfo['encoding']));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1339,4 +1360,17 @@ class getid3_lib
|
|||
}
|
||||
return $filesize;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Workaround for Bug #37268 (https://bugs.php.net/bug.php?id=37268)
|
||||
* @param string $path A path.
|
||||
* @param string $suffix If the name component ends in suffix this will also be cut off.
|
||||
* @return string
|
||||
*/
|
||||
public static function mb_basename($path, $suffix = null) {
|
||||
$splited = preg_split('#/#', rtrim($path, '/ '));
|
||||
return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Please see readme.txt for more information //
|
||||
|
@ -17,18 +18,21 @@ if (!defined('GETID3_OS_ISWINDOWS')) {
|
|||
if (!defined('GETID3_INCLUDEPATH')) {
|
||||
define('GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR);
|
||||
}
|
||||
// Workaround Bug #39923 (https://bugs.php.net/bug.php?id=39923)
|
||||
if (!defined('IMG_JPG') && defined('IMAGETYPE_JPEG')) {
|
||||
define('IMG_JPG', IMAGETYPE_JPEG);
|
||||
}
|
||||
|
||||
// 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))) {
|
||||
$temp_dir = '';
|
||||
}
|
||||
if (!$temp_dir && function_exists('sys_get_temp_dir')) {
|
||||
// PHP v5.2.1+
|
||||
if (!$temp_dir) {
|
||||
// sys_get_temp_dir() may give inaccessible temp dir, e.g. with open_basedir on virtual hosts
|
||||
$temp_dir = sys_get_temp_dir();
|
||||
}
|
||||
$temp_dir = realpath($temp_dir);
|
||||
$temp_dir = @realpath($temp_dir); // see https://github.com/JamesHeinrich/getID3/pull/10
|
||||
$open_basedir = ini_get('open_basedir');
|
||||
if ($open_basedir) {
|
||||
// e.g. "/var/www/vhosts/getid3.org/httpdocs/:/tmp/"
|
||||
|
@ -57,7 +61,9 @@ if (!$temp_dir) {
|
|||
$temp_dir = '*'; // invalid directory name should force tempnam() to use system default temp dir
|
||||
}
|
||||
// $temp_dir = '/something/else/'; // feel free to override temp dir here if it works better for your system
|
||||
define('GETID3_TEMP_DIR', $temp_dir);
|
||||
if (!defined('GETID3_TEMP_DIR')) {
|
||||
define('GETID3_TEMP_DIR', $temp_dir);
|
||||
}
|
||||
unset($open_basedir, $temp_dir);
|
||||
|
||||
// End: Defines
|
||||
|
@ -97,13 +103,13 @@ class getID3
|
|||
public $fp; // Filepointer to file being analysed.
|
||||
public $info; // Result array.
|
||||
public $tempdir = GETID3_TEMP_DIR;
|
||||
public $memory_limit = 0;
|
||||
|
||||
// Protected variables
|
||||
protected $startup_error = '';
|
||||
protected $startup_warning = '';
|
||||
protected $memory_limit = 0;
|
||||
|
||||
const VERSION = '1.9.7-20130705';
|
||||
const VERSION = '1.9.8-20140511';
|
||||
const FREAD_BUFFER_SIZE = 32768;
|
||||
|
||||
const ATTACHMENTS_NONE = false;
|
||||
|
@ -112,13 +118,6 @@ class getID3
|
|||
// public: constructor
|
||||
public function __construct() {
|
||||
|
||||
// Check for PHP version
|
||||
$required_php_version = '5.0.5';
|
||||
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;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check memory
|
||||
$this->memory_limit = ini_get('memory_limit');
|
||||
if (preg_match('#([0-9]+)M#i', $this->memory_limit, $matches)) {
|
||||
|
@ -261,16 +260,32 @@ class getID3
|
|||
$filename = preg_replace('#(.+)'.preg_quote(DIRECTORY_SEPARATOR).'{2,}#U', '\1'.DIRECTORY_SEPARATOR, $filename);
|
||||
|
||||
// open local file
|
||||
if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
|
||||
//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'))) {
|
||||
// great
|
||||
} else {
|
||||
throw new getid3_exception('Could not open "'.$filename.'" (does not exist, or is not a file)');
|
||||
$errormessagelist = array();
|
||||
if (!is_readable($filename)) {
|
||||
$errormessagelist[] = '!is_readable';
|
||||
}
|
||||
if (!is_file($filename)) {
|
||||
$errormessagelist[] = '!is_file';
|
||||
}
|
||||
if (!file_exists($filename)) {
|
||||
$errormessagelist[] = '!file_exists';
|
||||
}
|
||||
if (empty($errormessagelist)) {
|
||||
$errormessagelist[] = 'fopen failed';
|
||||
}
|
||||
throw new getid3_exception('Could not open "'.$filename.'" ('.implode('; ', $errormessagelist).')');
|
||||
}
|
||||
|
||||
$this->info['filesize'] = filesize($filename);
|
||||
// set redundant parameters - might be needed in some include file
|
||||
$this->info['filename'] = basename($filename);
|
||||
// filenames / filepaths in getID3 are always expressed with forward slashes (unix-style) for both Windows and other to try and minimize confusion
|
||||
$filename = str_replace('\\', '/', $filename);
|
||||
$this->info['filepath'] = str_replace('\\', '/', realpath(dirname($filename)));
|
||||
$this->info['filename'] = getid3_lib::mb_basename($filename);
|
||||
$this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename'];
|
||||
|
||||
|
||||
|
@ -352,7 +367,7 @@ class getID3
|
|||
|
||||
// ID3v2 detection (NOT parsing), even if ($this->option_tag_id3v2 == false) done to make fileformat easier
|
||||
if (!$this->option_tag_id3v2) {
|
||||
fseek($this->fp, 0, SEEK_SET);
|
||||
fseek($this->fp, 0);
|
||||
$header = fread($this->fp, 10);
|
||||
if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) {
|
||||
$this->info['id3v2']['header'] = true;
|
||||
|
@ -363,7 +378,7 @@ class getID3
|
|||
}
|
||||
|
||||
// read 32 kb file data
|
||||
fseek($this->fp, $this->info['avdataoffset'], SEEK_SET);
|
||||
fseek($this->fp, $this->info['avdataoffset']);
|
||||
$formattest = fread($this->fp, 32774);
|
||||
|
||||
// determine format
|
||||
|
@ -588,6 +603,14 @@ class getID3
|
|||
'mime_type' => 'audio/basic',
|
||||
),
|
||||
|
||||
// AMR - audio - Adaptive Multi Rate
|
||||
'amr' => array(
|
||||
'pattern' => '^\x23\x21AMR\x0A', // #!AMR[0A]
|
||||
'group' => 'audio',
|
||||
'module' => 'amr',
|
||||
'mime_type' => 'audio/amr',
|
||||
),
|
||||
|
||||
// AVR - audio - Audio Visual Research
|
||||
'avr' => array(
|
||||
'pattern' => '^2BIT',
|
||||
|
@ -1161,6 +1184,7 @@ class getID3
|
|||
'matroska' => array('matroska' , 'UTF-8'),
|
||||
'flac' => array('vorbiscomment' , 'UTF-8'),
|
||||
'divxtag' => array('divx' , 'ISO-8859-1'),
|
||||
'iptc' => array('iptc' , 'ISO-8859-1'),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1181,7 +1205,11 @@ class getID3
|
|||
$value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed!
|
||||
}
|
||||
if ($value) {
|
||||
$this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value;
|
||||
if (!is_numeric($key)) {
|
||||
$this->info['tags'][trim($tag_name)][trim($tag_key)][$key] = $value;
|
||||
} else {
|
||||
$this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($tag_key == 'picture') {
|
||||
|
@ -1196,14 +1224,7 @@ class getID3
|
|||
|
||||
if ($this->option_tags_html) {
|
||||
foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
|
||||
foreach ($valuearray as $key => $value) {
|
||||
if (is_string($value)) {
|
||||
//$this->info['tags_html'][$tag_name][$tag_key][$key] = getid3_lib::MultiByteCharString2HTML($value, $encoding);
|
||||
$this->info['tags_html'][$tag_name][$tag_key][$key] = str_replace('�', '', trim(getid3_lib::MultiByteCharString2HTML($value, $encoding)));
|
||||
} else {
|
||||
$this->info['tags_html'][$tag_name][$tag_key][$key] = $value;
|
||||
}
|
||||
}
|
||||
$this->info['tags_html'][$tag_name][$tag_key] = getid3_lib::recursiveMultiByteCharString2HTML($valuearray, $encoding);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1259,7 +1280,6 @@ class getID3
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function getHashdata($algorithm) {
|
||||
switch ($algorithm) {
|
||||
case 'md5':
|
||||
|
@ -1565,8 +1585,11 @@ class getID3
|
|||
}
|
||||
|
||||
|
||||
abstract class getid3_handler
|
||||
{
|
||||
abstract class getid3_handler {
|
||||
|
||||
/**
|
||||
* @var getID3
|
||||
*/
|
||||
protected $getid3; // pointer
|
||||
|
||||
protected $data_string_flag = false; // analyzing filepointer or string
|
||||
|
@ -1593,7 +1616,7 @@ abstract class getid3_handler
|
|||
// Analyze from string instead
|
||||
public function AnalyzeString($string) {
|
||||
// Enter string mode
|
||||
$this->setStringMode($string);
|
||||
$this->setStringMode($string);
|
||||
|
||||
// Save info
|
||||
$saved_avdataoffset = $this->getid3->info['avdataoffset'];
|
||||
|
@ -1634,10 +1657,10 @@ abstract class getid3_handler
|
|||
$this->data_string_position += $bytes;
|
||||
return substr($this->data_string, $this->data_string_position - $bytes, $bytes);
|
||||
}
|
||||
$pos = $this->ftell() + $bytes;
|
||||
if (!getid3_lib::intValueSupported($pos)) {
|
||||
$pos = $this->ftell() + $bytes;
|
||||
if (!getid3_lib::intValueSupported($pos)) {
|
||||
throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10);
|
||||
}
|
||||
}
|
||||
return fread($this->getid3->fp, $bytes);
|
||||
}
|
||||
|
||||
|
@ -1657,14 +1680,14 @@ abstract class getid3_handler
|
|||
break;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
$pos = $bytes;
|
||||
if ($whence == SEEK_CUR) {
|
||||
} else {
|
||||
$pos = $bytes;
|
||||
if ($whence == SEEK_CUR) {
|
||||
$pos = $this->ftell() + $bytes;
|
||||
} elseif ($whence == SEEK_END) {
|
||||
$pos = $this->info['filesize'] + $bytes;
|
||||
}
|
||||
if (!getid3_lib::intValueSupported($pos)) {
|
||||
} elseif ($whence == SEEK_END) {
|
||||
$pos = $this->getid3->info['filesize'] + $bytes;
|
||||
}
|
||||
if (!getid3_lib::intValueSupported($pos)) {
|
||||
throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10);
|
||||
}
|
||||
}
|
||||
|
@ -1682,20 +1705,17 @@ abstract class getid3_handler
|
|||
return $this->dependency_to == $module;
|
||||
}
|
||||
|
||||
protected function error($text)
|
||||
{
|
||||
protected function error($text) {
|
||||
$this->getid3->info['error'][] = $text;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function warning($text)
|
||||
{
|
||||
protected function warning($text) {
|
||||
return $this->getid3->warning($text);
|
||||
}
|
||||
|
||||
protected function notice($text)
|
||||
{
|
||||
protected function notice($text) {
|
||||
// does nothing for now
|
||||
}
|
||||
|
||||
|
|
|
@ -24,4 +24,4 @@ made publicly available to all getID3() users.
|
|||
The licensee may not sub-license getID3() itself, meaning that any
|
||||
commercially released product containing all or parts of getID3() must
|
||||
have added functionality beyond what is available in getID3();
|
||||
getID3() itself may not be re-licensed by the licensee.
|
||||
getID3() itself may not be re-licensed by the licensee.
|
|
@ -2,6 +2,7 @@
|
|||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
*****************************************************************
|
||||
|
@ -25,4 +26,4 @@ getID3 Commercial License: http://getid3.org/#gCL (payment required)
|
|||
*****************************************************************
|
||||
|
||||
Copies of each of the above licenses are included in the 'licenses'
|
||||
directory of the getID3 distribution.
|
||||
directory of the getID3 distribution.
|
|
@ -3,6 +3,7 @@
|
|||
/// 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 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
@ -15,8 +16,7 @@
|
|||
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
|
||||
|
||||
class getid3_asf extends getid3_handler
|
||||
{
|
||||
class getid3_asf extends getid3_handler {
|
||||
|
||||
public function __construct(getID3 $getid3) {
|
||||
parent::__construct($getid3); // extends getid3_handler::__construct()
|
||||
|
@ -66,25 +66,22 @@ class getid3_asf extends getid3_handler
|
|||
|
||||
$info['fileformat'] = 'asf';
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$HeaderObjectData = fread($this->getid3->fp, 30);
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$HeaderObjectData = $this->fread(30);
|
||||
|
||||
$thisfile_asf_headerobject['objectid'] = substr($HeaderObjectData, 0, 16);
|
||||
$thisfile_asf_headerobject['objectid_guid'] = $this->BytestringToGUID($thisfile_asf_headerobject['objectid']);
|
||||
if ($thisfile_asf_headerobject['objectid'] != GETID3_ASF_Header_Object) {
|
||||
$info['warning'][] = 'ASF header GUID {'.$this->BytestringToGUID($thisfile_asf_headerobject['objectid']).'} does not match expected "GETID3_ASF_Header_Object" GUID {'.$this->BytestringToGUID(GETID3_ASF_Header_Object).'}';
|
||||
unset($info['fileformat']);
|
||||
unset($info['asf']);
|
||||
return false;
|
||||
break;
|
||||
unset($info['fileformat'], $info['asf']);
|
||||
return $this->error('ASF header GUID {'.$this->BytestringToGUID($thisfile_asf_headerobject['objectid']).'} does not match expected "GETID3_ASF_Header_Object" GUID {'.$this->BytestringToGUID(GETID3_ASF_Header_Object).'}');
|
||||
}
|
||||
$thisfile_asf_headerobject['objectsize'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 16, 8));
|
||||
$thisfile_asf_headerobject['headerobjects'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 24, 4));
|
||||
$thisfile_asf_headerobject['reserved1'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 28, 1));
|
||||
$thisfile_asf_headerobject['reserved2'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 29, 1));
|
||||
|
||||
$NextObjectOffset = ftell($this->getid3->fp);
|
||||
$ASFHeaderData = fread($this->getid3->fp, $thisfile_asf_headerobject['objectsize'] - 30);
|
||||
$NextObjectOffset = $this->ftell();
|
||||
$ASFHeaderData = $this->fread($thisfile_asf_headerobject['objectsize'] - 30);
|
||||
$offset = 0;
|
||||
|
||||
for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) {
|
||||
|
@ -284,7 +281,7 @@ class getid3_asf extends getid3_handler
|
|||
$offset += 4;
|
||||
$thisfile_asf_headerextensionobject['extension_data'] = substr($ASFHeaderData, $offset, $thisfile_asf_headerextensionobject['extension_data_size']);
|
||||
$unhandled_sections = 0;
|
||||
$thisfile_asf_headerextensionobject['extension_data_parsed'] = $this->ASF_HeaderExtensionObjectDataParse($thisfile_asf_headerextensionobject['extension_data'], $unhandled_sections);
|
||||
$thisfile_asf_headerextensionobject['extension_data_parsed'] = $this->HeaderExtensionObjectDataParse($thisfile_asf_headerextensionobject['extension_data'], $unhandled_sections);
|
||||
if ($unhandled_sections === 0) {
|
||||
unset($thisfile_asf_headerextensionobject['extension_data']);
|
||||
}
|
||||
|
@ -332,7 +329,7 @@ class getid3_asf extends getid3_handler
|
|||
|
||||
$thisfile_asf_codeclistobject_codecentries_current['type_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_asf_codeclistobject_codecentries_current['type'] = $this->ASFCodecListObjectTypeLookup($thisfile_asf_codeclistobject_codecentries_current['type_raw']);
|
||||
$thisfile_asf_codeclistobject_codecentries_current['type'] = self::codecListObjectTypeLookup($thisfile_asf_codeclistobject_codecentries_current['type_raw']);
|
||||
|
||||
$CodecNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
|
||||
$offset += 2;
|
||||
|
@ -826,22 +823,14 @@ class getid3_asf extends getid3_handler
|
|||
break;
|
||||
|
||||
case 'id3':
|
||||
// id3v2 module might not be loaded
|
||||
if (class_exists('getid3_id3v2')) {
|
||||
$tempfile = tempnam(GETID3_TEMP_DIR, 'getID3');
|
||||
$tempfilehandle = fopen($tempfile, 'wb');
|
||||
$tempThisfileInfo = array('encoding'=>$info['encoding']);
|
||||
fwrite($tempfilehandle, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
|
||||
fclose($tempfilehandle);
|
||||
$this->getid3->include_module('tag.id3v2');
|
||||
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($tempfile);
|
||||
$getid3_id3v2 = new getid3_id3v2($getid3_temp);
|
||||
$getid3_id3v2->Analyze();
|
||||
$info['id3v2'] = $getid3_temp->info['id3v2'];
|
||||
unset($getid3_temp, $getid3_id3v2);
|
||||
$getid3_id3v2 = new getid3_id3v2($this->getid3);
|
||||
$getid3_id3v2->AnalyzeString($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
|
||||
unset($getid3_id3v2);
|
||||
|
||||
unlink($tempfile);
|
||||
if ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length'] > 1024) {
|
||||
$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = '<value too large to display>';
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -860,7 +849,7 @@ class getid3_asf extends getid3_handler
|
|||
$wm_picture_offset = 0;
|
||||
$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type_id'] = getid3_lib::LittleEndian2Int(substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 1));
|
||||
$wm_picture_offset += 1;
|
||||
$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type'] = $this->WMpictureTypeLookup($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type_id']);
|
||||
$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type'] = self::WMpictureTypeLookup($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type_id']);
|
||||
$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_size'] = getid3_lib::LittleEndian2Int(substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 4));
|
||||
$wm_picture_offset += 4;
|
||||
|
||||
|
@ -1156,8 +1145,8 @@ class getid3_asf extends getid3_handler
|
|||
}
|
||||
}
|
||||
|
||||
while (ftell($this->getid3->fp) < $info['avdataend']) {
|
||||
$NextObjectDataHeader = fread($this->getid3->fp, 24);
|
||||
while ($this->ftell() < $info['avdataend']) {
|
||||
$NextObjectDataHeader = $this->fread(24);
|
||||
$offset = 0;
|
||||
$NextObjectGUID = substr($NextObjectDataHeader, 0, 16);
|
||||
$offset += 16;
|
||||
|
@ -1179,7 +1168,7 @@ class getid3_asf extends getid3_handler
|
|||
$thisfile_asf['data_object'] = array();
|
||||
$thisfile_asf_dataobject = &$thisfile_asf['data_object'];
|
||||
|
||||
$DataObjectData = $NextObjectDataHeader.fread($this->getid3->fp, 50 - 24);
|
||||
$DataObjectData = $NextObjectDataHeader.$this->fread(50 - 24);
|
||||
$offset = 24;
|
||||
|
||||
$thisfile_asf_dataobject['objectid'] = $NextObjectGUID;
|
||||
|
@ -1207,9 +1196,9 @@ class getid3_asf extends getid3_handler
|
|||
// * * Error Correction Present bits 1 // If set, use Opaque Data Packet structure, else use Payload structure
|
||||
// * Error Correction Data
|
||||
|
||||
$info['avdataoffset'] = ftell($this->getid3->fp);
|
||||
fseek($this->getid3->fp, ($thisfile_asf_dataobject['objectsize'] - 50), SEEK_CUR); // skip actual audio/video data
|
||||
$info['avdataend'] = ftell($this->getid3->fp);
|
||||
$info['avdataoffset'] = $this->ftell();
|
||||
$this->fseek(($thisfile_asf_dataobject['objectsize'] - 50), SEEK_CUR); // skip actual audio/video data
|
||||
$info['avdataend'] = $this->ftell();
|
||||
break;
|
||||
|
||||
case GETID3_ASF_Simple_Index_Object:
|
||||
|
@ -1229,7 +1218,7 @@ class getid3_asf extends getid3_handler
|
|||
$thisfile_asf['simple_index_object'] = array();
|
||||
$thisfile_asf_simpleindexobject = &$thisfile_asf['simple_index_object'];
|
||||
|
||||
$SimpleIndexObjectData = $NextObjectDataHeader.fread($this->getid3->fp, 56 - 24);
|
||||
$SimpleIndexObjectData = $NextObjectDataHeader.$this->fread(56 - 24);
|
||||
$offset = 24;
|
||||
|
||||
$thisfile_asf_simpleindexobject['objectid'] = $NextObjectGUID;
|
||||
|
@ -1246,7 +1235,7 @@ class getid3_asf extends getid3_handler
|
|||
$thisfile_asf_simpleindexobject['index_entries_count'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$IndexEntriesData = $SimpleIndexObjectData.fread($this->getid3->fp, 6 * $thisfile_asf_simpleindexobject['index_entries_count']);
|
||||
$IndexEntriesData = $SimpleIndexObjectData.$this->fread(6 * $thisfile_asf_simpleindexobject['index_entries_count']);
|
||||
for ($IndexEntriesCounter = 0; $IndexEntriesCounter < $thisfile_asf_simpleindexobject['index_entries_count']; $IndexEntriesCounter++) {
|
||||
$thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_number'] = getid3_lib::LittleEndian2Int(substr($IndexEntriesData, $offset, 4));
|
||||
$offset += 4;
|
||||
|
@ -1283,7 +1272,7 @@ class getid3_asf extends getid3_handler
|
|||
$thisfile_asf['asf_index_object'] = array();
|
||||
$thisfile_asf_asfindexobject = &$thisfile_asf['asf_index_object'];
|
||||
|
||||
$ASFIndexObjectData = $NextObjectDataHeader.fread($this->getid3->fp, 34 - 24);
|
||||
$ASFIndexObjectData = $NextObjectDataHeader.$this->fread(34 - 24);
|
||||
$offset = 24;
|
||||
|
||||
$thisfile_asf_asfindexobject['objectid'] = $NextObjectGUID;
|
||||
|
@ -1297,7 +1286,7 @@ class getid3_asf extends getid3_handler
|
|||
$thisfile_asf_asfindexobject['index_blocks_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$ASFIndexObjectData .= fread($this->getid3->fp, 4 * $thisfile_asf_asfindexobject['index_specifiers_count']);
|
||||
$ASFIndexObjectData .= $this->fread(4 * $thisfile_asf_asfindexobject['index_specifiers_count']);
|
||||
for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) {
|
||||
$IndexSpecifierStreamNumber = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2));
|
||||
$offset += 2;
|
||||
|
@ -1307,17 +1296,17 @@ class getid3_asf extends getid3_handler
|
|||
$thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type_text'] = $this->ASFIndexObjectIndexTypeLookup($thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type']);
|
||||
}
|
||||
|
||||
$ASFIndexObjectData .= fread($this->getid3->fp, 4);
|
||||
$ASFIndexObjectData .= $this->fread(4);
|
||||
$thisfile_asf_asfindexobject['index_entry_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$ASFIndexObjectData .= fread($this->getid3->fp, 8 * $thisfile_asf_asfindexobject['index_specifiers_count']);
|
||||
$ASFIndexObjectData .= $this->fread(8 * $thisfile_asf_asfindexobject['index_specifiers_count']);
|
||||
for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) {
|
||||
$thisfile_asf_asfindexobject['block_positions'][$IndexSpecifiersCounter] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 8));
|
||||
$offset += 8;
|
||||
}
|
||||
|
||||
$ASFIndexObjectData .= fread($this->getid3->fp, 4 * $thisfile_asf_asfindexobject['index_specifiers_count'] * $thisfile_asf_asfindexobject['index_entry_count']);
|
||||
$ASFIndexObjectData .= $this->fread(4 * $thisfile_asf_asfindexobject['index_specifiers_count'] * $thisfile_asf_asfindexobject['index_entry_count']);
|
||||
for ($IndexEntryCounter = 0; $IndexEntryCounter < $thisfile_asf_asfindexobject['index_entry_count']; $IndexEntryCounter++) {
|
||||
for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) {
|
||||
$thisfile_asf_asfindexobject['offsets'][$IndexSpecifiersCounter][$IndexEntryCounter] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4));
|
||||
|
@ -1332,9 +1321,9 @@ class getid3_asf extends getid3_handler
|
|||
if ($this->GUIDname($NextObjectGUIDtext)) {
|
||||
$info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF body at offset '.($offset - 16 - 8);
|
||||
} else {
|
||||
$info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF body at offset '.(ftell($this->getid3->fp) - 16 - 8);
|
||||
$info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF body at offset '.($this->ftell() - 16 - 8);
|
||||
}
|
||||
fseek($this->getid3->fp, ($NextObjectSize - 16 - 8), SEEK_CUR);
|
||||
$this->fseek(($NextObjectSize - 16 - 8), SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1433,10 +1422,10 @@ class getid3_asf extends getid3_handler
|
|||
$thisfile_video['dataformat'] = (!empty($thisfile_video['dataformat']) ? $thisfile_video['dataformat'] : 'asf');
|
||||
}
|
||||
if (!empty($thisfile_video['streams'])) {
|
||||
$thisfile_video['streams']['resolution_x'] = 0;
|
||||
$thisfile_video['streams']['resolution_y'] = 0;
|
||||
$thisfile_video['resolution_x'] = 0;
|
||||
$thisfile_video['resolution_y'] = 0;
|
||||
foreach ($thisfile_video['streams'] as $key => $valuearray) {
|
||||
if (($valuearray['resolution_x'] > $thisfile_video['streams']['resolution_x']) || ($valuearray['resolution_y'] > $thisfile_video['streams']['resolution_y'])) {
|
||||
if (($valuearray['resolution_x'] > $thisfile_video['resolution_x']) || ($valuearray['resolution_y'] > $thisfile_video['resolution_y'])) {
|
||||
$thisfile_video['resolution_x'] = $valuearray['resolution_x'];
|
||||
$thisfile_video['resolution_y'] = $valuearray['resolution_y'];
|
||||
}
|
||||
|
@ -1451,15 +1440,14 @@ class getid3_asf extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public static function ASFCodecListObjectTypeLookup($CodecListType) {
|
||||
static $ASFCodecListObjectTypeLookup = array();
|
||||
if (empty($ASFCodecListObjectTypeLookup)) {
|
||||
$ASFCodecListObjectTypeLookup[0x0001] = 'Video Codec';
|
||||
$ASFCodecListObjectTypeLookup[0x0002] = 'Audio Codec';
|
||||
$ASFCodecListObjectTypeLookup[0xFFFF] = 'Unknown Codec';
|
||||
}
|
||||
public static function codecListObjectTypeLookup($CodecListType) {
|
||||
static $lookup = array(
|
||||
0x0001 => 'Video Codec',
|
||||
0x0002 => 'Audio Codec',
|
||||
0xFFFF => 'Unknown Codec'
|
||||
);
|
||||
|
||||
return (isset($ASFCodecListObjectTypeLookup[$CodecListType]) ? $ASFCodecListObjectTypeLookup[$CodecListType] : 'Invalid Codec Type');
|
||||
return (isset($lookup[$CodecListType]) ? $lookup[$CodecListType] : 'Invalid Codec Type');
|
||||
}
|
||||
|
||||
public static function KnownGUIDs() {
|
||||
|
@ -1666,31 +1654,37 @@ class getid3_asf extends getid3_handler
|
|||
}
|
||||
|
||||
public static function WMpictureTypeLookup($WMpictureType) {
|
||||
static $WMpictureTypeLookup = array();
|
||||
if (empty($WMpictureTypeLookup)) {
|
||||
$WMpictureTypeLookup[0x03] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Front Cover');
|
||||
$WMpictureTypeLookup[0x04] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Back Cover');
|
||||
$WMpictureTypeLookup[0x00] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'User Defined');
|
||||
$WMpictureTypeLookup[0x05] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Leaflet Page');
|
||||
$WMpictureTypeLookup[0x06] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Media Label');
|
||||
$WMpictureTypeLookup[0x07] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Lead Artist');
|
||||
$WMpictureTypeLookup[0x08] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Artist');
|
||||
$WMpictureTypeLookup[0x09] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Conductor');
|
||||
$WMpictureTypeLookup[0x0A] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Band');
|
||||
$WMpictureTypeLookup[0x0B] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Composer');
|
||||
$WMpictureTypeLookup[0x0C] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Lyricist');
|
||||
$WMpictureTypeLookup[0x0D] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Recording Location');
|
||||
$WMpictureTypeLookup[0x0E] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'During Recording');
|
||||
$WMpictureTypeLookup[0x0F] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'During Performance');
|
||||
$WMpictureTypeLookup[0x10] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Video Screen Capture');
|
||||
$WMpictureTypeLookup[0x12] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Illustration');
|
||||
$WMpictureTypeLookup[0x13] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Band Logotype');
|
||||
$WMpictureTypeLookup[0x14] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Publisher Logotype');
|
||||
static $lookup = null;
|
||||
if ($lookup === null) {
|
||||
$lookup = array(
|
||||
0x03 => 'Front Cover',
|
||||
0x04 => 'Back Cover',
|
||||
0x00 => 'User Defined',
|
||||
0x05 => 'Leaflet Page',
|
||||
0x06 => 'Media Label',
|
||||
0x07 => 'Lead Artist',
|
||||
0x08 => 'Artist',
|
||||
0x09 => 'Conductor',
|
||||
0x0A => 'Band',
|
||||
0x0B => 'Composer',
|
||||
0x0C => 'Lyricist',
|
||||
0x0D => 'Recording Location',
|
||||
0x0E => 'During Recording',
|
||||
0x0F => 'During Performance',
|
||||
0x10 => 'Video Screen Capture',
|
||||
0x12 => 'Illustration',
|
||||
0x13 => 'Band Logotype',
|
||||
0x14 => 'Publisher Logotype'
|
||||
);
|
||||
$lookup = array_map(function($str) {
|
||||
return getid3_lib::iconv_fallback('UTF-8', 'UTF-16LE', $str);
|
||||
}, $lookup);
|
||||
}
|
||||
return (isset($WMpictureTypeLookup[$WMpictureType]) ? $WMpictureTypeLookup[$WMpictureType] : '');
|
||||
|
||||
return (isset($lookup[$WMpictureType]) ? $lookup[$WMpictureType] : '');
|
||||
}
|
||||
|
||||
public function ASF_HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) {
|
||||
public function HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) {
|
||||
// http://msdn.microsoft.com/en-us/library/bb643323.aspx
|
||||
|
||||
$offset = 0;
|
||||
|
@ -1825,7 +1819,7 @@ class getid3_asf extends getid3_handler
|
|||
|
||||
$descriptionRecord['data_type'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
|
||||
$offset += 2;
|
||||
$descriptionRecord['data_type_text'] = $this->ASFmetadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']);
|
||||
$descriptionRecord['data_type_text'] = self::metadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']);
|
||||
|
||||
$descriptionRecord['data_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
|
||||
$offset += 4;
|
||||
|
@ -1897,7 +1891,7 @@ class getid3_asf extends getid3_handler
|
|||
|
||||
$descriptionRecord['data_type'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
|
||||
$offset += 2;
|
||||
$descriptionRecord['data_type_text'] = $this->ASFmetadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']);
|
||||
$descriptionRecord['data_type_text'] = self::metadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']);
|
||||
|
||||
$descriptionRecord['data_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
|
||||
$offset += 4;
|
||||
|
@ -1937,8 +1931,8 @@ class getid3_asf extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public static function ASFmetadataLibraryObjectDataTypeLookup($id) {
|
||||
static $ASFmetadataLibraryObjectDataTypeLookup = array(
|
||||
public static function metadataLibraryObjectDataTypeLookup($id) {
|
||||
static $lookup = array(
|
||||
0x0000 => 'Unicode string', // The data consists of a sequence of Unicode characters
|
||||
0x0001 => 'BYTE array', // The type of the data is implementation-specific
|
||||
0x0002 => 'BOOL', // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer. Only 0x0000 or 0x0001 are permitted values
|
||||
|
@ -1947,7 +1941,7 @@ class getid3_asf extends getid3_handler
|
|||
0x0005 => 'WORD', // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer
|
||||
0x0006 => 'GUID', // The data is 16 bytes long and should be interpreted as a 128-bit GUID
|
||||
);
|
||||
return (isset($ASFmetadataLibraryObjectDataTypeLookup[$id]) ? $ASFmetadataLibraryObjectDataTypeLookup[$id] : 'invalid');
|
||||
return (isset($lookup[$id]) ? $lookup[$id] : 'invalid');
|
||||
}
|
||||
|
||||
public function ASF_WMpicture(&$data) {
|
||||
|
@ -1964,7 +1958,7 @@ class getid3_asf extends getid3_handler
|
|||
$offset = 0;
|
||||
$WMpicture['image_type_id'] = getid3_lib::LittleEndian2Int(substr($data, $offset, 1));
|
||||
$offset += 1;
|
||||
$WMpicture['image_type'] = $this->WMpictureTypeLookup($WMpicture['image_type_id']);
|
||||
$WMpicture['image_type'] = self::WMpictureTypeLookup($WMpicture['image_type_id']);
|
||||
$WMpicture['image_size'] = getid3_lib::LittleEndian2Int(substr($data, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
|
@ -2016,4 +2010,4 @@ class getid3_asf extends getid3_handler
|
|||
return $string;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
// //
|
||||
// FLV module by Seth Kaufman <sethØwhirl-i-gig*com> //
|
||||
// //
|
||||
|
@ -38,6 +39,11 @@
|
|||
// * version 0.6.1 (30 May 2011) //
|
||||
// prevent infinite loops in expGolombUe() //
|
||||
// //
|
||||
// * version 0.7.0 (16 Jul 2013) //
|
||||
// handle GETID3_FLV_VIDEO_VP6FLV_ALPHA //
|
||||
// improved AVCSequenceParameterSetReader::readData() //
|
||||
// by Xander Schouwerwou <schouwerwouØgmail*com> //
|
||||
// //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio-video.flv.php //
|
||||
|
@ -67,38 +73,38 @@ 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
|
||||
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
||||
$FLVdataLength = $info['avdataend'] - $info['avdataoffset'];
|
||||
$FLVheader = fread($this->getid3->fp, 5);
|
||||
$FLVheader = $this->fread(5);
|
||||
|
||||
$info['fileformat'] = 'flv';
|
||||
$info['flv']['header']['signature'] = substr($FLVheader, 0, 3);
|
||||
$info['flv']['header']['version'] = getid3_lib::BigEndian2Int(substr($FLVheader, 3, 1));
|
||||
$TypeFlags = getid3_lib::BigEndian2Int(substr($FLVheader, 4, 1));
|
||||
|
||||
$magic = 'FLV';
|
||||
if ($info['flv']['header']['signature'] != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['flv']['header']['signature']).'"';
|
||||
unset($info['flv']);
|
||||
unset($info['fileformat']);
|
||||
if ($info['flv']['header']['signature'] != self::magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(self::magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['flv']['header']['signature']).'"';
|
||||
unset($info['flv'], $info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['flv']['header']['hasAudio'] = (bool) ($TypeFlags & 0x04);
|
||||
$info['flv']['header']['hasVideo'] = (bool) ($TypeFlags & 0x01);
|
||||
|
||||
$FrameSizeDataLength = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 4));
|
||||
$FrameSizeDataLength = getid3_lib::BigEndian2Int($this->fread(4));
|
||||
$FLVheaderFrameLength = 9;
|
||||
if ($FrameSizeDataLength > $FLVheaderFrameLength) {
|
||||
fseek($this->getid3->fp, $FrameSizeDataLength - $FLVheaderFrameLength, SEEK_CUR);
|
||||
$this->fseek($FrameSizeDataLength - $FLVheaderFrameLength, SEEK_CUR);
|
||||
}
|
||||
$Duration = 0;
|
||||
$found_video = false;
|
||||
|
@ -108,15 +114,15 @@ class getid3_flv extends getid3_handler
|
|||
$tagParseCount = 0;
|
||||
$info['flv']['framecount'] = array('total'=>0, 'audio'=>0, 'video'=>0);
|
||||
$flv_framecount = &$info['flv']['framecount'];
|
||||
while (((ftell($this->getid3->fp) + 16) < $info['avdataend']) && (($tagParseCount++ <= $this->max_frames) || !$found_valid_meta_playtime)) {
|
||||
$ThisTagHeader = fread($this->getid3->fp, 16);
|
||||
while ((($this->ftell() + 16) < $info['avdataend']) && (($tagParseCount++ <= $this->max_frames) || !$found_valid_meta_playtime)) {
|
||||
$ThisTagHeader = $this->fread(16);
|
||||
|
||||
$PreviousTagLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 0, 4));
|
||||
$TagType = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 4, 1));
|
||||
$DataLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 5, 3));
|
||||
$Timestamp = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 8, 3));
|
||||
$LastHeaderByte = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 15, 1));
|
||||
$NextOffset = ftell($this->getid3->fp) - 1 + $DataLength;
|
||||
$NextOffset = $this->ftell() - 1 + $DataLength;
|
||||
if ($Timestamp > $Duration) {
|
||||
$Duration = $Timestamp;
|
||||
}
|
||||
|
@ -140,7 +146,7 @@ class getid3_flv extends getid3_handler
|
|||
$found_video = true;
|
||||
$info['flv']['video']['videoCodec'] = $LastHeaderByte & 0x07;
|
||||
|
||||
$FLVvideoHeader = fread($this->getid3->fp, 11);
|
||||
$FLVvideoHeader = $this->fread(11);
|
||||
|
||||
if ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H264) {
|
||||
// this code block contributed by: moysevichØgmail*com
|
||||
|
@ -160,7 +166,7 @@ class getid3_flv extends getid3_handler
|
|||
//$spsSize = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 9, 2));
|
||||
$spsSize = getid3_lib::LittleEndian2Int(substr($FLVvideoHeader, 9, 2));
|
||||
// read the first SequenceParameterSet
|
||||
$sps = fread($this->getid3->fp, $spsSize);
|
||||
$sps = $this->fread($spsSize);
|
||||
if (strlen($sps) == $spsSize) { // make sure that whole SequenceParameterSet was red
|
||||
$spsReader = new AVCSequenceParameterSetReader($sps);
|
||||
$spsReader->readData();
|
||||
|
@ -185,19 +191,15 @@ class getid3_flv extends getid3_handler
|
|||
//$PictureSizeEnc <<= 1;
|
||||
//$info['video']['resolution_y'] = ($PictureSizeEnc & 0xFF00) >> 8;
|
||||
|
||||
$PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 2));
|
||||
$PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2));
|
||||
$PictureSizeEnc['x'] >>= 7;
|
||||
$PictureSizeEnc['y'] >>= 7;
|
||||
$PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 2)) >> 7;
|
||||
$PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2)) >> 7;
|
||||
$info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFF;
|
||||
$info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFF;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
$PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 3));
|
||||
$PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 3));
|
||||
$PictureSizeEnc['x'] >>= 7;
|
||||
$PictureSizeEnc['y'] >>= 7;
|
||||
$PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 3)) >> 7;
|
||||
$PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 3)) >> 7;
|
||||
$info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFFFF;
|
||||
$info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFFFF;
|
||||
break;
|
||||
|
@ -233,8 +235,22 @@ class getid3_flv extends getid3_handler
|
|||
break;
|
||||
|
||||
}
|
||||
|
||||
} elseif ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_VP6FLV_ALPHA) {
|
||||
|
||||
/* contributed by schouwerwouØgmail*com */
|
||||
if (!isset($info['video']['resolution_x'])) { // only when meta data isn't set
|
||||
$PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 2));
|
||||
$PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 7, 2));
|
||||
$info['video']['resolution_x'] = ($PictureSizeEnc['x'] & 0xFF) << 3;
|
||||
$info['video']['resolution_y'] = ($PictureSizeEnc['y'] & 0xFF) << 3;
|
||||
}
|
||||
/* end schouwerwouØgmail*com */
|
||||
|
||||
}
|
||||
if (!empty($info['video']['resolution_x']) && !empty($info['video']['resolution_y'])) {
|
||||
$info['video']['pixel_aspect_ratio'] = $info['video']['resolution_x'] / $info['video']['resolution_y'];
|
||||
}
|
||||
$info['video']['pixel_aspect_ratio'] = $info['video']['resolution_x'] / $info['video']['resolution_y'];
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -242,8 +258,8 @@ class getid3_flv extends getid3_handler
|
|||
case GETID3_FLV_TAG_META:
|
||||
if (!$found_meta) {
|
||||
$found_meta = true;
|
||||
fseek($this->getid3->fp, -1, SEEK_CUR);
|
||||
$datachunk = fread($this->getid3->fp, $DataLength);
|
||||
$this->fseek(-1, SEEK_CUR);
|
||||
$datachunk = $this->fread($DataLength);
|
||||
$AMFstream = new AMFStream($datachunk);
|
||||
$reader = new AMFReader($AMFstream);
|
||||
$eventName = $reader->readData();
|
||||
|
@ -279,7 +295,7 @@ class getid3_flv extends getid3_handler
|
|||
// noop
|
||||
break;
|
||||
}
|
||||
fseek($this->getid3->fp, $NextOffset, SEEK_SET);
|
||||
$this->fseek($NextOffset);
|
||||
}
|
||||
|
||||
$info['playtime_seconds'] = $Duration / 1000;
|
||||
|
@ -288,16 +304,16 @@ class getid3_flv extends getid3_handler
|
|||
}
|
||||
|
||||
if ($info['flv']['header']['hasAudio']) {
|
||||
$info['audio']['codec'] = $this->FLVaudioFormat($info['flv']['audio']['audioFormat']);
|
||||
$info['audio']['sample_rate'] = $this->FLVaudioRate($info['flv']['audio']['audioRate']);
|
||||
$info['audio']['bits_per_sample'] = $this->FLVaudioBitDepth($info['flv']['audio']['audioSampleSize']);
|
||||
$info['audio']['codec'] = self::audioFormatLookup($info['flv']['audio']['audioFormat']);
|
||||
$info['audio']['sample_rate'] = self::audioRateLookup($info['flv']['audio']['audioRate']);
|
||||
$info['audio']['bits_per_sample'] = self::audioBitDepthLookup($info['flv']['audio']['audioSampleSize']);
|
||||
|
||||
$info['audio']['channels'] = $info['flv']['audio']['audioType'] + 1; // 0=mono,1=stereo
|
||||
$info['audio']['lossless'] = ($info['flv']['audio']['audioFormat'] ? false : true); // 0=uncompressed
|
||||
$info['audio']['dataformat'] = 'flv';
|
||||
}
|
||||
if (!empty($info['flv']['header']['hasVideo'])) {
|
||||
$info['video']['codec'] = $this->FLVvideoCodec($info['flv']['video']['videoCodec']);
|
||||
$info['video']['codec'] = self::videoCodecLookup($info['flv']['video']['videoCodec']);
|
||||
$info['video']['dataformat'] = 'flv';
|
||||
$info['video']['lossless'] = false;
|
||||
}
|
||||
|
@ -308,17 +324,17 @@ class getid3_flv extends getid3_handler
|
|||
$info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
}
|
||||
if (isset($info['flv']['meta']['onMetaData']['audiocodecid'])) {
|
||||
$info['audio']['codec'] = $this->FLVaudioFormat($info['flv']['meta']['onMetaData']['audiocodecid']);
|
||||
$info['audio']['codec'] = self::audioFormatLookup($info['flv']['meta']['onMetaData']['audiocodecid']);
|
||||
}
|
||||
if (isset($info['flv']['meta']['onMetaData']['videocodecid'])) {
|
||||
$info['video']['codec'] = $this->FLVvideoCodec($info['flv']['meta']['onMetaData']['videocodecid']);
|
||||
$info['video']['codec'] = self::videoCodecLookup($info['flv']['meta']['onMetaData']['videocodecid']);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function FLVaudioFormat($id) {
|
||||
$FLVaudioFormat = array(
|
||||
public static function audioFormatLookup($id) {
|
||||
static $lookup = array(
|
||||
0 => 'Linear PCM, platform endian',
|
||||
1 => 'ADPCM',
|
||||
2 => 'mp3',
|
||||
|
@ -330,35 +346,35 @@ class getid3_flv extends getid3_handler
|
|||
8 => 'G.711 mu-law logarithmic PCM',
|
||||
9 => 'reserved',
|
||||
10 => 'AAC',
|
||||
11 => false, // unknown?
|
||||
11 => 'Speex',
|
||||
12 => false, // unknown?
|
||||
13 => false, // unknown?
|
||||
14 => 'mp3 8kHz',
|
||||
15 => 'Device-specific sound',
|
||||
);
|
||||
return (isset($FLVaudioFormat[$id]) ? $FLVaudioFormat[$id] : false);
|
||||
return (isset($lookup[$id]) ? $lookup[$id] : false);
|
||||
}
|
||||
|
||||
public function FLVaudioRate($id) {
|
||||
$FLVaudioRate = array(
|
||||
public static function audioRateLookup($id) {
|
||||
static $lookup = array(
|
||||
0 => 5500,
|
||||
1 => 11025,
|
||||
2 => 22050,
|
||||
3 => 44100,
|
||||
);
|
||||
return (isset($FLVaudioRate[$id]) ? $FLVaudioRate[$id] : false);
|
||||
return (isset($lookup[$id]) ? $lookup[$id] : false);
|
||||
}
|
||||
|
||||
public function FLVaudioBitDepth($id) {
|
||||
$FLVaudioBitDepth = array(
|
||||
public static function audioBitDepthLookup($id) {
|
||||
static $lookup = array(
|
||||
0 => 8,
|
||||
1 => 16,
|
||||
);
|
||||
return (isset($FLVaudioBitDepth[$id]) ? $FLVaudioBitDepth[$id] : false);
|
||||
return (isset($lookup[$id]) ? $lookup[$id] : false);
|
||||
}
|
||||
|
||||
public function FLVvideoCodec($id) {
|
||||
$FLVvideoCodec = array(
|
||||
public static function videoCodecLookup($id) {
|
||||
static $lookup = array(
|
||||
GETID3_FLV_VIDEO_H263 => 'Sorenson H.263',
|
||||
GETID3_FLV_VIDEO_SCREEN => 'Screen video',
|
||||
GETID3_FLV_VIDEO_VP6FLV => 'On2 VP6',
|
||||
|
@ -366,7 +382,7 @@ class getid3_flv extends getid3_handler
|
|||
GETID3_FLV_VIDEO_SCREENV2 => 'Screen video v2',
|
||||
GETID3_FLV_VIDEO_H264 => 'Sorenson H.264',
|
||||
);
|
||||
return (isset($FLVvideoCodec[$id]) ? $FLVvideoCodec[$id] : false);
|
||||
return (isset($lookup[$id]) ? $lookup[$id] : false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -374,7 +390,7 @@ class AMFStream {
|
|||
public $bytes;
|
||||
public $pos;
|
||||
|
||||
public function AMFStream(&$bytes) {
|
||||
public function __construct(&$bytes) {
|
||||
$this->bytes =& $bytes;
|
||||
$this->pos = 0;
|
||||
}
|
||||
|
@ -457,7 +473,7 @@ class AMFStream {
|
|||
class AMFReader {
|
||||
public $stream;
|
||||
|
||||
public function AMFReader(&$stream) {
|
||||
public function __construct(&$stream) {
|
||||
$this->stream =& $stream;
|
||||
}
|
||||
|
||||
|
@ -619,60 +635,60 @@ class AVCSequenceParameterSetReader {
|
|||
public $width;
|
||||
public $height;
|
||||
|
||||
public function AVCSequenceParameterSetReader($sps) {
|
||||
public function __construct($sps) {
|
||||
$this->sps = $sps;
|
||||
}
|
||||
|
||||
public function readData() {
|
||||
$this->skipBits(8);
|
||||
$this->skipBits(8);
|
||||
$profile = $this->getBits(8); // read profile
|
||||
$this->skipBits(16);
|
||||
$this->expGolombUe(); // read sps id
|
||||
if (in_array($profile, array(H264_PROFILE_HIGH, H264_PROFILE_HIGH10, H264_PROFILE_HIGH422, H264_PROFILE_HIGH444, H264_PROFILE_HIGH444_PREDICTIVE))) {
|
||||
if ($this->expGolombUe() == 3) {
|
||||
$this->skipBits(1);
|
||||
}
|
||||
$this->expGolombUe();
|
||||
$this->expGolombUe();
|
||||
$this->skipBits(1);
|
||||
if ($this->getBit()) {
|
||||
for ($i = 0; $i < 8; $i++) {
|
||||
if ($this->getBit()) {
|
||||
$size = $i < 6 ? 16 : 64;
|
||||
$lastScale = 8;
|
||||
$nextScale = 8;
|
||||
for ($j = 0; $j < $size; $j++) {
|
||||
if ($nextScale != 0) {
|
||||
$deltaScale = $this->expGolombUe();
|
||||
$nextScale = ($lastScale + $deltaScale + 256) % 256;
|
||||
}
|
||||
if ($nextScale != 0) {
|
||||
$lastScale = $nextScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
$profile = $this->getBits(8); // read profile
|
||||
if ($profile > 0) {
|
||||
$this->skipBits(8);
|
||||
$level_idc = $this->getBits(8); // level_idc
|
||||
$this->expGolombUe(); // seq_parameter_set_id // sps
|
||||
$this->expGolombUe(); // log2_max_frame_num_minus4
|
||||
$picOrderType = $this->expGolombUe(); // pic_order_cnt_type
|
||||
if ($picOrderType == 0) {
|
||||
$this->expGolombUe(); // log2_max_pic_order_cnt_lsb_minus4
|
||||
} elseif ($picOrderType == 1) {
|
||||
$this->skipBits(1); // delta_pic_order_always_zero_flag
|
||||
$this->expGolombSe(); // offset_for_non_ref_pic
|
||||
$this->expGolombSe(); // offset_for_top_to_bottom_field
|
||||
$num_ref_frames_in_pic_order_cnt_cycle = $this->expGolombUe(); // num_ref_frames_in_pic_order_cnt_cycle
|
||||
for ($i = 0; $i < $num_ref_frames_in_pic_order_cnt_cycle; $i++) {
|
||||
$this->expGolombSe(); // offset_for_ref_frame[ i ]
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->expGolombUe();
|
||||
$pocType = $this->expGolombUe();
|
||||
if ($pocType == 0) {
|
||||
$this->expGolombUe();
|
||||
} elseif ($pocType == 1) {
|
||||
$this->skipBits(1);
|
||||
$this->expGolombSe();
|
||||
$this->expGolombSe();
|
||||
$pocCycleLength = $this->expGolombUe();
|
||||
for ($i = 0; $i < $pocCycleLength; $i++) {
|
||||
$this->expGolombSe();
|
||||
$this->expGolombUe(); // num_ref_frames
|
||||
$this->skipBits(1); // gaps_in_frame_num_value_allowed_flag
|
||||
$pic_width_in_mbs_minus1 = $this->expGolombUe(); // pic_width_in_mbs_minus1
|
||||
$pic_height_in_map_units_minus1 = $this->expGolombUe(); // pic_height_in_map_units_minus1
|
||||
|
||||
$frame_mbs_only_flag = $this->getBits(1); // frame_mbs_only_flag
|
||||
if ($frame_mbs_only_flag == 0) {
|
||||
$this->skipBits(1); // mb_adaptive_frame_field_flag
|
||||
}
|
||||
$this->skipBits(1); // direct_8x8_inference_flag
|
||||
$frame_cropping_flag = $this->getBits(1); // frame_cropping_flag
|
||||
|
||||
$frame_crop_left_offset = 0;
|
||||
$frame_crop_right_offset = 0;
|
||||
$frame_crop_top_offset = 0;
|
||||
$frame_crop_bottom_offset = 0;
|
||||
|
||||
if ($frame_cropping_flag) {
|
||||
$frame_crop_left_offset = $this->expGolombUe(); // frame_crop_left_offset
|
||||
$frame_crop_right_offset = $this->expGolombUe(); // frame_crop_right_offset
|
||||
$frame_crop_top_offset = $this->expGolombUe(); // frame_crop_top_offset
|
||||
$frame_crop_bottom_offset = $this->expGolombUe(); // frame_crop_bottom_offset
|
||||
}
|
||||
$this->skipBits(1); // vui_parameters_present_flag
|
||||
// etc
|
||||
|
||||
$this->width = (($pic_width_in_mbs_minus1 + 1) * 16) - ($frame_crop_left_offset * 2) - ($frame_crop_right_offset * 2);
|
||||
$this->height = ((2 - $frame_mbs_only_flag) * ($pic_height_in_map_units_minus1 + 1) * 16) - ($frame_crop_top_offset * 2) - ($frame_crop_bottom_offset * 2);
|
||||
}
|
||||
$this->expGolombUe();
|
||||
$this->skipBits(1);
|
||||
$this->width = ($this->expGolombUe() + 1) * 16;
|
||||
$heightMap = $this->expGolombUe() + 1;
|
||||
$this->height = (2 - $this->getBit()) * $heightMap * 16;
|
||||
}
|
||||
|
||||
public function skipBits($bits) {
|
||||
|
@ -726,4 +742,4 @@ class AVCSequenceParameterSetReader {
|
|||
public function getHeight() {
|
||||
return $this->height;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
/// 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 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
@ -281,10 +282,8 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
switch ($trackarray['CodecID']) {
|
||||
case 'V_MS/VFW/FOURCC':
|
||||
if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) {
|
||||
$this->warning('Unable to parse codec private data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio-video.riff.php"');
|
||||
break;
|
||||
}
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
|
||||
|
||||
$parsed = getid3_riff::ParseBITMAPINFOHEADER($trackarray['CodecPrivate']);
|
||||
$track_info['codec'] = getid3_riff::fourccLookup($parsed['fourcc']);
|
||||
$info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
|
||||
|
@ -335,10 +334,7 @@ class getid3_matroska extends getid3_handler
|
|||
case 'A_MPEG/L3':
|
||||
case 'A_MPEG/L2':
|
||||
case 'A_FLAC':
|
||||
if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.'.($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']).'.php', __FILE__, false)) {
|
||||
$this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.'.$track_info['dataformat'].'.php"');
|
||||
break;
|
||||
}
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.'.($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']).'.php', __FILE__, true);
|
||||
|
||||
if (!isset($info['matroska']['track_data_offsets'][$trackarray['TrackNumber']])) {
|
||||
$this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because $info[matroska][track_data_offsets]['.$trackarray['TrackNumber'].'] not set');
|
||||
|
@ -385,10 +381,6 @@ class getid3_matroska extends getid3_handler
|
|||
}
|
||||
if (!empty($getid3_temp->info['warning'])) {
|
||||
foreach ($getid3_temp->info['warning'] as $newerror) {
|
||||
if ($track_info['dataformat'] == 'mp3' && preg_match('/^Probable truncated file: expecting \d+ bytes of audio data, only found \d+ \(short by \d+ bytes\)$/', $newerror)) {
|
||||
// LAME/Xing header is probably set, but audio data is chunked into Matroska file and near-impossible to verify if audio stream is complete, so ignore useless warning
|
||||
continue;
|
||||
}
|
||||
$this->warning($class.'() says: ['.$newerror.']');
|
||||
}
|
||||
}
|
||||
|
@ -400,7 +392,7 @@ class getid3_matroska extends getid3_handler
|
|||
case 'A_AAC/MPEG2/LC/SBR':
|
||||
case 'A_AAC/MPEG4/LC':
|
||||
case 'A_AAC/MPEG4/LC/SBR':
|
||||
$this->warning($trackarray['CodecID'].' audio data contains no header, audio/video bitrates can\'t be calculated');
|
||||
$this->warning($trackarray['CodecID'].' audio data contains no header, audio/video bitrates can\'t be calculated');
|
||||
break;
|
||||
|
||||
case 'A_VORBIS':
|
||||
|
@ -415,10 +407,7 @@ class getid3_matroska extends getid3_handler
|
|||
}
|
||||
$vorbis_offset -= 1;
|
||||
|
||||
if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, false)) {
|
||||
$this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.ogg.php"');
|
||||
break;
|
||||
}
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, true);
|
||||
|
||||
// create temp instance
|
||||
$getid3_temp = new getID3();
|
||||
|
@ -455,10 +444,7 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case 'A_MS/ACM':
|
||||
if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) {
|
||||
$this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio-video.riff.php"');
|
||||
break;
|
||||
}
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
|
||||
|
||||
$parsed = getid3_riff::parseWAVEFORMATex($trackarray['CodecPrivate']);
|
||||
foreach ($parsed as $key => $value) {
|
||||
|
@ -515,7 +501,6 @@ class getid3_matroska extends getid3_handler
|
|||
switch ($top_element['id']) {
|
||||
|
||||
case EBML_ID_EBML:
|
||||
$info['fileformat'] = 'matroska';
|
||||
$info['matroska']['header']['offset'] = $top_element['offset'];
|
||||
$info['matroska']['header']['length'] = $top_element['length'];
|
||||
|
||||
|
@ -534,6 +519,7 @@ class getid3_matroska extends getid3_handler
|
|||
case EBML_ID_DOCTYPE:
|
||||
$element_data['data'] = getid3_lib::trimNullByte($element_data['data']);
|
||||
$info['matroska']['doctype'] = $element_data['data'];
|
||||
$info['fileformat'] = $element_data['data'];
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1526,8 +1512,8 @@ class getid3_matroska extends getid3_handler
|
|||
$CodecIDlist['V_MPEG4/ISO/AVC'] = 'h264';
|
||||
$CodecIDlist['V_MPEG4/ISO/SP'] = 'mpeg4';
|
||||
$CodecIDlist['V_VP8'] = 'vp8';
|
||||
$CodecIDlist['V_MS/VFW/FOURCC'] = 'riff';
|
||||
$CodecIDlist['A_MS/ACM'] = 'riff';
|
||||
$CodecIDlist['V_MS/VFW/FOURCC'] = 'vcm'; // Microsoft (TM) Video Codec Manager (VCM)
|
||||
$CodecIDlist['A_MS/ACM'] = 'acm'; // Microsoft (TM) Audio Codec Manager (ACM)
|
||||
}
|
||||
return (isset($CodecIDlist[$codecid]) ? $CodecIDlist[$codecid] : $codecid);
|
||||
}
|
||||
|
@ -1762,4 +1748,4 @@ class getid3_matroska extends getid3_handler
|
|||
return $info;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
/// 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 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
@ -30,7 +31,7 @@ class getid3_quicktime extends getid3_handler
|
|||
$info['quicktime']['hinting'] = false;
|
||||
$info['quicktime']['controller'] = 'standard'; // may be overridden if 'ctyp' atom is present
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
||||
$offset = 0;
|
||||
$atomcounter = 0;
|
||||
|
@ -40,15 +41,15 @@ class getid3_quicktime extends getid3_handler
|
|||
$info['error'][] = 'Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions';
|
||||
break;
|
||||
}
|
||||
fseek($this->getid3->fp, $offset, SEEK_SET);
|
||||
$AtomHeader = fread($this->getid3->fp, 8);
|
||||
$this->fseek($offset);
|
||||
$AtomHeader = $this->fread(8);
|
||||
|
||||
$atomsize = getid3_lib::BigEndian2Int(substr($AtomHeader, 0, 4));
|
||||
$atomname = substr($AtomHeader, 4, 4);
|
||||
|
||||
// 64-bit MOV patch by jlegateØktnc*com
|
||||
if ($atomsize == 1) {
|
||||
$atomsize = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 8));
|
||||
$atomsize = getid3_lib::BigEndian2Int($this->fread(8));
|
||||
}
|
||||
|
||||
$info['quicktime'][$atomname]['name'] = $atomname;
|
||||
|
@ -66,58 +67,8 @@ class getid3_quicktime extends getid3_handler
|
|||
// to read user data atoms, you should allow for the terminating 0.
|
||||
break;
|
||||
}
|
||||
switch ($atomname) {
|
||||
case 'mdat': // Media DATa atom
|
||||
// 'mdat' contains the actual data for the audio/video
|
||||
if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) {
|
||||
|
||||
$info['avdataoffset'] = $info['quicktime'][$atomname]['offset'] + 8;
|
||||
$OldAVDataEnd = $info['avdataend'];
|
||||
$info['avdataend'] = $info['quicktime'][$atomname]['offset'] + $info['quicktime'][$atomname]['size'];
|
||||
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
|
||||
$getid3_temp->info['avdataend'] = $info['avdataend'];
|
||||
$getid3_mp3 = new getid3_mp3($getid3_temp);
|
||||
if ($getid3_mp3->MPEGaudioHeaderValid($getid3_mp3->MPEGaudioHeaderDecode(fread($this->getid3->fp, 4)))) {
|
||||
$getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
|
||||
if (!empty($getid3_temp->info['warning'])) {
|
||||
foreach ($getid3_temp->info['warning'] as $value) {
|
||||
$info['warning'][] = $value;
|
||||
}
|
||||
}
|
||||
if (!empty($getid3_temp->info['mpeg'])) {
|
||||
$info['mpeg'] = $getid3_temp->info['mpeg'];
|
||||
if (isset($info['mpeg']['audio'])) {
|
||||
$info['audio']['dataformat'] = 'mp3';
|
||||
$info['audio']['codec'] = (!empty($info['mpeg']['audio']['encoder']) ? $info['mpeg']['audio']['encoder'] : (!empty($info['mpeg']['audio']['codec']) ? $info['mpeg']['audio']['codec'] : (!empty($info['mpeg']['audio']['LAME']) ? 'LAME' :'mp3')));
|
||||
$info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
|
||||
$info['audio']['channels'] = $info['mpeg']['audio']['channels'];
|
||||
$info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
|
||||
$info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
|
||||
$info['bitrate'] = $info['audio']['bitrate'];
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($getid3_mp3, $getid3_temp);
|
||||
$info['avdataend'] = $OldAVDataEnd;
|
||||
unset($OldAVDataEnd);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case 'free': // FREE space atom
|
||||
case 'skip': // SKIP atom
|
||||
case 'wide': // 64-bit expansion placeholder atom
|
||||
// 'free', 'skip' and 'wide' are just padding, contains no useful data at all
|
||||
break;
|
||||
|
||||
default:
|
||||
$atomHierarchy = array();
|
||||
$info['quicktime'][$atomname] = $this->QuicktimeParseAtom($atomname, $atomsize, fread($this->getid3->fp, $atomsize), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms);
|
||||
break;
|
||||
}
|
||||
$atomHierarchy = array();
|
||||
$info['quicktime'][$atomname] = $this->QuicktimeParseAtom($atomname, $atomsize, $this->fread(min($atomsize, round($this->getid3->memory_limit / 2))), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms);
|
||||
|
||||
$offset += $atomsize;
|
||||
$atomcounter++;
|
||||
|
@ -172,15 +123,12 @@ class getid3_quicktime extends getid3_handler
|
|||
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
//$atom_parent = array_pop($atomHierarchy);
|
||||
$atom_parent = end($atomHierarchy); // http://www.getid3.org/phpBB3/viewtopic.php?t=1717
|
||||
$atom_parent = end($atomHierarchy); // not array_pop($atomHierarchy); see http://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;
|
||||
//echo getid3_lib::PrintHexBytes(substr($atom_data, 0, 8)).'<br>';
|
||||
//echo getid3_lib::PrintHexBytes(substr($atom_data, 0, 8), false).'<br><br>';
|
||||
switch ($atomname) {
|
||||
case 'moov': // MOVie container atom
|
||||
case 'trak': // TRAcK container atom
|
||||
|
@ -200,27 +148,27 @@ class getid3_quicktime extends getid3_handler
|
|||
break;
|
||||
|
||||
case 'ilst': // Item LiST container atom
|
||||
$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
|
||||
|
||||
// some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted
|
||||
$allnumericnames = true;
|
||||
foreach ($atom_structure['subatoms'] as $subatomarray) {
|
||||
if (!is_integer($subatomarray['name']) || (count($subatomarray['subatoms']) != 1)) {
|
||||
$allnumericnames = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($allnumericnames) {
|
||||
$newData = array();
|
||||
if ($atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms)) {
|
||||
// some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted
|
||||
$allnumericnames = true;
|
||||
foreach ($atom_structure['subatoms'] as $subatomarray) {
|
||||
foreach ($subatomarray['subatoms'] as $newData_subatomarray) {
|
||||
unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']);
|
||||
$newData[$subatomarray['name']] = $newData_subatomarray;
|
||||
if (!is_integer($subatomarray['name']) || (count($subatomarray['subatoms']) != 1)) {
|
||||
$allnumericnames = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$atom_structure['data'] = $newData;
|
||||
unset($atom_structure['subatoms']);
|
||||
if ($allnumericnames) {
|
||||
$newData = array();
|
||||
foreach ($atom_structure['subatoms'] as $subatomarray) {
|
||||
foreach ($subatomarray['subatoms'] as $newData_subatomarray) {
|
||||
unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']);
|
||||
$newData[$subatomarray['name']] = $newData_subatomarray;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$atom_structure['data'] = $newData;
|
||||
unset($atom_structure['subatoms']);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -308,46 +256,46 @@ class getid3_quicktime extends getid3_handler
|
|||
case 'geID':
|
||||
case 'plID':
|
||||
case 'sfID': // iTunes store country
|
||||
case '©alb': // ALBum
|
||||
case '©art': // ARTist
|
||||
case '©ART':
|
||||
case '©aut':
|
||||
case '©cmt': // CoMmenT
|
||||
case '©com': // COMposer
|
||||
case '©cpy':
|
||||
case '©day': // content created year
|
||||
case '©dir':
|
||||
case '©ed1':
|
||||
case '©ed2':
|
||||
case '©ed3':
|
||||
case '©ed4':
|
||||
case '©ed5':
|
||||
case '©ed6':
|
||||
case '©ed7':
|
||||
case '©ed8':
|
||||
case '©ed9':
|
||||
case '©enc':
|
||||
case '©fmt':
|
||||
case '©gen': // GENre
|
||||
case '©grp': // GRouPing
|
||||
case '©hst':
|
||||
case '©inf':
|
||||
case '©lyr': // LYRics
|
||||
case '©mak':
|
||||
case '©mod':
|
||||
case '©nam': // full NAMe
|
||||
case '©ope':
|
||||
case '©PRD':
|
||||
case '©prd':
|
||||
case '©prf':
|
||||
case '©req':
|
||||
case '©src':
|
||||
case '©swr':
|
||||
case '©too': // encoder
|
||||
case '©trk': // TRacK
|
||||
case '©url':
|
||||
case '©wrn':
|
||||
case '©wrt': // WRiTer
|
||||
case "\xA9".'alb': // ALBum
|
||||
case "\xA9".'art': // ARTist
|
||||
case "\xA9".'ART':
|
||||
case "\xA9".'aut':
|
||||
case "\xA9".'cmt': // CoMmenT
|
||||
case "\xA9".'com': // COMposer
|
||||
case "\xA9".'cpy':
|
||||
case "\xA9".'day': // content created year
|
||||
case "\xA9".'dir':
|
||||
case "\xA9".'ed1':
|
||||
case "\xA9".'ed2':
|
||||
case "\xA9".'ed3':
|
||||
case "\xA9".'ed4':
|
||||
case "\xA9".'ed5':
|
||||
case "\xA9".'ed6':
|
||||
case "\xA9".'ed7':
|
||||
case "\xA9".'ed8':
|
||||
case "\xA9".'ed9':
|
||||
case "\xA9".'enc':
|
||||
case "\xA9".'fmt':
|
||||
case "\xA9".'gen': // GENre
|
||||
case "\xA9".'grp': // GRouPing
|
||||
case "\xA9".'hst':
|
||||
case "\xA9".'inf':
|
||||
case "\xA9".'lyr': // LYRics
|
||||
case "\xA9".'mak':
|
||||
case "\xA9".'mod':
|
||||
case "\xA9".'nam': // full NAMe
|
||||
case "\xA9".'ope':
|
||||
case "\xA9".'PRD':
|
||||
case "\xA9".'prd':
|
||||
case "\xA9".'prf':
|
||||
case "\xA9".'req':
|
||||
case "\xA9".'src':
|
||||
case "\xA9".'swr':
|
||||
case "\xA9".'too': // encoder
|
||||
case "\xA9".'trk': // TRacK
|
||||
case "\xA9".'url':
|
||||
case "\xA9".'wrn':
|
||||
case "\xA9".'wrt': // WRiTer
|
||||
case '----': // itunes specific
|
||||
if ($atom_parent == 'udta') {
|
||||
// User data atom handler
|
||||
|
@ -370,7 +318,7 @@ class getid3_quicktime extends getid3_handler
|
|||
$boxsmalltype = substr($atom_data, $atomoffset + 2, 2);
|
||||
$boxsmalldata = substr($atom_data, $atomoffset + 4, $boxsmallsize);
|
||||
if ($boxsmallsize <= 1) {
|
||||
$info['warning'][] = 'Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.$atomname.'" at offset: '.($atom_structure['offset'] + $atomoffset);
|
||||
$info['warning'][] = 'Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset);
|
||||
$atom_structure['data'] = null;
|
||||
$atomoffset = strlen($atom_data);
|
||||
break;
|
||||
|
@ -380,7 +328,7 @@ class getid3_quicktime extends getid3_handler
|
|||
$atom_structure['data'] = $boxsmalldata;
|
||||
break;
|
||||
default:
|
||||
$info['warning'][] = 'Unknown QuickTime smallbox type: "'.getid3_lib::PrintHexBytes($boxsmalltype).'" at offset '.$baseoffset;
|
||||
$info['warning'][] = 'Unknown QuickTime smallbox type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxsmalltype).'" ('.trim(getid3_lib::PrintHexBytes($boxsmalltype)).') at offset '.$baseoffset;
|
||||
$atom_structure['data'] = $atom_data;
|
||||
break;
|
||||
}
|
||||
|
@ -392,7 +340,7 @@ class getid3_quicktime extends getid3_handler
|
|||
$boxtype = substr($atom_data, $atomoffset + 4, 4);
|
||||
$boxdata = substr($atom_data, $atomoffset + 8, $boxsize - 8);
|
||||
if ($boxsize <= 1) {
|
||||
$info['warning'][] = 'Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.$atomname.'" at offset: '.($atom_structure['offset'] + $atomoffset);
|
||||
$info['warning'][] = 'Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset);
|
||||
$atom_structure['data'] = null;
|
||||
$atomoffset = strlen($atom_data);
|
||||
break;
|
||||
|
@ -409,7 +357,7 @@ class getid3_quicktime extends getid3_handler
|
|||
$atom_structure['version'] = getid3_lib::BigEndian2Int(substr($boxdata, 0, 1));
|
||||
$atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($boxdata, 1, 3));
|
||||
switch ($atom_structure['flags_raw']) {
|
||||
case 0: // data flag
|
||||
case 0: // data flag
|
||||
case 21: // tmpo/cpil flag
|
||||
switch ($atomname) {
|
||||
case 'cpil':
|
||||
|
@ -460,17 +408,27 @@ class getid3_quicktime extends getid3_handler
|
|||
}
|
||||
break;
|
||||
|
||||
case 1: // text flag
|
||||
case 1: // text flag
|
||||
case 13: // image flag
|
||||
default:
|
||||
$atom_structure['data'] = substr($boxdata, 8);
|
||||
if ($atomname == 'covr') {
|
||||
// not a foolproof check, but better than nothing
|
||||
if (preg_match('#^\xFF\xD8\xFF#', $atom_structure['data'])) {
|
||||
$atom_structure['image_mime'] = 'image/jpeg';
|
||||
} elseif (preg_match('#^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A#', $atom_structure['data'])) {
|
||||
$atom_structure['image_mime'] = 'image/png';
|
||||
} elseif (preg_match('#^GIF#', $atom_structure['data'])) {
|
||||
$atom_structure['image_mime'] = 'image/gif';
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unknown QuickTime box type: "'.getid3_lib::PrintHexBytes($boxtype).'" at offset '.$baseoffset;
|
||||
$info['warning'][] = 'Unknown QuickTime box type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxtype).'" ('.trim(getid3_lib::PrintHexBytes($boxtype)).') at offset '.$baseoffset;
|
||||
$atom_structure['data'] = $atom_data;
|
||||
|
||||
}
|
||||
|
@ -840,7 +798,12 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
$sttsEntriesDataOffset = 8;
|
||||
//$FrameRateCalculatorArray = array();
|
||||
$frames_count = 0;
|
||||
for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
|
||||
|
||||
$max_stts_entries_to_scan = min(floor($this->getid3->memory_limit / 10000), $atom_structure['number_entries']);
|
||||
if ($max_stts_entries_to_scan < $atom_structure['number_entries']) {
|
||||
$info['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));
|
||||
$sttsEntriesDataOffset += 4;
|
||||
$atom_structure['time_to_sample_table'][$i]['sample_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
|
||||
|
@ -1086,8 +1049,8 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
case 'sync': // SYNChronization atom
|
||||
case 'scpt': // tranSCriPT atom
|
||||
case 'ssrc': // non-primary SouRCe atom
|
||||
for ($i = 0; $i < (strlen($atom_data) % 4); $i++) {
|
||||
$atom_structure['track_id'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $i * 4, 4));
|
||||
for ($i = 0; $i < strlen($atom_data); $i += 4) {
|
||||
@$atom_structure['track_id'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4));
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1260,10 +1223,76 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
break;
|
||||
|
||||
case 'mdat': // Media DATa atom
|
||||
// 'mdat' contains the actual data for the audio/video, possibly also subtitles
|
||||
|
||||
/* due to lack of known documentation, this is a kludge implementation. If you know of documentation on how mdat is properly structed, please send it to info@getid3.org */
|
||||
|
||||
// first, skip any 'wide' padding, and second 'mdat' header (with specified size of zero?)
|
||||
$mdat_offset = 0;
|
||||
while (true) {
|
||||
if (substr($atom_data, $mdat_offset, 8) == "\x00\x00\x00\x08".'wide') {
|
||||
$mdat_offset += 8;
|
||||
} elseif (substr($atom_data, $mdat_offset, 8) == "\x00\x00\x00\x00".'mdat') {
|
||||
$mdat_offset += 8;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check to see if it looks like chapter titles, in the form of unterminated strings with a leading 16-bit size field
|
||||
while (($chapter_string_length = getid3_lib::BigEndian2Int(substr($atom_data, $mdat_offset, 2)))
|
||||
&& ($chapter_string_length < 1000)
|
||||
&& ($chapter_string_length <= (strlen($atom_data) - $mdat_offset - 2))
|
||||
&& preg_match('#^[\x20-\xFF]+$#', substr($atom_data, $mdat_offset + 2, $chapter_string_length), $chapter_matches)) {
|
||||
$mdat_offset += (2 + $chapter_string_length);
|
||||
@$info['quicktime']['comments']['chapters'][] = $chapter_matches[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
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;
|
||||
$OldAVDataEnd = $info['avdataend'];
|
||||
$info['avdataend'] = $atom_structure['offset'] + $atom_structure['size']; // $info['quicktime'][$atomname]['offset'] + $info['quicktime'][$atomname]['size'];
|
||||
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
|
||||
$getid3_temp->info['avdataend'] = $info['avdataend'];
|
||||
$getid3_mp3 = new getid3_mp3($getid3_temp);
|
||||
if ($getid3_mp3->MPEGaudioHeaderValid($getid3_mp3->MPEGaudioHeaderDecode($this->fread(4)))) {
|
||||
$getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
|
||||
if (!empty($getid3_temp->info['warning'])) {
|
||||
foreach ($getid3_temp->info['warning'] as $value) {
|
||||
$info['warning'][] = $value;
|
||||
}
|
||||
}
|
||||
if (!empty($getid3_temp->info['mpeg'])) {
|
||||
$info['mpeg'] = $getid3_temp->info['mpeg'];
|
||||
if (isset($info['mpeg']['audio'])) {
|
||||
$info['audio']['dataformat'] = 'mp3';
|
||||
$info['audio']['codec'] = (!empty($info['mpeg']['audio']['encoder']) ? $info['mpeg']['audio']['encoder'] : (!empty($info['mpeg']['audio']['codec']) ? $info['mpeg']['audio']['codec'] : (!empty($info['mpeg']['audio']['LAME']) ? 'LAME' :'mp3')));
|
||||
$info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
|
||||
$info['audio']['channels'] = $info['mpeg']['audio']['channels'];
|
||||
$info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
|
||||
$info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
|
||||
$info['bitrate'] = $info['audio']['bitrate'];
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($getid3_mp3, $getid3_temp);
|
||||
$info['avdataend'] = $OldAVDataEnd;
|
||||
unset($OldAVDataEnd);
|
||||
|
||||
}
|
||||
|
||||
unset($mdat_offset, $chapter_string_length, $chapter_matches);
|
||||
break;
|
||||
|
||||
case 'free': // FREE space atom
|
||||
case 'skip': // SKIP atom
|
||||
case 'wide': // 64-bit expansion placeholder atom
|
||||
// 'mdat' data is too big to deal with, contains no useful metadata
|
||||
// 'free', 'skip' and 'wide' are just padding, contains no useful data at all
|
||||
|
||||
// When writing QuickTime files, it is sometimes necessary to update an atom's size.
|
||||
|
@ -1329,7 +1358,7 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
//$atom_structure['data'] = $atom_data;
|
||||
break;
|
||||
|
||||
case '©xyz': // GPS latitude+longitude+altitude
|
||||
case "\xA9".'xyz': // GPS latitude+longitude+altitude
|
||||
$atom_structure['data'] = $atom_data;
|
||||
if (preg_match('#([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)?/$#i', $atom_data, $matches)) {
|
||||
@list($all, $latitude, $longitude, $altitude) = $matches;
|
||||
|
@ -1358,16 +1387,12 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
$info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']);
|
||||
}
|
||||
break;
|
||||
case 'NCHD': // MakerNoteVersion
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
|
||||
$atom_structure['data'] = $atom_data;
|
||||
break;
|
||||
case 'NCTG': // NikonTags
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
|
||||
case 'NCTG': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
|
||||
$atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data);
|
||||
break;
|
||||
case 'NCDB': // NikonTags
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
|
||||
case 'NCHD': // Nikon:MakerNoteVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
|
||||
case 'NCDB': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
|
||||
case 'CNCV': // Canon:CompressorVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html
|
||||
$atom_structure['data'] = $atom_data;
|
||||
break;
|
||||
|
||||
|
@ -1391,7 +1416,7 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unknown QuickTime atom type: "'.$atomname.'" ('.trim(getid3_lib::PrintHexBytes($atomname)).') at offset '.$baseoffset;
|
||||
$info['warning'][] = 'Unknown QuickTime atom type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" ('.trim(getid3_lib::PrintHexBytes($atomname)).') at offset '.$baseoffset;
|
||||
$atom_structure['data'] = $atom_data;
|
||||
break;
|
||||
}
|
||||
|
@ -2086,58 +2111,58 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
public function CopyToAppropriateCommentsSection($keyname, $data, $boxname='') {
|
||||
static $handyatomtranslatorarray = array();
|
||||
if (empty($handyatomtranslatorarray)) {
|
||||
$handyatomtranslatorarray['©cpy'] = 'copyright';
|
||||
$handyatomtranslatorarray['©day'] = 'creation_date'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['©dir'] = 'director';
|
||||
$handyatomtranslatorarray['©ed1'] = 'edit1';
|
||||
$handyatomtranslatorarray['©ed2'] = 'edit2';
|
||||
$handyatomtranslatorarray['©ed3'] = 'edit3';
|
||||
$handyatomtranslatorarray['©ed4'] = 'edit4';
|
||||
$handyatomtranslatorarray['©ed5'] = 'edit5';
|
||||
$handyatomtranslatorarray['©ed6'] = 'edit6';
|
||||
$handyatomtranslatorarray['©ed7'] = 'edit7';
|
||||
$handyatomtranslatorarray['©ed8'] = 'edit8';
|
||||
$handyatomtranslatorarray['©ed9'] = 'edit9';
|
||||
$handyatomtranslatorarray['©fmt'] = 'format';
|
||||
$handyatomtranslatorarray['©inf'] = 'information';
|
||||
$handyatomtranslatorarray['©prd'] = 'producer';
|
||||
$handyatomtranslatorarray['©prf'] = 'performers';
|
||||
$handyatomtranslatorarray['©req'] = 'system_requirements';
|
||||
$handyatomtranslatorarray['©src'] = 'source_credit';
|
||||
$handyatomtranslatorarray['©wrt'] = 'writer';
|
||||
$handyatomtranslatorarray["\xA9".'cpy'] = 'copyright';
|
||||
$handyatomtranslatorarray["\xA9".'day'] = 'creation_date'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'dir'] = 'director';
|
||||
$handyatomtranslatorarray["\xA9".'ed1'] = 'edit1';
|
||||
$handyatomtranslatorarray["\xA9".'ed2'] = 'edit2';
|
||||
$handyatomtranslatorarray["\xA9".'ed3'] = 'edit3';
|
||||
$handyatomtranslatorarray["\xA9".'ed4'] = 'edit4';
|
||||
$handyatomtranslatorarray["\xA9".'ed5'] = 'edit5';
|
||||
$handyatomtranslatorarray["\xA9".'ed6'] = 'edit6';
|
||||
$handyatomtranslatorarray["\xA9".'ed7'] = 'edit7';
|
||||
$handyatomtranslatorarray["\xA9".'ed8'] = 'edit8';
|
||||
$handyatomtranslatorarray["\xA9".'ed9'] = 'edit9';
|
||||
$handyatomtranslatorarray["\xA9".'fmt'] = 'format';
|
||||
$handyatomtranslatorarray["\xA9".'inf'] = 'information';
|
||||
$handyatomtranslatorarray["\xA9".'prd'] = 'producer';
|
||||
$handyatomtranslatorarray["\xA9".'prf'] = 'performers';
|
||||
$handyatomtranslatorarray["\xA9".'req'] = 'system_requirements';
|
||||
$handyatomtranslatorarray["\xA9".'src'] = 'source_credit';
|
||||
$handyatomtranslatorarray["\xA9".'wrt'] = 'writer';
|
||||
|
||||
// http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
|
||||
$handyatomtranslatorarray['©nam'] = 'title'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['©cmt'] = 'comment'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['©wrn'] = 'warning';
|
||||
$handyatomtranslatorarray['©hst'] = 'host_computer';
|
||||
$handyatomtranslatorarray['©mak'] = 'make';
|
||||
$handyatomtranslatorarray['©mod'] = 'model';
|
||||
$handyatomtranslatorarray['©PRD'] = 'product';
|
||||
$handyatomtranslatorarray['©swr'] = 'software';
|
||||
$handyatomtranslatorarray['©aut'] = 'author';
|
||||
$handyatomtranslatorarray['©ART'] = 'artist';
|
||||
$handyatomtranslatorarray['©trk'] = 'track';
|
||||
$handyatomtranslatorarray['©alb'] = 'album'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['©com'] = 'comment';
|
||||
$handyatomtranslatorarray['©gen'] = 'genre'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['©ope'] = 'composer';
|
||||
$handyatomtranslatorarray['©url'] = 'url';
|
||||
$handyatomtranslatorarray['©enc'] = 'encoder';
|
||||
$handyatomtranslatorarray["\xA9".'nam'] = 'title'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'cmt'] = 'comment'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'wrn'] = 'warning';
|
||||
$handyatomtranslatorarray["\xA9".'hst'] = 'host_computer';
|
||||
$handyatomtranslatorarray["\xA9".'mak'] = 'make';
|
||||
$handyatomtranslatorarray["\xA9".'mod'] = 'model';
|
||||
$handyatomtranslatorarray["\xA9".'PRD'] = 'product';
|
||||
$handyatomtranslatorarray["\xA9".'swr'] = 'software';
|
||||
$handyatomtranslatorarray["\xA9".'aut'] = 'author';
|
||||
$handyatomtranslatorarray["\xA9".'ART'] = 'artist';
|
||||
$handyatomtranslatorarray["\xA9".'trk'] = 'track';
|
||||
$handyatomtranslatorarray["\xA9".'alb'] = 'album'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'com'] = 'comment';
|
||||
$handyatomtranslatorarray["\xA9".'gen'] = 'genre'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'ope'] = 'composer';
|
||||
$handyatomtranslatorarray["\xA9".'url'] = 'url';
|
||||
$handyatomtranslatorarray["\xA9".'enc'] = 'encoder';
|
||||
|
||||
// http://atomicparsley.sourceforge.net/mpeg-4files.html
|
||||
$handyatomtranslatorarray['©art'] = 'artist'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'art'] = 'artist'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['aART'] = 'album_artist';
|
||||
$handyatomtranslatorarray['trkn'] = 'track_number'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['disk'] = 'disc_number'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['gnre'] = 'genre'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['©too'] = 'encoder'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'too'] = 'encoder'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['tmpo'] = 'bpm'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['cprt'] = 'copyright'; // iTunes 4.0?
|
||||
$handyatomtranslatorarray['cpil'] = 'compilation'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['covr'] = 'picture'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['rtng'] = 'rating'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['©grp'] = 'grouping'; // iTunes 4.2
|
||||
$handyatomtranslatorarray["\xA9".'grp'] = 'grouping'; // iTunes 4.2
|
||||
$handyatomtranslatorarray['stik'] = 'stik'; // iTunes 4.9
|
||||
$handyatomtranslatorarray['pcst'] = 'podcast'; // iTunes 4.9
|
||||
$handyatomtranslatorarray['catg'] = 'category'; // iTunes 4.9
|
||||
|
@ -2145,7 +2170,7 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
$handyatomtranslatorarray['purl'] = 'podcast_url'; // iTunes 4.9
|
||||
$handyatomtranslatorarray['egid'] = 'episode_guid'; // iTunes 4.9
|
||||
$handyatomtranslatorarray['desc'] = 'description'; // iTunes 5.0
|
||||
$handyatomtranslatorarray['©lyr'] = 'lyrics'; // iTunes 5.0
|
||||
$handyatomtranslatorarray["\xA9".'lyr'] = 'lyrics'; // iTunes 5.0
|
||||
$handyatomtranslatorarray['tvnn'] = 'tv_network_name'; // iTunes 6.0
|
||||
$handyatomtranslatorarray['tvsh'] = 'tv_show_name'; // iTunes 6.0
|
||||
$handyatomtranslatorarray['tvsn'] = 'tv_season'; // iTunes 6.0
|
||||
|
@ -2218,4 +2243,4 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
return substr($pascalstring, 1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
/// 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 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
@ -26,8 +27,9 @@ 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
|
||||
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
@ -58,7 +60,8 @@ class getid3_riff extends getid3_handler
|
|||
switch ($RIFFtype) {
|
||||
|
||||
case 'FORM': // AIFF, AIFC
|
||||
$info['fileformat'] = 'aiff';
|
||||
//$info['fileformat'] = 'aiff';
|
||||
$this->container = 'aiff';
|
||||
$thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
|
||||
$thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
|
||||
break;
|
||||
|
@ -66,13 +69,18 @@ class getid3_riff extends getid3_handler
|
|||
case 'RIFF': // AVI, WAV, etc
|
||||
case 'SDSS': // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
|
||||
case 'RMP3': // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
|
||||
$info['fileformat'] = 'riff';
|
||||
//$info['fileformat'] = 'riff';
|
||||
$this->container = 'riff';
|
||||
$thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
|
||||
if ($RIFFsubtype == 'RMP3') {
|
||||
// RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
|
||||
$RIFFsubtype = 'WAVE';
|
||||
}
|
||||
$thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
|
||||
if ($RIFFsubtype != 'AMV ') {
|
||||
// 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
|
||||
// Handled separately in ParseRIFFAMV()
|
||||
$thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
|
||||
}
|
||||
if (($info['avdataend'] - $info['filesize']) == 1) {
|
||||
// LiteWave appears to incorrectly *not* pad actual output file
|
||||
// to nearest WORD boundary so may appear to be short by one
|
||||
|
@ -110,16 +118,19 @@ class getid3_riff extends getid3_handler
|
|||
$nextRIFFoffset = $chunkdata['offset'] + $chunkdata['size'];
|
||||
|
||||
switch ($nextRIFFheaderID) {
|
||||
|
||||
case 'RIFF':
|
||||
$chunkdata['chunks'] = $this->ParseRIFF($chunkdata['offset'] + 4, $nextRIFFoffset);
|
||||
|
||||
if (!isset($thisfile_riff[$nextRIFFtype])) {
|
||||
$thisfile_riff[$nextRIFFtype] = array();
|
||||
}
|
||||
$thisfile_riff[$nextRIFFtype][] = $chunkdata;
|
||||
break;
|
||||
|
||||
case 'AMV ':
|
||||
unset($info['riff']);
|
||||
$info['amv'] = $this->ParseRIFFAMV($chunkdata['offset'] + 4, $nextRIFFoffset);
|
||||
break;
|
||||
|
||||
case 'JUNK':
|
||||
// ignore
|
||||
$thisfile_riff[$nextRIFFheaderID][] = $chunkdata;
|
||||
|
@ -152,13 +163,17 @@ class getid3_riff extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->error('Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "'.$RIFFsubtype.'" instead');
|
||||
unset($info['fileformat']);
|
||||
//unset($info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$streamindex = 0;
|
||||
switch ($RIFFsubtype) {
|
||||
|
||||
// http://en.wikipedia.org/wiki/Wav
|
||||
case 'WAVE':
|
||||
$info['fileformat'] = 'wav';
|
||||
|
||||
if (empty($thisfile_audio['bitrate_mode'])) {
|
||||
$thisfile_audio['bitrate_mode'] = 'cbr';
|
||||
}
|
||||
|
@ -588,10 +603,13 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
break;
|
||||
|
||||
// http://en.wikipedia.org/wiki/Audio_Video_Interleave
|
||||
case 'AVI ':
|
||||
$info['fileformat'] = 'avi';
|
||||
$info['mime_type'] = 'video/avi';
|
||||
|
||||
$thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably
|
||||
$thisfile_video['dataformat'] = 'avi';
|
||||
$info['mime_type'] = 'video/avi';
|
||||
|
||||
if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) {
|
||||
$info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8;
|
||||
|
@ -825,7 +843,7 @@ class getid3_riff extends getid3_handler
|
|||
|
||||
switch ($strhfccType) {
|
||||
case 'vids':
|
||||
$thisfile_riff_raw_strf_strhfccType_streamindex = self::ParseBITMAPINFOHEADER(substr($strfData, 0, 40), ($info['fileformat'] == 'riff'));
|
||||
$thisfile_riff_raw_strf_strhfccType_streamindex = self::ParseBITMAPINFOHEADER(substr($strfData, 0, 40), ($this->container == 'riff'));
|
||||
$thisfile_video['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount'];
|
||||
|
||||
if ($thisfile_riff_video_current['codec'] == 'DV') {
|
||||
|
@ -875,11 +893,28 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'AMV ':
|
||||
$info['fileformat'] = 'amv';
|
||||
$info['mime_type'] = 'video/amv';
|
||||
|
||||
$thisfile_video['bitrate_mode'] = 'vbr'; // it's MJPEG, presumably contant-quality encoding, thereby VBR
|
||||
$thisfile_video['dataformat'] = 'mjpeg';
|
||||
$thisfile_video['codec'] = 'mjpeg';
|
||||
$thisfile_video['lossless'] = false;
|
||||
$thisfile_video['bits_per_sample'] = 24;
|
||||
|
||||
$thisfile_audio['dataformat'] = 'adpcm';
|
||||
$thisfile_audio['lossless'] = false;
|
||||
break;
|
||||
|
||||
|
||||
// http://en.wikipedia.org/wiki/CD-DA
|
||||
case 'CDDA':
|
||||
$thisfile_audio['bitrate_mode'] = 'cbr';
|
||||
$info['fileformat'] = 'cda';
|
||||
unset($info['mime_type']);
|
||||
|
||||
$thisfile_audio_dataformat = 'cda';
|
||||
$thisfile_audio['lossless'] = true;
|
||||
unset($info['mime_type']);
|
||||
|
||||
$info['avdataoffset'] = 44;
|
||||
|
||||
|
@ -901,6 +936,7 @@ class getid3_riff extends getid3_handler
|
|||
$info['playtime_seconds'] = $thisfile_riff_CDDA_fmt_0['playtime_seconds'];
|
||||
|
||||
// hardcoded data for CD-audio
|
||||
$thisfile_audio['lossless'] = true;
|
||||
$thisfile_audio['sample_rate'] = 44100;
|
||||
$thisfile_audio['channels'] = 2;
|
||||
$thisfile_audio['bits_per_sample'] = 16;
|
||||
|
@ -909,13 +945,15 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
break;
|
||||
|
||||
|
||||
// http://en.wikipedia.org/wiki/AIFF
|
||||
case 'AIFF':
|
||||
case 'AIFC':
|
||||
$info['fileformat'] = 'aiff';
|
||||
$info['mime_type'] = 'audio/x-aiff';
|
||||
|
||||
$thisfile_audio['bitrate_mode'] = 'cbr';
|
||||
$thisfile_audio_dataformat = 'aiff';
|
||||
$thisfile_audio['lossless'] = true;
|
||||
$info['mime_type'] = 'audio/x-aiff';
|
||||
|
||||
if (isset($thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'])) {
|
||||
$info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'] + 8;
|
||||
|
@ -1028,12 +1066,15 @@ class getid3_riff extends getid3_handler
|
|||
*/
|
||||
break;
|
||||
|
||||
// http://en.wikipedia.org/wiki/8SVX
|
||||
case '8SVX':
|
||||
$info['fileformat'] = '8svx';
|
||||
$info['mime_type'] = 'audio/8svx';
|
||||
|
||||
$thisfile_audio['bitrate_mode'] = 'cbr';
|
||||
$thisfile_audio_dataformat = '8svx';
|
||||
$thisfile_audio['bits_per_sample'] = 8;
|
||||
$thisfile_audio['channels'] = 1; // overridden below, if need be
|
||||
$info['mime_type'] = 'audio/x-aiff';
|
||||
|
||||
if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) {
|
||||
$info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8;
|
||||
|
@ -1108,31 +1149,31 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'CDXA':
|
||||
$info['mime_type'] = 'video/mpeg';
|
||||
$info['fileformat'] = 'vcd'; // Asume Video CD
|
||||
$info['mime_type'] = 'video/mpeg';
|
||||
|
||||
if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) {
|
||||
if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, false)) {
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_mpeg = new getid3_mpeg($getid3_temp);
|
||||
$getid3_mpeg->Analyze();
|
||||
if (empty($getid3_temp->info['error'])) {
|
||||
$info['audio'] = $getid3_temp->info['audio'];
|
||||
$info['video'] = $getid3_temp->info['video'];
|
||||
$info['mpeg'] = $getid3_temp->info['mpeg'];
|
||||
$info['warning'] = $getid3_temp->info['warning'];
|
||||
}
|
||||
unset($getid3_temp, $getid3_mpeg);
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, true);
|
||||
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_mpeg = new getid3_mpeg($getid3_temp);
|
||||
$getid3_mpeg->Analyze();
|
||||
if (empty($getid3_temp->info['error'])) {
|
||||
$info['audio'] = $getid3_temp->info['audio'];
|
||||
$info['video'] = $getid3_temp->info['video'];
|
||||
$info['mpeg'] = $getid3_temp->info['mpeg'];
|
||||
$info['warning'] = $getid3_temp->info['warning'];
|
||||
}
|
||||
unset($getid3_temp, $getid3_mpeg);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "'.$RIFFsubtype.'" instead';
|
||||
unset($info['fileformat']);
|
||||
break;
|
||||
//unset($info['fileformat']);
|
||||
}
|
||||
|
||||
switch ($RIFFsubtype) {
|
||||
|
@ -1150,6 +1191,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_id3v2 = new getid3_id3v2($getid3_temp);
|
||||
|
@ -1278,6 +1320,115 @@ class getid3_riff extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// https://code.google.com/p/amv-codec-tools/wiki/AmvDocumentation
|
||||
//typedef struct _amvmainheader {
|
||||
//FOURCC fcc; // 'amvh'
|
||||
//DWORD cb;
|
||||
//DWORD dwMicroSecPerFrame;
|
||||
//BYTE reserve[28];
|
||||
//DWORD dwWidth;
|
||||
//DWORD dwHeight;
|
||||
//DWORD dwSpeed;
|
||||
//DWORD reserve0;
|
||||
//DWORD reserve1;
|
||||
//BYTE bTimeSec;
|
||||
//BYTE bTimeMin;
|
||||
//WORD wTimeHour;
|
||||
//} AMVMAINHEADER;
|
||||
|
||||
$info = &$this->getid3->info;
|
||||
$RIFFchunk = false;
|
||||
|
||||
try {
|
||||
|
||||
$this->fseek($startoffset);
|
||||
$maxoffset = min($maxoffset, $info['avdataend']);
|
||||
$AMVheader = $this->fread(284);
|
||||
if (substr($AMVheader, 0, 8) != 'hdrlamvh') {
|
||||
throw new Exception('expecting "hdrlamv" at offset '.($startoffset + 0).', found "'.substr($AMVheader, 0, 8).'"');
|
||||
}
|
||||
if (substr($AMVheader, 8, 4) != "\x38\x00\x00\x00") { // "amvh" chunk size, hardcoded to 0x38 = 56 bytes
|
||||
throw new Exception('expecting "0x38000000" at offset '.($startoffset + 8).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 8, 4)).'"');
|
||||
}
|
||||
$RIFFchunk = array();
|
||||
$RIFFchunk['amvh']['us_per_frame'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 12, 4));
|
||||
$RIFFchunk['amvh']['reserved28'] = substr($AMVheader, 16, 28); // null? reserved?
|
||||
$RIFFchunk['amvh']['resolution_x'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 44, 4));
|
||||
$RIFFchunk['amvh']['resolution_y'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 48, 4));
|
||||
$RIFFchunk['amvh']['frame_rate_int'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 52, 4));
|
||||
$RIFFchunk['amvh']['reserved0'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 56, 4)); // 1? reserved?
|
||||
$RIFFchunk['amvh']['reserved1'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 60, 4)); // 0? reserved?
|
||||
$RIFFchunk['amvh']['runtime_sec'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 64, 1));
|
||||
$RIFFchunk['amvh']['runtime_min'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 65, 1));
|
||||
$RIFFchunk['amvh']['runtime_hrs'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 66, 2));
|
||||
|
||||
$info['video']['frame_rate'] = 1000000 / $RIFFchunk['amvh']['us_per_frame'];
|
||||
$info['video']['resolution_x'] = $RIFFchunk['amvh']['resolution_x'];
|
||||
$info['video']['resolution_y'] = $RIFFchunk['amvh']['resolution_y'];
|
||||
$info['playtime_seconds'] = ($RIFFchunk['amvh']['runtime_hrs'] * 3600) + ($RIFFchunk['amvh']['runtime_min'] * 60) + $RIFFchunk['amvh']['runtime_sec'];
|
||||
|
||||
// the rest is all hardcoded(?) and does not appear to be useful until you get to audio info at offset 256, even then everything is probably hardcoded
|
||||
|
||||
if (substr($AMVheader, 68, 20) != 'LIST'."\x00\x00\x00\x00".'strlstrh'."\x38\x00\x00\x00") {
|
||||
throw new Exception('expecting "LIST<0x00000000>strlstrh<0x38000000>" at offset '.($startoffset + 68).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 68, 20)).'"');
|
||||
}
|
||||
// followed by 56 bytes of null: substr($AMVheader, 88, 56) -> 144
|
||||
if (substr($AMVheader, 144, 8) != 'strf'."\x24\x00\x00\x00") {
|
||||
throw new Exception('expecting "strf<0x24000000>" at offset '.($startoffset + 144).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 144, 8)).'"');
|
||||
}
|
||||
// followed by 36 bytes of null: substr($AMVheader, 144, 36) -> 180
|
||||
|
||||
if (substr($AMVheader, 188, 20) != 'LIST'."\x00\x00\x00\x00".'strlstrh'."\x30\x00\x00\x00") {
|
||||
throw new Exception('expecting "LIST<0x00000000>strlstrh<0x30000000>" at offset '.($startoffset + 188).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 188, 20)).'"');
|
||||
}
|
||||
// followed by 48 bytes of null: substr($AMVheader, 208, 48) -> 256
|
||||
if (substr($AMVheader, 256, 8) != 'strf'."\x14\x00\x00\x00") {
|
||||
throw new Exception('expecting "strf<0x14000000>" at offset '.($startoffset + 256).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 256, 8)).'"');
|
||||
}
|
||||
// followed by 20 bytes of a modified WAVEFORMATEX:
|
||||
// typedef struct {
|
||||
// WORD wFormatTag; //(Fixme: this is equal to PCM's 0x01 format code)
|
||||
// WORD nChannels; //(Fixme: this is always 1)
|
||||
// DWORD nSamplesPerSec; //(Fixme: for all known sample files this is equal to 22050)
|
||||
// DWORD nAvgBytesPerSec; //(Fixme: for all known sample files this is equal to 44100)
|
||||
// WORD nBlockAlign; //(Fixme: this seems to be 2 in AMV files, is this correct ?)
|
||||
// WORD wBitsPerSample; //(Fixme: this seems to be 16 in AMV files instead of the expected 4)
|
||||
// WORD cbSize; //(Fixme: this seems to be 0 in AMV files)
|
||||
// WORD reserved;
|
||||
// } WAVEFORMATEX;
|
||||
$RIFFchunk['strf']['wformattag'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 264, 2));
|
||||
$RIFFchunk['strf']['nchannels'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 266, 2));
|
||||
$RIFFchunk['strf']['nsamplespersec'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 268, 4));
|
||||
$RIFFchunk['strf']['navgbytespersec'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 272, 4));
|
||||
$RIFFchunk['strf']['nblockalign'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 276, 2));
|
||||
$RIFFchunk['strf']['wbitspersample'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 278, 2));
|
||||
$RIFFchunk['strf']['cbsize'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 280, 2));
|
||||
$RIFFchunk['strf']['reserved'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 282, 2));
|
||||
|
||||
|
||||
$info['audio']['lossless'] = false;
|
||||
$info['audio']['sample_rate'] = $RIFFchunk['strf']['nsamplespersec'];
|
||||
$info['audio']['channels'] = $RIFFchunk['strf']['nchannels'];
|
||||
$info['audio']['bits_per_sample'] = $RIFFchunk['strf']['wbitspersample'];
|
||||
$info['audio']['bitrate'] = $info['audio']['sample_rate'] * $info['audio']['channels'] * $info['audio']['bits_per_sample'];
|
||||
$info['audio']['bitrate_mode'] = 'cbr';
|
||||
|
||||
|
||||
} catch (getid3_exception $e) {
|
||||
if ($e->getCode() == 10) {
|
||||
$this->warning('RIFFAMV parser: '.$e->getMessage());
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
return $RIFFchunk;
|
||||
}
|
||||
|
||||
|
||||
public function ParseRIFF($startoffset, $maxoffset) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -1329,7 +1480,7 @@ class getid3_riff extends getid3_handler
|
|||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
|
||||
$getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
|
||||
$getid3_mp3 = new getid3_mp3($getid3_temp);
|
||||
$getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
|
||||
$getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
|
||||
if (isset($getid3_temp->info['mpeg']['audio'])) {
|
||||
$info['mpeg']['audio'] = $getid3_temp->info['mpeg']['audio'];
|
||||
|
@ -1412,7 +1563,7 @@ class getid3_riff extends getid3_handler
|
|||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
|
||||
$getid3_temp->info['avdataend'] = $info['avdataend'];
|
||||
$getid3_mp3 = new getid3_mp3($getid3_temp);
|
||||
$getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
|
||||
$getid3_mp3->getOnlyMPEGaudioInfo($info['avdataoffset'], false);
|
||||
if (empty($getid3_temp->info['error'])) {
|
||||
$info['audio'] = $getid3_temp->info['audio'];
|
||||
|
@ -2426,10 +2577,10 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
|
||||
private function EitherEndian2Int($byteword, $signed=false) {
|
||||
if ($this->getid3->info['fileformat'] == 'riff') {
|
||||
if ($this->container == 'riff') {
|
||||
return getid3_lib::LittleEndian2Int($byteword, $signed);
|
||||
}
|
||||
return getid3_lib::BigEndian2Int($byteword, false, $signed);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
/// 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 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
@ -470,4 +471,4 @@ class getid3_ac3 extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
/// 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 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
@ -287,4 +288,4 @@ class getid3_dts extends getid3_handler
|
|||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
/// 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 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
@ -439,4 +440,4 @@ class getid3_flac extends getid3_handler
|
|||
return (isset($lookup[$type_id]) ? $lookup[$type_id] : 'reserved');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
/// 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 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
@ -95,8 +96,8 @@ class getid3_mp3 extends getid3_handler
|
|||
|
||||
// Not sure what version of LAME this is - look in padding of last frame for longer version string
|
||||
$PossibleLAMEversionStringOffset = $info['avdataend'] - $PossiblyLongerLAMEversion_FrameLength;
|
||||
fseek($this->getid3->fp, $PossibleLAMEversionStringOffset);
|
||||
$PossiblyLongerLAMEversion_Data = fread($this->getid3->fp, $PossiblyLongerLAMEversion_FrameLength);
|
||||
$this->fseek($PossibleLAMEversionStringOffset);
|
||||
$PossiblyLongerLAMEversion_Data = $this->fread($PossiblyLongerLAMEversion_FrameLength);
|
||||
switch (substr($CurrentDataLAMEversionString, -1)) {
|
||||
case 'a':
|
||||
case 'b':
|
||||
|
@ -422,12 +423,12 @@ class getid3_mp3 extends getid3_handler
|
|||
$MPEGaudioEmphasisLookup = self::MPEGaudioEmphasisArray();
|
||||
}
|
||||
|
||||
if (fseek($this->getid3->fp, $offset, SEEK_SET) != 0) {
|
||||
if ($this->fseek($offset) != 0) {
|
||||
$info['error'][] = 'decodeMPEGaudioHeader() failed to seek to next offset at '.$offset;
|
||||
return false;
|
||||
}
|
||||
//$headerstring = fread($this->getid3->fp, 1441); // worst-case max length = 32kHz @ 320kbps layer 3 = 1441 bytes/frame
|
||||
$headerstring = fread($this->getid3->fp, 226); // LAME header at offset 36 + 190 bytes of Xing/LAME data
|
||||
//$headerstring = $this->fread(1441); // worst-case max length = 32kHz @ 320kbps layer 3 = 1441 bytes/frame
|
||||
$headerstring = $this->fread(226); // LAME header at offset 36 + 190 bytes of Xing/LAME data
|
||||
|
||||
// MP3 audio frame structure:
|
||||
// $aa $aa $aa $aa [$bb $bb] $cc...
|
||||
|
@ -890,19 +891,21 @@ class getid3_mp3 extends getid3_handler
|
|||
|
||||
if (($ExpectedNumberOfAudioBytes > 0) && ($ExpectedNumberOfAudioBytes != ($info['avdataend'] - $info['avdataoffset']))) {
|
||||
if ($ExpectedNumberOfAudioBytes > ($info['avdataend'] - $info['avdataoffset'])) {
|
||||
if (isset($info['fileformat']) && ($info['fileformat'] == 'riff')) {
|
||||
if ($this->isDependencyFor('matroska') || $this->isDependencyFor('riff')) {
|
||||
// ignore, audio data is broken into chunks so will always be data "missing"
|
||||
} elseif (($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])) == 1) {
|
||||
$info['warning'][] = 'Last byte of data truncated (this is a known bug in Meracl ID3 Tag Writer before v1.3.5)';
|
||||
} else {
|
||||
$info['warning'][] = 'Probable truncated file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' (short by '.($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])).' bytes)';
|
||||
}
|
||||
elseif (($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])) == 1) {
|
||||
$this->warning('Last byte of data truncated (this is a known bug in Meracl ID3 Tag Writer before v1.3.5)');
|
||||
}
|
||||
else {
|
||||
$this->warning('Probable truncated file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' (short by '.($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])).' bytes)');
|
||||
}
|
||||
} else {
|
||||
if ((($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes) == 1) {
|
||||
// $prenullbytefileoffset = ftell($this->getid3->fp);
|
||||
// fseek($this->getid3->fp, $info['avdataend'], SEEK_SET);
|
||||
// $PossibleNullByte = fread($this->getid3->fp, 1);
|
||||
// fseek($this->getid3->fp, $prenullbytefileoffset, SEEK_SET);
|
||||
// $prenullbytefileoffset = $this->ftell();
|
||||
// $this->fseek($info['avdataend']);
|
||||
// $PossibleNullByte = $this->fread(1);
|
||||
// $this->fseek($prenullbytefileoffset);
|
||||
// if ($PossibleNullByte === "\x00") {
|
||||
$info['avdataend']--;
|
||||
// $info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
|
||||
|
@ -1118,8 +1121,8 @@ class getid3_mp3 extends getid3_handler
|
|||
public function FreeFormatFrameLength($offset, $deepscan=false) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $offset, SEEK_SET);
|
||||
$MPEGaudioData = fread($this->getid3->fp, 32768);
|
||||
$this->fseek($offset);
|
||||
$MPEGaudioData = $this->fread(32768);
|
||||
|
||||
$SyncPattern1 = substr($MPEGaudioData, 0, 4);
|
||||
// may be different pattern due to padding
|
||||
|
@ -1166,8 +1169,8 @@ class getid3_mp3 extends getid3_handler
|
|||
$ActualFrameLengthValues = array();
|
||||
$nextoffset = $offset + $framelength;
|
||||
while ($nextoffset < ($info['avdataend'] - 6)) {
|
||||
fseek($this->getid3->fp, $nextoffset - 1, SEEK_SET);
|
||||
$NextSyncPattern = fread($this->getid3->fp, 6);
|
||||
$this->fseek($nextoffset - 1);
|
||||
$NextSyncPattern = $this->fread(6);
|
||||
if ((substr($NextSyncPattern, 1, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 1, strlen($SyncPattern2)) == $SyncPattern2)) {
|
||||
// good - found where expected
|
||||
$ActualFrameLengthValues[] = $framelength;
|
||||
|
@ -1215,22 +1218,22 @@ class getid3_mp3 extends getid3_handler
|
|||
$Distribution['padding'] = array();
|
||||
|
||||
$info = &$this->getid3->info;
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
||||
$max_frames_scan = 5000;
|
||||
$frames_scanned = 0;
|
||||
|
||||
$previousvalidframe = $info['avdataoffset'];
|
||||
while (ftell($this->getid3->fp) < $info['avdataend']) {
|
||||
while ($this->ftell() < $info['avdataend']) {
|
||||
set_time_limit(30);
|
||||
$head4 = fread($this->getid3->fp, 4);
|
||||
$head4 = $this->fread(4);
|
||||
if (strlen($head4) < 4) {
|
||||
break;
|
||||
}
|
||||
if ($head4{0} != "\xFF") {
|
||||
for ($i = 1; $i < 4; $i++) {
|
||||
if ($head4{$i} == "\xFF") {
|
||||
fseek($this->getid3->fp, $i - 4, SEEK_CUR);
|
||||
$this->fseek($i - 4, SEEK_CUR);
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
@ -1258,9 +1261,9 @@ class getid3_mp3 extends getid3_handler
|
|||
$LongMPEGfrequencyLookup[$head4]);
|
||||
}
|
||||
if ($MPEGaudioHeaderLengthCache[$head4] > 4) {
|
||||
$WhereWeWere = ftell($this->getid3->fp);
|
||||
fseek($this->getid3->fp, $MPEGaudioHeaderLengthCache[$head4] - 4, SEEK_CUR);
|
||||
$next4 = fread($this->getid3->fp, 4);
|
||||
$WhereWeWere = $this->ftell();
|
||||
$this->fseek($MPEGaudioHeaderLengthCache[$head4] - 4, SEEK_CUR);
|
||||
$next4 = $this->fread(4);
|
||||
if ($next4{0} == "\xFF") {
|
||||
if (!isset($MPEGaudioHeaderDecodeCache[$next4])) {
|
||||
$MPEGaudioHeaderDecodeCache[$next4] = self::MPEGaudioHeaderDecode($next4);
|
||||
|
@ -1269,7 +1272,7 @@ class getid3_mp3 extends getid3_handler
|
|||
$MPEGaudioHeaderValidCache[$next4] = self::MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$next4], false, false);
|
||||
}
|
||||
if ($MPEGaudioHeaderValidCache[$next4]) {
|
||||
fseek($this->getid3->fp, -4, SEEK_CUR);
|
||||
$this->fseek(-4, SEEK_CUR);
|
||||
|
||||
getid3_lib::safe_inc($Distribution['bitrate'][$LongMPEGbitrateLookup[$head4]]);
|
||||
getid3_lib::safe_inc($Distribution['layer'][$LongMPEGlayerLookup[$head4]]);
|
||||
|
@ -1277,7 +1280,7 @@ class getid3_mp3 extends getid3_handler
|
|||
getid3_lib::safe_inc($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]);
|
||||
getid3_lib::safe_inc($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]);
|
||||
if ($max_frames_scan && (++$frames_scanned >= $max_frames_scan)) {
|
||||
$pct_data_scanned = (ftell($this->getid3->fp) - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']);
|
||||
$pct_data_scanned = ($this->ftell() - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']);
|
||||
$info['warning'][] = 'too many MPEG audio frames to scan, only scanned first '.$max_frames_scan.' frames ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.';
|
||||
foreach ($Distribution as $key1 => $value1) {
|
||||
foreach ($value1 as $key2 => $value2) {
|
||||
|
@ -1290,7 +1293,7 @@ class getid3_mp3 extends getid3_handler
|
|||
}
|
||||
}
|
||||
unset($next4);
|
||||
fseek($this->getid3->fp, $WhereWeWere - 3, SEEK_SET);
|
||||
$this->fseek($WhereWeWere - 3);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1355,13 +1358,13 @@ class getid3_mp3 extends getid3_handler
|
|||
|
||||
}
|
||||
|
||||
fseek($this->getid3->fp, $avdataoffset, SEEK_SET);
|
||||
$this->fseek($avdataoffset);
|
||||
$sync_seek_buffer_size = min(128 * 1024, $info['avdataend'] - $avdataoffset);
|
||||
if ($sync_seek_buffer_size <= 0) {
|
||||
$info['error'][] = 'Invalid $sync_seek_buffer_size at offset '.$avdataoffset;
|
||||
return false;
|
||||
}
|
||||
$header = fread($this->getid3->fp, $sync_seek_buffer_size);
|
||||
$header = $this->fread($sync_seek_buffer_size);
|
||||
$sync_seek_buffer_size = strlen($header);
|
||||
$SynchSeekOffset = 0;
|
||||
while ($SynchSeekOffset < $sync_seek_buffer_size) {
|
||||
|
@ -1473,7 +1476,7 @@ class getid3_mp3 extends getid3_handler
|
|||
|
||||
$dummy = array('error'=>$info['error'], 'warning'=>$info['warning'], 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
|
||||
$synchstartoffset = $info['avdataoffset'];
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
||||
// you can play with these numbers:
|
||||
$max_frames_scan = 50000;
|
||||
|
@ -1488,13 +1491,13 @@ class getid3_mp3 extends getid3_handler
|
|||
$pct_data_scanned = 0;
|
||||
for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) {
|
||||
$frames_scanned_this_segment = 0;
|
||||
if (ftell($this->getid3->fp) >= $info['avdataend']) {
|
||||
if ($this->ftell() >= $info['avdataend']) {
|
||||
break;
|
||||
}
|
||||
$scan_start_offset[$current_segment] = max(ftell($this->getid3->fp), $info['avdataoffset'] + round($current_segment * (($info['avdataend'] - $info['avdataoffset']) / $max_scan_segments)));
|
||||
$scan_start_offset[$current_segment] = max($this->ftell(), $info['avdataoffset'] + round($current_segment * (($info['avdataend'] - $info['avdataoffset']) / $max_scan_segments)));
|
||||
if ($current_segment > 0) {
|
||||
fseek($this->getid3->fp, $scan_start_offset[$current_segment], SEEK_SET);
|
||||
$buffer_4k = fread($this->getid3->fp, 4096);
|
||||
$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 ($this->decodeMPEGaudioHeader($scan_start_offset[$current_segment] + $j, $dummy, false, false, $FastMode)) {
|
||||
|
@ -1523,7 +1526,7 @@ class getid3_mp3 extends getid3_handler
|
|||
}
|
||||
$frames_scanned++;
|
||||
if ($frames_scan_per_segment && (++$frames_scanned_this_segment >= $frames_scan_per_segment)) {
|
||||
$this_pct_scanned = (ftell($this->getid3->fp) - $scan_start_offset[$current_segment]) / ($info['avdataend'] - $info['avdataoffset']);
|
||||
$this_pct_scanned = ($this->ftell() - $scan_start_offset[$current_segment]) / ($info['avdataend'] - $info['avdataoffset']);
|
||||
if (($current_segment == 0) && (($this_pct_scanned * $max_scan_segments) >= 1)) {
|
||||
// file likely contains < $max_frames_scan, just scan as one segment
|
||||
$max_scan_segments = 1;
|
||||
|
@ -2006,4 +2009,4 @@ class getid3_mp3 extends getid3_handler
|
|||
return (isset($LAMEpresetUsedLookup[$LAMEtag['preset_used_id']]) ? $LAMEpresetUsedLookup[$LAMEtag['preset_used_id']] : 'new/unknown preset: '.$LAMEtag['preset_used_id'].' - report to info@getid3.org');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
/// 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 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
@ -114,6 +115,66 @@ class getid3_ogg extends getid3_handler
|
|||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
}
|
||||
|
||||
} elseif (substr($filedata, 0, 7) == "\x80".'theora') {
|
||||
|
||||
// http://www.theora.org/doc/Theora.pdf (section 6.2)
|
||||
|
||||
$info['ogg']['pageheader']['theora']['theora_magic'] = substr($filedata, $filedataoffset, 7); // hard-coded to "\x80.'theora'
|
||||
$filedataoffset += 7;
|
||||
$info['ogg']['pageheader']['theora']['version_major'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 1));
|
||||
$filedataoffset += 1;
|
||||
$info['ogg']['pageheader']['theora']['version_minor'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 1));
|
||||
$filedataoffset += 1;
|
||||
$info['ogg']['pageheader']['theora']['version_revision'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 1));
|
||||
$filedataoffset += 1;
|
||||
$info['ogg']['pageheader']['theora']['frame_width_macroblocks'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 2));
|
||||
$filedataoffset += 2;
|
||||
$info['ogg']['pageheader']['theora']['frame_height_macroblocks'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 2));
|
||||
$filedataoffset += 2;
|
||||
$info['ogg']['pageheader']['theora']['resolution_x'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 3));
|
||||
$filedataoffset += 3;
|
||||
$info['ogg']['pageheader']['theora']['resolution_y'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 3));
|
||||
$filedataoffset += 3;
|
||||
$info['ogg']['pageheader']['theora']['picture_offset_x'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 1));
|
||||
$filedataoffset += 1;
|
||||
$info['ogg']['pageheader']['theora']['picture_offset_y'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 1));
|
||||
$filedataoffset += 1;
|
||||
$info['ogg']['pageheader']['theora']['frame_rate_numerator'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['pageheader']['theora']['frame_rate_denominator'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['pageheader']['theora']['pixel_aspect_numerator'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 3));
|
||||
$filedataoffset += 3;
|
||||
$info['ogg']['pageheader']['theora']['pixel_aspect_denominator'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 3));
|
||||
$filedataoffset += 3;
|
||||
$info['ogg']['pageheader']['theora']['color_space_id'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 1));
|
||||
$filedataoffset += 1;
|
||||
$info['ogg']['pageheader']['theora']['nominal_bitrate'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 3));
|
||||
$filedataoffset += 3;
|
||||
$info['ogg']['pageheader']['theora']['flags'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 2));
|
||||
$filedataoffset += 2;
|
||||
|
||||
$info['ogg']['pageheader']['theora']['quality'] = ($info['ogg']['pageheader']['theora']['flags'] & 0xFC00) >> 10;
|
||||
$info['ogg']['pageheader']['theora']['kfg_shift'] = ($info['ogg']['pageheader']['theora']['flags'] & 0x03E0) >> 5;
|
||||
$info['ogg']['pageheader']['theora']['pixel_format_id'] = ($info['ogg']['pageheader']['theora']['flags'] & 0x0018) >> 3;
|
||||
$info['ogg']['pageheader']['theora']['reserved'] = ($info['ogg']['pageheader']['theora']['flags'] & 0x0007) >> 0; // should be 0
|
||||
$info['ogg']['pageheader']['theora']['color_space'] = self::TheoraColorSpace($info['ogg']['pageheader']['theora']['color_space_id']);
|
||||
$info['ogg']['pageheader']['theora']['pixel_format'] = self::TheoraPixelFormat($info['ogg']['pageheader']['theora']['pixel_format_id']);
|
||||
|
||||
$info['video']['dataformat'] = 'theora';
|
||||
$info['mime_type'] = 'video/ogg';
|
||||
//$info['audio']['bitrate_mode'] = 'abr';
|
||||
//$info['audio']['lossless'] = false;
|
||||
$info['video']['resolution_x'] = $info['ogg']['pageheader']['theora']['resolution_x'];
|
||||
$info['video']['resolution_y'] = $info['ogg']['pageheader']['theora']['resolution_y'];
|
||||
if ($info['ogg']['pageheader']['theora']['frame_rate_denominator'] > 0) {
|
||||
$info['video']['frame_rate'] = (float) $info['ogg']['pageheader']['theora']['frame_rate_numerator'] / $info['ogg']['pageheader']['theora']['frame_rate_denominator'];
|
||||
}
|
||||
if ($info['ogg']['pageheader']['theora']['pixel_aspect_denominator'] > 0) {
|
||||
$info['video']['pixel_aspect_ratio'] = (float) $info['ogg']['pageheader']['theora']['pixel_aspect_numerator'] / $info['ogg']['pageheader']['theora']['pixel_aspect_denominator'];
|
||||
}
|
||||
$info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of getID3 ['.$this->getid3->version().'] -- bitrate, playtime and all audio data are currently unavailable';
|
||||
|
||||
|
||||
} elseif (substr($filedata, 0, 8) == "fishead\x00") {
|
||||
|
||||
|
@ -172,8 +233,8 @@ class getid3_ogg extends getid3_handler
|
|||
|
||||
} elseif (substr($filedata, 1, 6) == 'theora') {
|
||||
|
||||
$info['video']['dataformat'] = 'theora';
|
||||
$info['error'][] = 'Ogg Theora not correctly handled in this version of getID3 ['.$this->getid3->version().']';
|
||||
$info['video']['dataformat'] = 'theora1';
|
||||
$info['error'][] = 'Ogg Theora (v1) not correctly handled in this version of getID3 ['.$this->getid3->version().']';
|
||||
//break;
|
||||
|
||||
} elseif (substr($filedata, 1, 6) == 'vorbis') {
|
||||
|
@ -668,4 +729,28 @@ class getid3_ogg extends getid3_handler
|
|||
return round($qval, 1); // 5 or 4.9
|
||||
}
|
||||
|
||||
}
|
||||
public static function TheoraColorSpace($colorspace_id) {
|
||||
// http://www.theora.org/doc/Theora.pdf (table 6.3)
|
||||
static $TheoraColorSpaceLookup = array();
|
||||
if (empty($TheoraColorSpaceLookup)) {
|
||||
$TheoraColorSpaceLookup[0] = 'Undefined';
|
||||
$TheoraColorSpaceLookup[1] = 'Rec. 470M';
|
||||
$TheoraColorSpaceLookup[2] = 'Rec. 470BG';
|
||||
$TheoraColorSpaceLookup[3] = 'Reserved';
|
||||
}
|
||||
return (isset($TheoraColorSpaceLookup[$colorspace_id]) ? $TheoraColorSpaceLookup[$colorspace_id] : null);
|
||||
}
|
||||
|
||||
public static function TheoraPixelFormat($pixelformat_id) {
|
||||
// http://www.theora.org/doc/Theora.pdf (table 6.4)
|
||||
static $TheoraPixelFormatLookup = array();
|
||||
if (empty($TheoraPixelFormatLookup)) {
|
||||
$TheoraPixelFormatLookup[0] = '4:2:0';
|
||||
$TheoraPixelFormatLookup[1] = 'Reserved';
|
||||
$TheoraPixelFormatLookup[2] = '4:2:2';
|
||||
$TheoraPixelFormatLookup[3] = '4:4:4';
|
||||
}
|
||||
return (isset($TheoraPixelFormatLookup[$pixelformat_id]) ? $TheoraPixelFormatLookup[$pixelformat_id] : null);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
/// 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 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
@ -32,8 +33,8 @@ class getid3_apetag extends getid3_handler
|
|||
|
||||
if ($this->overrideendoffset == 0) {
|
||||
|
||||
fseek($this->getid3->fp, 0 - $id3v1tagsize - $apetagheadersize - $lyrics3tagsize, SEEK_END);
|
||||
$APEfooterID3v1 = fread($this->getid3->fp, $id3v1tagsize + $apetagheadersize + $lyrics3tagsize);
|
||||
$this->fseek(0 - $id3v1tagsize - $apetagheadersize - $lyrics3tagsize, SEEK_END);
|
||||
$APEfooterID3v1 = $this->fread($id3v1tagsize + $apetagheadersize + $lyrics3tagsize);
|
||||
|
||||
//if (preg_match('/APETAGEX.{24}TAG.{125}$/i', $APEfooterID3v1)) {
|
||||
if (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $id3v1tagsize - $apetagheadersize, 8) == 'APETAGEX') {
|
||||
|
@ -51,8 +52,8 @@ class getid3_apetag extends getid3_handler
|
|||
|
||||
} else {
|
||||
|
||||
fseek($this->getid3->fp, $this->overrideendoffset - $apetagheadersize, SEEK_SET);
|
||||
if (fread($this->getid3->fp, 8) == 'APETAGEX') {
|
||||
$this->fseek($this->overrideendoffset - $apetagheadersize);
|
||||
if ($this->fread(8) == 'APETAGEX') {
|
||||
$info['ape']['tag_offset_end'] = $this->overrideendoffset;
|
||||
}
|
||||
|
||||
|
@ -68,21 +69,21 @@ class getid3_apetag extends getid3_handler
|
|||
// shortcut
|
||||
$thisfile_ape = &$info['ape'];
|
||||
|
||||
fseek($this->getid3->fp, $thisfile_ape['tag_offset_end'] - $apetagheadersize, SEEK_SET);
|
||||
$APEfooterData = fread($this->getid3->fp, 32);
|
||||
$this->fseek($thisfile_ape['tag_offset_end'] - $apetagheadersize);
|
||||
$APEfooterData = $this->fread(32);
|
||||
if (!($thisfile_ape['footer'] = $this->parseAPEheaderFooter($APEfooterData))) {
|
||||
$info['error'][] = 'Error parsing APE footer at offset '.$thisfile_ape['tag_offset_end'];
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($thisfile_ape['footer']['flags']['header']) && $thisfile_ape['footer']['flags']['header']) {
|
||||
fseek($this->getid3->fp, $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'] - $apetagheadersize, SEEK_SET);
|
||||
$thisfile_ape['tag_offset_start'] = ftell($this->getid3->fp);
|
||||
$APEtagData = fread($this->getid3->fp, $thisfile_ape['footer']['raw']['tagsize'] + $apetagheadersize);
|
||||
$this->fseek($thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'] - $apetagheadersize);
|
||||
$thisfile_ape['tag_offset_start'] = $this->ftell();
|
||||
$APEtagData = $this->fread($thisfile_ape['footer']['raw']['tagsize'] + $apetagheadersize);
|
||||
} else {
|
||||
$thisfile_ape['tag_offset_start'] = $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'];
|
||||
fseek($this->getid3->fp, $thisfile_ape['tag_offset_start'], SEEK_SET);
|
||||
$APEtagData = fread($this->getid3->fp, $thisfile_ape['footer']['raw']['tagsize']);
|
||||
$this->fseek($thisfile_ape['tag_offset_start']);
|
||||
$APEtagData = $this->fread($thisfile_ape['footer']['raw']['tagsize']);
|
||||
}
|
||||
$info['avdataend'] = $thisfile_ape['tag_offset_start'];
|
||||
|
||||
|
@ -367,4 +368,4 @@ class getid3_apetag extends getid3_handler
|
|||
return in_array(strtolower($itemkey), $APEtagItemIsUTF8Lookup);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
/// 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 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
@ -25,9 +26,9 @@ class getid3_id3v1 extends getid3_handler
|
|||
return false;
|
||||
}
|
||||
|
||||
fseek($this->getid3->fp, -256, SEEK_END);
|
||||
$preid3v1 = fread($this->getid3->fp, 128);
|
||||
$id3v1tag = fread($this->getid3->fp, 128);
|
||||
$this->fseek(-256, SEEK_END);
|
||||
$preid3v1 = $this->fread(128);
|
||||
$id3v1tag = $this->fread(128);
|
||||
|
||||
if (substr($id3v1tag, 0, 3) == 'TAG') {
|
||||
|
||||
|
@ -356,4 +357,4 @@ class getid3_id3v1 extends getid3_handler
|
|||
return $ID3v1Tag;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
/// 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 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
@ -51,8 +52,8 @@ class getid3_id3v2 extends getid3_handler
|
|||
$thisfile_id3v2_flags = &$thisfile_id3v2['flags'];
|
||||
|
||||
|
||||
fseek($this->getid3->fp, $this->StartingOffset, SEEK_SET);
|
||||
$header = fread($this->getid3->fp, 10);
|
||||
$this->fseek($this->StartingOffset);
|
||||
$header = $this->fread(10);
|
||||
if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) {
|
||||
|
||||
$thisfile_id3v2['majorversion'] = ord($header{3});
|
||||
|
@ -131,7 +132,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
}
|
||||
if ($sizeofframes > 0) {
|
||||
|
||||
$framedata = fread($this->getid3->fp, $sizeofframes); // read all frames from file into $framedata variable
|
||||
$framedata = $this->fread($sizeofframes); // read all frames from file into $framedata variable
|
||||
|
||||
// if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
|
||||
if (!empty($thisfile_id3v2_flags['unsynch']) && ($id3v2_majorversion <= 3)) {
|
||||
|
@ -423,7 +424,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
// ID3v2 size 4 * %0xxxxxxx
|
||||
|
||||
if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter']) {
|
||||
$footer = fread($this->getid3->fp, 10);
|
||||
$footer = $this->fread(10);
|
||||
if (substr($footer, 0, 3) == '3DI') {
|
||||
$thisfile_id3v2['footer'] = true;
|
||||
$thisfile_id3v2['majorversion_footer'] = ord($footer{3});
|
||||
|
@ -642,7 +643,12 @@ class getid3_id3v2 extends getid3_handler
|
|||
$parsedFrame['description'] = $frame_description;
|
||||
$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
|
||||
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
|
||||
$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $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']])) {
|
||||
$info['id3v2']['comments'][$parsedFrame['framenameshort']][$commentkey] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']));
|
||||
} else {
|
||||
$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']));
|
||||
}
|
||||
}
|
||||
//unset($parsedFrame['data']); do not unset, may be needed elsewhere, e.g. for replaygain
|
||||
|
||||
|
@ -1077,7 +1083,12 @@ class getid3_id3v2 extends getid3_handler
|
|||
$parsedFrame['description'] = $frame_description;
|
||||
$parsedFrame['data'] = $frame_text;
|
||||
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
|
||||
$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
|
||||
$commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (!empty($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']])) {
|
||||
$info['id3v2']['comments'][$parsedFrame['framenameshort']][$commentkey] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
|
||||
} else {
|
||||
$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1885,7 +1896,7 @@ class getid3_id3v2 extends getid3_handler
|
|||
$frame_offset += 2;
|
||||
$parsedFrame['bitsperpoint'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
|
||||
$frame_bytesperpoint = ceil($parsedFrame['bitsperpoint'] / 8);
|
||||
for ($i = 0; $i < $frame_indexpoints; $i++) {
|
||||
for ($i = 0; $i < $parsedFrame['indexpoints']; $i++) {
|
||||
$parsedFrame['indexes'][$i] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesperpoint));
|
||||
$frame_offset += $frame_bytesperpoint;
|
||||
}
|
||||
|
@ -3411,4 +3422,3 @@ class getid3_id3v2 extends getid3_handler
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
/// 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 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
@ -27,8 +28,8 @@ class getid3_lyrics3 extends getid3_handler
|
|||
return false;
|
||||
}
|
||||
|
||||
fseek($this->getid3->fp, (0 - 128 - 9 - 6), SEEK_END); // end - ID3v1 - "LYRICSEND" - [Lyrics3size]
|
||||
$lyrics3_id3v1 = fread($this->getid3->fp, 128 + 9 + 6);
|
||||
$this->fseek((0 - 128 - 9 - 6), SEEK_END); // end - ID3v1 - "LYRICSEND" - [Lyrics3size]
|
||||
$lyrics3_id3v1 = $this->fread(128 + 9 + 6);
|
||||
$lyrics3lsz = substr($lyrics3_id3v1, 0, 6); // Lyrics3size
|
||||
$lyrics3end = substr($lyrics3_id3v1, 6, 9); // LYRICSEND or LYRICS200
|
||||
$id3v1tag = substr($lyrics3_id3v1, 15, 128); // ID3v1
|
||||
|
@ -68,9 +69,9 @@ class getid3_lyrics3 extends getid3_handler
|
|||
|
||||
if (isset($info['ape']['tag_offset_start']) && ($info['ape']['tag_offset_start'] > 15)) {
|
||||
|
||||
fseek($this->getid3->fp, $info['ape']['tag_offset_start'] - 15, SEEK_SET);
|
||||
$lyrics3lsz = fread($this->getid3->fp, 6);
|
||||
$lyrics3end = fread($this->getid3->fp, 9);
|
||||
$this->fseek($info['ape']['tag_offset_start'] - 15);
|
||||
$lyrics3lsz = $this->fread(6);
|
||||
$lyrics3end = $this->fread(9);
|
||||
|
||||
if ($lyrics3end == 'LYRICSEND') {
|
||||
// Lyrics3v1, APE, maybe ID3v1
|
||||
|
@ -101,20 +102,19 @@ class getid3_lyrics3 extends getid3_handler
|
|||
|
||||
if (!isset($info['ape'])) {
|
||||
$GETID3_ERRORARRAY = &$info['warning'];
|
||||
if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, false)) {
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_apetag = new getid3_apetag($getid3_temp);
|
||||
$getid3_apetag->overrideendoffset = $info['lyrics3']['tag_offset_start'];
|
||||
$getid3_apetag->Analyze();
|
||||
if (!empty($getid3_temp->info['ape'])) {
|
||||
$info['ape'] = $getid3_temp->info['ape'];
|
||||
}
|
||||
if (!empty($getid3_temp->info['replay_gain'])) {
|
||||
$info['replay_gain'] = $getid3_temp->info['replay_gain'];
|
||||
}
|
||||
unset($getid3_temp, $getid3_apetag);
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, true);
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_apetag = new getid3_apetag($getid3_temp);
|
||||
$getid3_apetag->overrideendoffset = $info['lyrics3']['tag_offset_start'];
|
||||
$getid3_apetag->Analyze();
|
||||
if (!empty($getid3_temp->info['ape'])) {
|
||||
$info['ape'] = $getid3_temp->info['ape'];
|
||||
}
|
||||
if (!empty($getid3_temp->info['replay_gain'])) {
|
||||
$info['replay_gain'] = $getid3_temp->info['replay_gain'];
|
||||
}
|
||||
unset($getid3_temp, $getid3_apetag);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -132,11 +132,11 @@ class getid3_lyrics3 extends getid3_handler
|
|||
return false;
|
||||
}
|
||||
|
||||
fseek($this->getid3->fp, $endoffset, SEEK_SET);
|
||||
$this->fseek($endoffset);
|
||||
if ($length <= 0) {
|
||||
return false;
|
||||
}
|
||||
$rawdata = fread($this->getid3->fp, $length);
|
||||
$rawdata = $this->fread($length);
|
||||
|
||||
$ParsedLyrics3['raw']['lyrics3version'] = $version;
|
||||
$ParsedLyrics3['raw']['lyrics3tagsize'] = $length;
|
||||
|
@ -169,7 +169,7 @@ class getid3_lyrics3 extends getid3_handler
|
|||
$ParsedLyrics3['raw']['LYR'] = trim(substr($rawdata, 11, strlen($rawdata) - 11 - 9));
|
||||
$this->Lyrics3LyricsTimestampParse($ParsedLyrics3);
|
||||
} else {
|
||||
$info['error'][] = '"LYRICSEND" expected at '.(ftell($this->getid3->fp) - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead';
|
||||
$info['error'][] = '"LYRICSEND" expected at '.($this->ftell() - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead';
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
@ -217,7 +217,7 @@ class getid3_lyrics3 extends getid3_handler
|
|||
$this->Lyrics3LyricsTimestampParse($ParsedLyrics3);
|
||||
}
|
||||
} else {
|
||||
$info['error'][] = '"LYRICS200" expected at '.(ftell($this->getid3->fp) - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead';
|
||||
$info['error'][] = '"LYRICS200" expected at '.($this->ftell() - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead';
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
@ -291,4 +291,4 @@ class getid3_lyrics3 extends getid3_handler
|
|||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
*****************************************************************
|
||||
|
@ -67,13 +68,13 @@ What does getID3() do?
|
|||
===========================================================================
|
||||
|
||||
Reads & parses (to varying degrees):
|
||||
# tags:
|
||||
¤ tags:
|
||||
* APE (v1 and v2)
|
||||
* ID3v1 (& ID3v1.1)
|
||||
* ID3v2 (v2.4, v2.3, v2.2)
|
||||
* Lyrics3 (v1 & v2)
|
||||
|
||||
# audio-lossy:
|
||||
¤ audio-lossy:
|
||||
* MP3/MP2/MP1
|
||||
* MPC / Musepack
|
||||
* Ogg (Vorbis, OggFLAC, Speex)
|
||||
|
@ -85,7 +86,7 @@ Reads & parses (to varying degrees):
|
|||
* DSS
|
||||
* VQF
|
||||
|
||||
# audio-lossless:
|
||||
¤ audio-lossless:
|
||||
* AIFF
|
||||
* AU
|
||||
* Bonk
|
||||
|
@ -104,7 +105,7 @@ Reads & parses (to varying degrees):
|
|||
* WAV (RIFF)
|
||||
* WavPack
|
||||
|
||||
# audio-video:
|
||||
¤ audio-video:
|
||||
* ASF: ASF, Windows Media Audio (WMA), Windows Media Video (WMV)
|
||||
* AVI (RIFF)
|
||||
* Flash
|
||||
|
@ -114,7 +115,7 @@ Reads & parses (to varying degrees):
|
|||
* Quicktime (including MP4)
|
||||
* RealVideo
|
||||
|
||||
# still image:
|
||||
¤ still image:
|
||||
* BMP
|
||||
* GIF
|
||||
* JPEG
|
||||
|
@ -123,7 +124,7 @@ Reads & parses (to varying degrees):
|
|||
* SWF (Flash)
|
||||
* PhotoCD
|
||||
|
||||
# data:
|
||||
¤ data:
|
||||
* ISO-9660 CD-ROM image (directory structure)
|
||||
* SZIP (limited support)
|
||||
* ZIP (directory structure)
|
||||
|
@ -309,7 +310,7 @@ http://www.getid3.org/phpBB3/viewforum.php?f=7
|
|||
(http://web.inter.nl.net/users/hvdh/lossless/lossless.htm)
|
||||
* Support for RIFF-INFO chunks
|
||||
* http://lotto.st-andrews.ac.uk/~njh/tag_interchange.html
|
||||
(thanks Nick Humfrey <njh@surgeradio*co*uk>)
|
||||
(thanks Nick Humfrey <njhØsurgeradio*co*uk>)
|
||||
* http://abcavi.narod.ru/sof/abcavi/infotags.htm
|
||||
(thanks Kibi)
|
||||
* Better support for Bink video
|
||||
|
@ -324,23 +325,23 @@ http://www.getid3.org/phpBB3/viewforum.php?f=7
|
|||
* Support for IFF
|
||||
* Support for ICO
|
||||
* Support for ANI
|
||||
* Support for EXE (comments, author, etc) (thanks p*quaedackers@planet*nl)
|
||||
* Support for EXE (comments, author, etc) (thanks p*quaedackersØplanet*nl)
|
||||
* Support for DVD-IFO (region, subtitles, aspect ratio, etc)
|
||||
(thanks p*quaedackers@planet*nl)
|
||||
(thanks p*quaedackersØplanet*nl)
|
||||
* More complete support for SWF - parsing encapsulated MP3 and/or JPEG content
|
||||
(thanks n8n8@yahoo*com)
|
||||
(thanks n8n8Øyahoo*com)
|
||||
* Support for a2b
|
||||
* Optional scan-through-frames for AVI verification
|
||||
(thanks rockcohen@massive-interactive*nl)
|
||||
* Support for TTF (thanks info@butterflyx*com)
|
||||
(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 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)
|
||||
* Support for ID4 (http://www.wackysoft.cjb.net grizlyY2K@hotmail*com)
|
||||
* 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)
|
||||
* Parse XML data from Quicktime SMIL metafiles (klausrathØmac*com)
|
||||
* ID3v2 genre string creator function
|
||||
* More complete parsing of JPG
|
||||
* Support for all old-style ASF packets
|
||||
|
@ -424,7 +425,7 @@ http://www.getid3.org/phpBB3/viewtopic.php?t=25
|
|||
"movi" chunk that fits in the first 2GB, should issue error
|
||||
to show that playtime is incorrect. Other data should be mostly
|
||||
correct, assuming that data is constant throughout the file)
|
||||
|
||||
* PHP <= v5 on Windows cannot read UTF-8 filenames
|
||||
|
||||
|
||||
Known Bugs/Issues in other programs
|
||||
|
@ -600,4 +601,4 @@ Reference material:
|
|||
* http://cpansearch.perl.org/src/RGIBSON/Audio-DSS-0.02/lib/Audio/DSS.pm
|
||||
* 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.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
|
Loading…
Reference in New Issue