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:
Scott Taylor 2014-09-11 19:07:17 +00:00
parent 293e344490
commit ac02e9951e
19 changed files with 918 additions and 587 deletions

View File

@ -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,23 +1223,29 @@ 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);
if (!is_numeric($key)) {
$ThisFileInfo['comments'][$tagname][$key] = $value;
} else {
$ThisFileInfo['comments'][$tagname][] = $value;
}
}
}
}
}
}
// Copy to ['comments_html']
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
@ -1242,6 +1261,8 @@ class getid3_lib
}
}
}
}
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);
}
}

View File

@ -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,9 +1205,13 @@ 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) {
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') {
unset($this->info[$comment_name]['comments'][$tag_key]);
}
@ -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('&#0;', '', 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
@ -1662,7 +1685,7 @@ abstract class getid3_handler
if ($whence == SEEK_CUR) {
$pos = $this->ftell() + $bytes;
} elseif ($whence == SEEK_END) {
$pos = $this->info['filesize'] + $bytes;
$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
}

View File

@ -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 //
/////////////////////////////////////////////////////////////////
*****************************************************************

View File

@ -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');
}
return (isset($WMpictureTypeLookup[$WMpictureType]) ? $WMpictureTypeLookup[$WMpictureType] : '');
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);
}
public function ASF_HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) {
return (isset($lookup[$WMpictureType]) ? $lookup[$WMpictureType] : '');
}
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;

View File

@ -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,17 +235,31 @@ 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'];
}
}
break;
// Meta tag
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,7 +635,7 @@ class AVCSequenceParameterSetReader {
public $width;
public $height;
public function AVCSequenceParameterSetReader($sps) {
public function __construct($sps) {
$this->sps = $sps;
}
@ -627,53 +643,53 @@ class AVCSequenceParameterSetReader {
$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;
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(); // 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();
$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();
$this->skipBits(1);
$this->width = ($this->expGolombUe() + 1) * 16;
$heightMap = $this->expGolombUe() + 1;
$this->height = (2 - $this->getBit()) * $heightMap * 16;
}
public function skipBits($bits) {
$newBits = $this->currentBits + $bits;

View File

@ -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.']');
}
}
@ -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);
}

View File

@ -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;
}
$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,8 +148,7 @@ class getid3_quicktime extends getid3_handler
break;
case 'ilst': // Item LiST container atom
$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
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) {
@ -222,6 +169,7 @@ class getid3_quicktime extends getid3_handler
$atom_structure['data'] = $newData;
unset($atom_structure['subatoms']);
}
}
break;
case "\x00\x00\x00\x01":
@ -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;
@ -464,13 +412,23 @@ class getid3_quicktime extends getid3_handler
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

View File

@ -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';
}
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,12 +893,29 @@ 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';
$thisfile_audio_dataformat = 'cda';
$thisfile_audio['lossless'] = true;
$info['fileformat'] = 'cda';
unset($info['mime_type']);
$thisfile_audio_dataformat = 'cda';
$info['avdataoffset'] = 44;
if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) {
@ -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,11 +1149,13 @@ class getid3_riff extends getid3_handler
}
break;
case 'CDXA':
$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_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);
@ -1125,14 +1168,12 @@ class getid3_riff extends getid3_handler
}
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,7 +2577,7 @@ 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);

View File

@ -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 //
/////////////////////////////////////////////////////////////////

View File

@ -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 //
/////////////////////////////////////////////////////////////////

View File

@ -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 //
/////////////////////////////////////////////////////////////////

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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'];

View File

@ -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') {

View File

@ -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,8 +643,13 @@ 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'])) {
$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,8 +1083,13 @@ class getid3_id3v2 extends getid3_handler
$parsedFrame['description'] = $frame_description;
$parsedFrame['data'] = $frame_text;
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
$commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (!empty($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0));
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
}
}

View File

@ -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,7 +102,7 @@ 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_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);
@ -115,7 +116,6 @@ class getid3_lyrics3 extends getid3_handler
}
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;

View File

@ -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