podcast 1.37.7: PHP 8 compatibility fixes (#144)
Fix some warning in the main code, update getid3
This commit is contained in:
parent
f5c1e3a2e4
commit
dcf32c365d
|
@ -1,3 +1,6 @@
|
|||
1.37.7:
|
||||
* Additional fixes for PHP 8
|
||||
|
||||
1.37.6:
|
||||
* Hotfixes for PHP 8 (surrim)
|
||||
|
||||
|
|
8
serendipity_event_podcast/composer.json
Normal file
8
serendipity_event_podcast/composer.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"config": {
|
||||
"vendor-dir": "player"
|
||||
},
|
||||
"require": {
|
||||
"james-heinrich/getid3": "^1.9"
|
||||
}
|
||||
}
|
86
serendipity_event_podcast/composer.lock
generated
Normal file
86
serendipity_event_podcast/composer.lock
generated
Normal file
|
@ -0,0 +1,86 @@
|
|||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "1aca7343f11a56253e87d4b5e4ff8bfc",
|
||||
"packages": [
|
||||
{
|
||||
"name": "james-heinrich/getid3",
|
||||
"version": "v1.9.22",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/JamesHeinrich/getID3.git",
|
||||
"reference": "45f20faa0f0a24489740392c5b512ddcc36deccd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/45f20faa0f0a24489740392c5b512ddcc36deccd",
|
||||
"reference": "45f20faa0f0a24489740392c5b512ddcc36deccd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-parallel-lint/php-parallel-lint": "^1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-SimpleXML": "SimpleXML extension is required to analyze RIFF/WAV/BWF audio files (also requires `ext-libxml`).",
|
||||
"ext-com_dotnet": "COM extension is required when loading files larger than 2GB on Windows.",
|
||||
"ext-ctype": "ctype extension is required when loading files larger than 2GB on 32-bit PHP (also on 64-bit PHP on Windows) or executing `getid3_lib::CopyTagsToComments`.",
|
||||
"ext-dba": "DBA extension is required to use the DBA database as a cache storage.",
|
||||
"ext-exif": "EXIF extension is required for graphic modules.",
|
||||
"ext-iconv": "iconv extension is required to work with different character sets (when `ext-mbstring` is not available).",
|
||||
"ext-json": "JSON extension is required to analyze Apple Quicktime videos.",
|
||||
"ext-libxml": "libxml extension is required to analyze RIFF/WAV/BWF audio files.",
|
||||
"ext-mbstring": "mbstring extension is required to work with different character sets.",
|
||||
"ext-mysql": "MySQL extension is required to use the MySQL database as a cache storage (deprecated in PHP 5.5, removed in PHP >= 7.0, use `ext-mysqli` instead).",
|
||||
"ext-mysqli": "MySQLi extension is required to use the MySQL database as a cache storage.",
|
||||
"ext-rar": "RAR extension is required for RAR archive module.",
|
||||
"ext-sqlite3": "SQLite3 extension is required to use the SQLite3 database as a cache storage.",
|
||||
"ext-xml": "XML extension is required for graphic modules to analyze the XML metadata.",
|
||||
"ext-zlib": "Zlib extension is required for archive modules and compressed metadata."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"getid3/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"GPL-1.0-or-later",
|
||||
"LGPL-3.0-only",
|
||||
"MPL-2.0"
|
||||
],
|
||||
"description": "PHP script that extracts useful information from popular multimedia file formats",
|
||||
"homepage": "https://www.getid3.org/",
|
||||
"keywords": [
|
||||
"codecs",
|
||||
"php",
|
||||
"tags"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/JamesHeinrich/getID3/issues",
|
||||
"source": "https://github.com/JamesHeinrich/getID3/tree/v1.9.22"
|
||||
},
|
||||
"time": "2022-09-29T16:41:13+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.3.0"
|
||||
}
|
12
serendipity_event_podcast/player/autoload.php
Normal file
12
serendipity_event_podcast/player/autoload.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit295fe9b55080d50c65b251f903ebe7f9::getLoader();
|
572
serendipity_event_podcast/player/composer/ClassLoader.php
Normal file
572
serendipity_event_podcast/player/composer/ClassLoader.php
Normal file
|
@ -0,0 +1,572 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see https://www.php-fig.org/psr/psr-0/
|
||||
* @see https://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/** @var ?string */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<int, string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<string, string[]>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
/** @var bool */
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
/** @var bool */
|
||||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var bool[]
|
||||
* @psalm-var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var ?string */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var self[]
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param ?string $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
$this->vendorDir = $vendorDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, array<int, string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[] Array of classname => path
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $classMap Class to filename map
|
||||
* @psalm-param array<string, string> $classMap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param string[]|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
(array) $paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param string[]|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
(array) $paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param string[]|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param string[]|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
|
||||
if (null === $this->vendorDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($prepend) {
|
||||
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||
} else {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
|
||||
if (null !== $this->vendorDir) {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return true|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently registered loaders indexed by their corresponding vendor directories.
|
||||
*
|
||||
* @return self[]
|
||||
*/
|
||||
public static function getRegisteredLoaders()
|
||||
{
|
||||
return self::$registeredLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $ext
|
||||
* @return string|false
|
||||
*/
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
$subPath = $class;
|
||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||
$subPath = substr($subPath, 0, $lastPos);
|
||||
$search = $subPath . '\\';
|
||||
if (isset($this->prefixDirsPsr4[$search])) {
|
||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||
if (file_exists($file = $dir . $pathEnd)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
* @private
|
||||
*/
|
||||
function includeFile($file)
|
||||
{
|
||||
include $file;
|
||||
}
|
352
serendipity_event_podcast/player/composer/InstalledVersions.php
Normal file
352
serendipity_event_podcast/player/composer/InstalledVersions.php
Normal file
|
@ -0,0 +1,352 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Composer\Semver\VersionParser;
|
||||
|
||||
/**
|
||||
* This class is copied in every Composer installed project and available to all
|
||||
*
|
||||
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||
*
|
||||
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class InstalledVersions
|
||||
{
|
||||
/**
|
||||
* @var mixed[]|null
|
||||
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
private static $canGetVendors;
|
||||
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static $installedByVendor = array();
|
||||
|
||||
/**
|
||||
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||
*
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackages()
|
||||
{
|
||||
$packages = array();
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
$packages[] = array_keys($installed['versions']);
|
||||
}
|
||||
|
||||
if (1 === \count($packages)) {
|
||||
return $packages[0];
|
||||
}
|
||||
|
||||
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all package names with a specific type e.g. 'library'
|
||||
*
|
||||
* @param string $type
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackagesByType($type)
|
||||
{
|
||||
$packagesByType = array();
|
||||
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
foreach ($installed['versions'] as $name => $package) {
|
||||
if (isset($package['type']) && $package['type'] === $type) {
|
||||
$packagesByType[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $packagesByType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package is installed
|
||||
*
|
||||
* This also returns true if the package name is provided or replaced by another package
|
||||
*
|
||||
* @param string $packageName
|
||||
* @param bool $includeDevRequirements
|
||||
* @return bool
|
||||
*/
|
||||
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (isset($installed['versions'][$packageName])) {
|
||||
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package satisfies a version constraint
|
||||
*
|
||||
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||
*
|
||||
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||
*
|
||||
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||
* @param string $packageName
|
||||
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||
* @return bool
|
||||
*/
|
||||
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||
{
|
||||
$constraint = $parser->parseConstraints($constraint);
|
||||
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||
|
||||
return $provided->matches($constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||
*
|
||||
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||
* whether a given version of a package is installed, and not just whether it exists
|
||||
*
|
||||
* @param string $packageName
|
||||
* @return string Version constraint usable with composer/semver
|
||||
*/
|
||||
public static function getVersionRanges($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ranges = array();
|
||||
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||
}
|
||||
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||
}
|
||||
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||
}
|
||||
|
||||
return implode(' || ', $ranges);
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getPrettyVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||
*/
|
||||
public static function getReference($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['reference'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||
*/
|
||||
public static function getInstallPath($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||
*/
|
||||
public static function getRootPackage()
|
||||
{
|
||||
$installed = self::getInstalled();
|
||||
|
||||
return $installed[0]['root'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw installed.php data for custom implementations
|
||||
*
|
||||
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||
* @return array[]
|
||||
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
|
||||
*/
|
||||
public static function getRawData()
|
||||
{
|
||||
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
self::$installed = include __DIR__ . '/installed.php';
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
return self::$installed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||
*
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
public static function getAllRawData()
|
||||
{
|
||||
return self::getInstalled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets you reload the static array from another file
|
||||
*
|
||||
* This is only useful for complex integrations in which a project needs to use
|
||||
* this class but then also needs to execute another project's autoloader in process,
|
||||
* and wants to ensure both projects have access to their version of installed.php.
|
||||
*
|
||||
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||
* the data it needs from this class, then call reload() with
|
||||
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||
* the project in which it runs can then also use this class safely, without
|
||||
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||
*
|
||||
* @param array[] $data A vendor/composer/installed.php data set
|
||||
* @return void
|
||||
*
|
||||
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||
*/
|
||||
public static function reload($data)
|
||||
{
|
||||
self::$installed = $data;
|
||||
self::$installedByVendor = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static function getInstalled()
|
||||
{
|
||||
if (null === self::$canGetVendors) {
|
||||
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||
}
|
||||
|
||||
$installed = array();
|
||||
|
||||
if (self::$canGetVendors) {
|
||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir];
|
||||
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
|
||||
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
||||
self::$installed = $installed[count($installed) - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
self::$installed = require __DIR__ . '/installed.php';
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
$installed[] = self::$installed;
|
||||
|
||||
return $installed;
|
||||
}
|
||||
}
|
21
serendipity_event_podcast/player/composer/LICENSE
Normal file
21
serendipity_event_podcast/player/composer/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
|
||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'AMFReader' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio-video.flv.php',
|
||||
'AMFStream' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio-video.flv.php',
|
||||
'AVCSequenceParameterSetReader' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio-video.flv.php',
|
||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||
'Image_XMP' => $vendorDir . '/james-heinrich/getid3/getid3/module.tag.xmp.php',
|
||||
'getID3' => $vendorDir . '/james-heinrich/getid3/getid3/getid3.php',
|
||||
'getID3_cached_dbm' => $vendorDir . '/james-heinrich/getid3/getid3/extension.cache.dbm.php',
|
||||
'getID3_cached_mysql' => $vendorDir . '/james-heinrich/getid3/getid3/extension.cache.mysql.php',
|
||||
'getID3_cached_mysqli' => $vendorDir . '/james-heinrich/getid3/getid3/extension.cache.mysqli.php',
|
||||
'getID3_cached_sqlite3' => $vendorDir . '/james-heinrich/getid3/getid3/extension.cache.sqlite3.php',
|
||||
'getid3_aa' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.aa.php',
|
||||
'getid3_aac' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.aac.php',
|
||||
'getid3_ac3' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.ac3.php',
|
||||
'getid3_amr' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.amr.php',
|
||||
'getid3_apetag' => $vendorDir . '/james-heinrich/getid3/getid3/module.tag.apetag.php',
|
||||
'getid3_asf' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio-video.asf.php',
|
||||
'getid3_au' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.au.php',
|
||||
'getid3_avr' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.avr.php',
|
||||
'getid3_bink' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio-video.bink.php',
|
||||
'getid3_bmp' => $vendorDir . '/james-heinrich/getid3/getid3/module.graphic.bmp.php',
|
||||
'getid3_bonk' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.bonk.php',
|
||||
'getid3_cue' => $vendorDir . '/james-heinrich/getid3/getid3/module.misc.cue.php',
|
||||
'getid3_dsdiff' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.dsdiff.php',
|
||||
'getid3_dsf' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.dsf.php',
|
||||
'getid3_dss' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.dss.php',
|
||||
'getid3_dts' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.dts.php',
|
||||
'getid3_efax' => $vendorDir . '/james-heinrich/getid3/getid3/module.graphic.efax.php',
|
||||
'getid3_exception' => $vendorDir . '/james-heinrich/getid3/getid3/getid3.php',
|
||||
'getid3_exe' => $vendorDir . '/james-heinrich/getid3/getid3/module.misc.exe.php',
|
||||
'getid3_flac' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.flac.php',
|
||||
'getid3_flv' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio-video.flv.php',
|
||||
'getid3_gif' => $vendorDir . '/james-heinrich/getid3/getid3/module.graphic.gif.php',
|
||||
'getid3_gzip' => $vendorDir . '/james-heinrich/getid3/getid3/module.archive.gzip.php',
|
||||
'getid3_handler' => $vendorDir . '/james-heinrich/getid3/getid3/getid3.php',
|
||||
'getid3_hpk' => $vendorDir . '/james-heinrich/getid3/getid3/module.archive.hpk.php',
|
||||
'getid3_id3v1' => $vendorDir . '/james-heinrich/getid3/getid3/module.tag.id3v1.php',
|
||||
'getid3_id3v2' => $vendorDir . '/james-heinrich/getid3/getid3/module.tag.id3v2.php',
|
||||
'getid3_iso' => $vendorDir . '/james-heinrich/getid3/getid3/module.misc.iso.php',
|
||||
'getid3_ivf' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio-video.ivf.php',
|
||||
'getid3_jpg' => $vendorDir . '/james-heinrich/getid3/getid3/module.graphic.jpg.php',
|
||||
'getid3_la' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.la.php',
|
||||
'getid3_lib' => $vendorDir . '/james-heinrich/getid3/getid3/getid3.lib.php',
|
||||
'getid3_lpac' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.lpac.php',
|
||||
'getid3_lyrics3' => $vendorDir . '/james-heinrich/getid3/getid3/module.tag.lyrics3.php',
|
||||
'getid3_matroska' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio-video.matroska.php',
|
||||
'getid3_midi' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.midi.php',
|
||||
'getid3_mod' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.mod.php',
|
||||
'getid3_monkey' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.monkey.php',
|
||||
'getid3_mp3' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.mp3.php',
|
||||
'getid3_mpc' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.mpc.php',
|
||||
'getid3_mpeg' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio-video.mpeg.php',
|
||||
'getid3_msoffice' => $vendorDir . '/james-heinrich/getid3/getid3/module.misc.msoffice.php',
|
||||
'getid3_nsv' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio-video.nsv.php',
|
||||
'getid3_ogg' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.ogg.php',
|
||||
'getid3_optimfrog' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.optimfrog.php',
|
||||
'getid3_par2' => $vendorDir . '/james-heinrich/getid3/getid3/module.misc.par2.php',
|
||||
'getid3_pcd' => $vendorDir . '/james-heinrich/getid3/getid3/module.graphic.pcd.php',
|
||||
'getid3_pdf' => $vendorDir . '/james-heinrich/getid3/getid3/module.misc.pdf.php',
|
||||
'getid3_png' => $vendorDir . '/james-heinrich/getid3/getid3/module.graphic.png.php',
|
||||
'getid3_quicktime' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio-video.quicktime.php',
|
||||
'getid3_rar' => $vendorDir . '/james-heinrich/getid3/getid3/module.archive.rar.php',
|
||||
'getid3_real' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio-video.real.php',
|
||||
'getid3_riff' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio-video.riff.php',
|
||||
'getid3_rkau' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.rkau.php',
|
||||
'getid3_shorten' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.shorten.php',
|
||||
'getid3_svg' => $vendorDir . '/james-heinrich/getid3/getid3/module.graphic.svg.php',
|
||||
'getid3_swf' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio-video.swf.php',
|
||||
'getid3_szip' => $vendorDir . '/james-heinrich/getid3/getid3/module.archive.szip.php',
|
||||
'getid3_tag_nikon_nctg' => $vendorDir . '/james-heinrich/getid3/getid3/module.tag.nikon-nctg.php',
|
||||
'getid3_tak' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.tak.php',
|
||||
'getid3_tar' => $vendorDir . '/james-heinrich/getid3/getid3/module.archive.tar.php',
|
||||
'getid3_tiff' => $vendorDir . '/james-heinrich/getid3/getid3/module.graphic.tiff.php',
|
||||
'getid3_torrent' => $vendorDir . '/james-heinrich/getid3/getid3/module.misc.torrent.php',
|
||||
'getid3_ts' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio-video.ts.php',
|
||||
'getid3_tta' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.tta.php',
|
||||
'getid3_voc' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.voc.php',
|
||||
'getid3_vqf' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.vqf.php',
|
||||
'getid3_wavpack' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio.wavpack.php',
|
||||
'getid3_write_apetag' => $vendorDir . '/james-heinrich/getid3/getid3/write.apetag.php',
|
||||
'getid3_write_id3v1' => $vendorDir . '/james-heinrich/getid3/getid3/write.id3v1.php',
|
||||
'getid3_write_id3v2' => $vendorDir . '/james-heinrich/getid3/getid3/write.id3v2.php',
|
||||
'getid3_write_lyrics3' => $vendorDir . '/james-heinrich/getid3/getid3/write.lyrics3.php',
|
||||
'getid3_write_metaflac' => $vendorDir . '/james-heinrich/getid3/getid3/write.metaflac.php',
|
||||
'getid3_write_real' => $vendorDir . '/james-heinrich/getid3/getid3/write.real.php',
|
||||
'getid3_write_vorbiscomment' => $vendorDir . '/james-heinrich/getid3/getid3/write.vorbiscomment.php',
|
||||
'getid3_writetags' => $vendorDir . '/james-heinrich/getid3/getid3/write.php',
|
||||
'getid3_wtv' => $vendorDir . '/james-heinrich/getid3/getid3/module.audio-video.wtv.php',
|
||||
'getid3_xz' => $vendorDir . '/james-heinrich/getid3/getid3/module.archive.xz.php',
|
||||
'getid3_zip' => $vendorDir . '/james-heinrich/getid3/getid3/module.archive.zip.php',
|
||||
);
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
38
serendipity_event_podcast/player/composer/autoload_real.php
Normal file
38
serendipity_event_podcast/player/composer/autoload_real.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit295fe9b55080d50c65b251f903ebe7f9
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Composer\Autoload\ClassLoader
|
||||
*/
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit295fe9b55080d50c65b251f903ebe7f9', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit295fe9b55080d50c65b251f903ebe7f9', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit295fe9b55080d50c65b251f903ebe7f9::getInitializer($loader));
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
108
serendipity_event_podcast/player/composer/autoload_static.php
Normal file
108
serendipity_event_podcast/player/composer/autoload_static.php
Normal file
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInit295fe9b55080d50c65b251f903ebe7f9
|
||||
{
|
||||
public static $classMap = array (
|
||||
'AMFReader' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio-video.flv.php',
|
||||
'AMFStream' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio-video.flv.php',
|
||||
'AVCSequenceParameterSetReader' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio-video.flv.php',
|
||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||
'Image_XMP' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.tag.xmp.php',
|
||||
'getID3' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/getid3.php',
|
||||
'getID3_cached_dbm' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/extension.cache.dbm.php',
|
||||
'getID3_cached_mysql' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/extension.cache.mysql.php',
|
||||
'getID3_cached_mysqli' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/extension.cache.mysqli.php',
|
||||
'getID3_cached_sqlite3' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/extension.cache.sqlite3.php',
|
||||
'getid3_aa' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.aa.php',
|
||||
'getid3_aac' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.aac.php',
|
||||
'getid3_ac3' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.ac3.php',
|
||||
'getid3_amr' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.amr.php',
|
||||
'getid3_apetag' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.tag.apetag.php',
|
||||
'getid3_asf' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio-video.asf.php',
|
||||
'getid3_au' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.au.php',
|
||||
'getid3_avr' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.avr.php',
|
||||
'getid3_bink' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio-video.bink.php',
|
||||
'getid3_bmp' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.graphic.bmp.php',
|
||||
'getid3_bonk' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.bonk.php',
|
||||
'getid3_cue' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.misc.cue.php',
|
||||
'getid3_dsdiff' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.dsdiff.php',
|
||||
'getid3_dsf' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.dsf.php',
|
||||
'getid3_dss' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.dss.php',
|
||||
'getid3_dts' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.dts.php',
|
||||
'getid3_efax' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.graphic.efax.php',
|
||||
'getid3_exception' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/getid3.php',
|
||||
'getid3_exe' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.misc.exe.php',
|
||||
'getid3_flac' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.flac.php',
|
||||
'getid3_flv' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio-video.flv.php',
|
||||
'getid3_gif' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.graphic.gif.php',
|
||||
'getid3_gzip' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.archive.gzip.php',
|
||||
'getid3_handler' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/getid3.php',
|
||||
'getid3_hpk' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.archive.hpk.php',
|
||||
'getid3_id3v1' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.tag.id3v1.php',
|
||||
'getid3_id3v2' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.tag.id3v2.php',
|
||||
'getid3_iso' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.misc.iso.php',
|
||||
'getid3_ivf' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio-video.ivf.php',
|
||||
'getid3_jpg' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.graphic.jpg.php',
|
||||
'getid3_la' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.la.php',
|
||||
'getid3_lib' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/getid3.lib.php',
|
||||
'getid3_lpac' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.lpac.php',
|
||||
'getid3_lyrics3' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.tag.lyrics3.php',
|
||||
'getid3_matroska' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio-video.matroska.php',
|
||||
'getid3_midi' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.midi.php',
|
||||
'getid3_mod' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.mod.php',
|
||||
'getid3_monkey' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.monkey.php',
|
||||
'getid3_mp3' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.mp3.php',
|
||||
'getid3_mpc' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.mpc.php',
|
||||
'getid3_mpeg' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio-video.mpeg.php',
|
||||
'getid3_msoffice' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.misc.msoffice.php',
|
||||
'getid3_nsv' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio-video.nsv.php',
|
||||
'getid3_ogg' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.ogg.php',
|
||||
'getid3_optimfrog' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.optimfrog.php',
|
||||
'getid3_par2' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.misc.par2.php',
|
||||
'getid3_pcd' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.graphic.pcd.php',
|
||||
'getid3_pdf' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.misc.pdf.php',
|
||||
'getid3_png' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.graphic.png.php',
|
||||
'getid3_quicktime' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio-video.quicktime.php',
|
||||
'getid3_rar' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.archive.rar.php',
|
||||
'getid3_real' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio-video.real.php',
|
||||
'getid3_riff' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio-video.riff.php',
|
||||
'getid3_rkau' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.rkau.php',
|
||||
'getid3_shorten' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.shorten.php',
|
||||
'getid3_svg' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.graphic.svg.php',
|
||||
'getid3_swf' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio-video.swf.php',
|
||||
'getid3_szip' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.archive.szip.php',
|
||||
'getid3_tag_nikon_nctg' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.tag.nikon-nctg.php',
|
||||
'getid3_tak' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.tak.php',
|
||||
'getid3_tar' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.archive.tar.php',
|
||||
'getid3_tiff' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.graphic.tiff.php',
|
||||
'getid3_torrent' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.misc.torrent.php',
|
||||
'getid3_ts' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio-video.ts.php',
|
||||
'getid3_tta' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.tta.php',
|
||||
'getid3_voc' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.voc.php',
|
||||
'getid3_vqf' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.vqf.php',
|
||||
'getid3_wavpack' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio.wavpack.php',
|
||||
'getid3_write_apetag' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/write.apetag.php',
|
||||
'getid3_write_id3v1' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/write.id3v1.php',
|
||||
'getid3_write_id3v2' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/write.id3v2.php',
|
||||
'getid3_write_lyrics3' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/write.lyrics3.php',
|
||||
'getid3_write_metaflac' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/write.metaflac.php',
|
||||
'getid3_write_real' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/write.real.php',
|
||||
'getid3_write_vorbiscomment' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/write.vorbiscomment.php',
|
||||
'getid3_writetags' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/write.php',
|
||||
'getid3_wtv' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.audio-video.wtv.php',
|
||||
'getid3_xz' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.archive.xz.php',
|
||||
'getid3_zip' => __DIR__ . '/..' . '/james-heinrich/getid3/getid3/module.archive.zip.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->classMap = ComposerStaticInit295fe9b55080d50c65b251f903ebe7f9::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
76
serendipity_event_podcast/player/composer/installed.json
Normal file
76
serendipity_event_podcast/player/composer/installed.json
Normal file
|
@ -0,0 +1,76 @@
|
|||
{
|
||||
"packages": [
|
||||
{
|
||||
"name": "james-heinrich/getid3",
|
||||
"version": "v1.9.22",
|
||||
"version_normalized": "1.9.22.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/JamesHeinrich/getID3.git",
|
||||
"reference": "45f20faa0f0a24489740392c5b512ddcc36deccd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/45f20faa0f0a24489740392c5b512ddcc36deccd",
|
||||
"reference": "45f20faa0f0a24489740392c5b512ddcc36deccd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-parallel-lint/php-parallel-lint": "^1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-SimpleXML": "SimpleXML extension is required to analyze RIFF/WAV/BWF audio files (also requires `ext-libxml`).",
|
||||
"ext-com_dotnet": "COM extension is required when loading files larger than 2GB on Windows.",
|
||||
"ext-ctype": "ctype extension is required when loading files larger than 2GB on 32-bit PHP (also on 64-bit PHP on Windows) or executing `getid3_lib::CopyTagsToComments`.",
|
||||
"ext-dba": "DBA extension is required to use the DBA database as a cache storage.",
|
||||
"ext-exif": "EXIF extension is required for graphic modules.",
|
||||
"ext-iconv": "iconv extension is required to work with different character sets (when `ext-mbstring` is not available).",
|
||||
"ext-json": "JSON extension is required to analyze Apple Quicktime videos.",
|
||||
"ext-libxml": "libxml extension is required to analyze RIFF/WAV/BWF audio files.",
|
||||
"ext-mbstring": "mbstring extension is required to work with different character sets.",
|
||||
"ext-mysql": "MySQL extension is required to use the MySQL database as a cache storage (deprecated in PHP 5.5, removed in PHP >= 7.0, use `ext-mysqli` instead).",
|
||||
"ext-mysqli": "MySQLi extension is required to use the MySQL database as a cache storage.",
|
||||
"ext-rar": "RAR extension is required for RAR archive module.",
|
||||
"ext-sqlite3": "SQLite3 extension is required to use the SQLite3 database as a cache storage.",
|
||||
"ext-xml": "XML extension is required for graphic modules to analyze the XML metadata.",
|
||||
"ext-zlib": "Zlib extension is required for archive modules and compressed metadata."
|
||||
},
|
||||
"time": "2022-09-29T16:41:13+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"getid3/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"GPL-1.0-or-later",
|
||||
"LGPL-3.0-only",
|
||||
"MPL-2.0"
|
||||
],
|
||||
"description": "PHP script that extracts useful information from popular multimedia file formats",
|
||||
"homepage": "https://www.getid3.org/",
|
||||
"keywords": [
|
||||
"codecs",
|
||||
"php",
|
||||
"tags"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/JamesHeinrich/getID3/issues",
|
||||
"source": "https://github.com/JamesHeinrich/getID3/tree/v1.9.22"
|
||||
},
|
||||
"install-path": "../james-heinrich/getid3"
|
||||
}
|
||||
],
|
||||
"dev": true,
|
||||
"dev-package-names": []
|
||||
}
|
32
serendipity_event_podcast/player/composer/installed.php
Normal file
32
serendipity_event_podcast/player/composer/installed.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php return array(
|
||||
'root' => array(
|
||||
'name' => '__root__',
|
||||
'pretty_version' => '1.0.0+no-version-set',
|
||||
'version' => '1.0.0.0',
|
||||
'reference' => NULL,
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev' => true,
|
||||
),
|
||||
'versions' => array(
|
||||
'__root__' => array(
|
||||
'pretty_version' => '1.0.0+no-version-set',
|
||||
'version' => '1.0.0.0',
|
||||
'reference' => NULL,
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'james-heinrich/getid3' => array(
|
||||
'pretty_version' => 'v1.9.22',
|
||||
'version' => '1.9.22.0',
|
||||
'reference' => '45f20faa0f0a24489740392c5b512ddcc36deccd',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../james-heinrich/getid3',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
),
|
||||
);
|
26
serendipity_event_podcast/player/composer/platform_check.php
Normal file
26
serendipity_event_podcast/player/composer/platform_check.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
// platform_check.php @generated by Composer
|
||||
|
||||
$issues = array();
|
||||
|
||||
if (!(PHP_VERSION_ID >= 50300)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 5.3.0". You are running ' . PHP_VERSION . '.';
|
||||
}
|
||||
|
||||
if ($issues) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||
} elseif (!headers_sent()) {
|
||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// extension.cache.mysql.php - part of getID3() //
|
||||
// Please see readme.txt for more information //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// This extension written by Allan Hansen <ahØartemis*dk> //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* This is a caching extension for getID3(). It works the exact same
|
||||
* way as the getID3 class, but return cached information very fast
|
||||
*
|
||||
* Example: (see also demo.cache.mysql.php in /demo/)
|
||||
*
|
||||
* Normal getID3 usage (example):
|
||||
*
|
||||
* require_once 'getid3/getid3.php';
|
||||
* $getID3 = new getID3;
|
||||
* $getID3->encoding = 'UTF-8';
|
||||
* $info1 = $getID3->analyze('file1.flac');
|
||||
* $info2 = $getID3->analyze('file2.wv');
|
||||
*
|
||||
* getID3_cached usage:
|
||||
*
|
||||
* require_once 'getid3/getid3.php';
|
||||
* require_once 'getid3/getid3/extension.cache.mysql.php';
|
||||
* $getID3 = new getID3_cached_mysql('localhost', 'database',
|
||||
* 'username', 'password');
|
||||
* $getID3->encoding = 'UTF-8';
|
||||
* $info1 = $getID3->analyze('file1.flac');
|
||||
* $info2 = $getID3->analyze('file2.wv');
|
||||
*
|
||||
*
|
||||
* Supported Cache Types (this extension)
|
||||
*
|
||||
* SQL Databases:
|
||||
*
|
||||
* cache_type cache_options
|
||||
* -------------------------------------------------------------------
|
||||
* mysql host, database, username, password
|
||||
*
|
||||
*
|
||||
* DBM-Style Databases: (use extension.cache.dbm)
|
||||
*
|
||||
* cache_type cache_options
|
||||
* -------------------------------------------------------------------
|
||||
* gdbm dbm_filename, lock_filename
|
||||
* ndbm dbm_filename, lock_filename
|
||||
* db2 dbm_filename, lock_filename
|
||||
* db3 dbm_filename, lock_filename
|
||||
* db4 dbm_filename, lock_filename (PHP5 required)
|
||||
*
|
||||
* PHP must have write access to both dbm_filename and lock_filename.
|
||||
*
|
||||
*
|
||||
* Recommended Cache Types
|
||||
*
|
||||
* Infrequent updates, many reads any DBM
|
||||
* Frequent updates mysql
|
||||
*/
|
||||
|
||||
|
||||
class getID3_cached_mysql extends getID3
|
||||
{
|
||||
|
||||
// private vars
|
||||
var $cursor;
|
||||
var $connection;
|
||||
|
||||
|
||||
// public: constructor - see top of this file for cache type and cache_options
|
||||
function getID3_cached_mysql($host, $database, $username, $password) {
|
||||
|
||||
// Check for mysql support
|
||||
if (!function_exists('mysql_pconnect')) {
|
||||
throw new Exception('PHP not compiled with mysql support.');
|
||||
}
|
||||
|
||||
// Connect to database
|
||||
$this->connection = mysql_pconnect($host, $username, $password);
|
||||
if (!$this->connection) {
|
||||
throw new Exception('mysql_pconnect() failed - check permissions and spelling.');
|
||||
}
|
||||
|
||||
// Select database
|
||||
if (!mysql_select_db($database, $this->connection)) {
|
||||
throw new Exception('Cannot use database '.$database);
|
||||
}
|
||||
|
||||
// Create cache table if not exists
|
||||
$this->create_table();
|
||||
|
||||
// Check version number and clear cache if changed
|
||||
$version = '';
|
||||
if ($this->cursor = mysql_query("SELECT `value` FROM `getid3_cache` WHERE (`filename` = '".mysql_real_escape_string(GETID3_VERSION)."') AND (`filesize` = '-1') AND (`filetime` = '-1') AND (`analyzetime` = '-1')", $this->connection)) {
|
||||
list($version) = mysql_fetch_array($this->cursor);
|
||||
}
|
||||
if ($version != GETID3_VERSION) {
|
||||
$this->clear_cache();
|
||||
}
|
||||
|
||||
parent::getID3();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// public: clear cache
|
||||
function clear_cache() {
|
||||
|
||||
$this->cursor = mysql_query("DELETE FROM `getid3_cache`", $this->connection);
|
||||
$this->cursor = mysql_query("INSERT INTO `getid3_cache` VALUES ('".GETID3_VERSION."', -1, -1, -1, '".GETID3_VERSION."')", $this->connection);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// public: analyze file
|
||||
function analyze($filename) {
|
||||
|
||||
if (file_exists($filename)) {
|
||||
|
||||
// Short-hands
|
||||
$filetime = filemtime($filename);
|
||||
$filesize = filesize($filename);
|
||||
|
||||
// Loopup file
|
||||
$result = '';
|
||||
if ($this->cursor = mysql_query("SELECT `value` FROM `getid3_cache` WHERE (`filename` = '".mysql_real_escape_string($filename)."') AND (`filesize` = '".mysql_real_escape_string($filesize)."') AND (`filetime` = '".mysql_real_escape_string($filetime)."')", $this->connection)) {
|
||||
// Hit
|
||||
list($result) = mysql_fetch_array($this->cursor);
|
||||
return unserialize(base64_decode($result));
|
||||
}
|
||||
}
|
||||
|
||||
// Miss
|
||||
$analysis = parent::analyze($filename);
|
||||
|
||||
// Save result
|
||||
if (file_exists($filename)) {
|
||||
$this->cursor = mysql_query("INSERT INTO `getid3_cache` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES ('".mysql_real_escape_string($filename)."', '".mysql_real_escape_string($filesize)."', '".mysql_real_escape_string($filetime)."', '".mysql_real_escape_string(time())."', '".mysql_real_escape_string(base64_encode(serialize($analysis)))."')", $this->connection);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// private: (re)create sql table
|
||||
function create_table($drop=false) {
|
||||
|
||||
$this->cursor = mysql_query("CREATE TABLE IF NOT EXISTS `getid3_cache` (
|
||||
`filename` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`filesize` INT(11) NOT NULL DEFAULT '0',
|
||||
`filetime` INT(11) NOT NULL DEFAULT '0',
|
||||
`analyzetime` INT(11) NOT NULL DEFAULT '0',
|
||||
`value` TEXT NOT NULL,
|
||||
PRIMARY KEY (`filename`,`filesize`,`filetime`)) TYPE=MyISAM", $this->connection);
|
||||
echo mysql_error($this->connection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,52 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.archive.rar.php //
|
||||
// module for analyzing RAR files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_rar
|
||||
{
|
||||
|
||||
var $option_use_rar_extension = false;
|
||||
|
||||
function getid3_rar(&$fd, &$ThisFileInfo) {
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'rar';
|
||||
|
||||
if ($this->option_use_rar_extension === true) {
|
||||
if (function_exists('rar_open')) {
|
||||
if ($rp = rar_open($ThisFileInfo['filenamepath'])) {
|
||||
$ThisFileInfo['rar']['files'] = array();
|
||||
$entries = rar_list($rp);
|
||||
foreach ($entries as $entry) {
|
||||
$ThisFileInfo['rar']['files'] = getid3_lib::array_merge_clobber($ThisFileInfo['rar']['files'], getid3_lib::CreateDeepArray($entry->getName(), '/', $entry->getUnpackedSize()));
|
||||
}
|
||||
rar_close($rp);
|
||||
return true;
|
||||
} else {
|
||||
$ThisFileInfo['error'][] = 'failed to rar_open('.$ThisFileInfo['filename'].')';
|
||||
}
|
||||
} else {
|
||||
$ThisFileInfo['error'][] = 'RAR support does not appear to be available in this PHP installation';
|
||||
}
|
||||
} else {
|
||||
$ThisFileInfo['error'][] = 'PHP-RAR processing has been disabled (set $getid3_rar->option_use_rar_extension=true to enable)';
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,419 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.archive.zip.php //
|
||||
// module for analyzing pkZip files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_zip
|
||||
{
|
||||
|
||||
function getid3_zip(&$fd, &$ThisFileInfo) {
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'zip';
|
||||
$ThisFileInfo['zip']['encoding'] = 'ISO-8859-1';
|
||||
$ThisFileInfo['zip']['files'] = array();
|
||||
|
||||
$ThisFileInfo['zip']['compressed_size'] = 0;
|
||||
$ThisFileInfo['zip']['uncompressed_size'] = 0;
|
||||
$ThisFileInfo['zip']['entries_count'] = 0;
|
||||
|
||||
if (!getid3_lib::intValueSupported($ThisFileInfo['filesize'])) {
|
||||
$ThisFileInfo['error'][] = 'File is larger than '.round(PHP_INT_MAX / 1073741824).'GB, not supported by PHP';
|
||||
return false;
|
||||
} else {
|
||||
$EOCDsearchData = '';
|
||||
$EOCDsearchCounter = 0;
|
||||
while ($EOCDsearchCounter++ < 512) {
|
||||
|
||||
fseek($fd, -128 * $EOCDsearchCounter, SEEK_END);
|
||||
$EOCDsearchData = fread($fd, 128).$EOCDsearchData;
|
||||
|
||||
if (strstr($EOCDsearchData, 'PK'."\x05\x06")) {
|
||||
|
||||
$EOCDposition = strpos($EOCDsearchData, 'PK'."\x05\x06");
|
||||
fseek($fd, (-128 * $EOCDsearchCounter) + $EOCDposition, SEEK_END);
|
||||
$ThisFileInfo['zip']['end_central_directory'] = $this->ZIPparseEndOfCentralDirectory($fd);
|
||||
|
||||
fseek($fd, $ThisFileInfo['zip']['end_central_directory']['directory_offset'], SEEK_SET);
|
||||
$ThisFileInfo['zip']['entries_count'] = 0;
|
||||
while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($fd)) {
|
||||
$ThisFileInfo['zip']['central_directory'][] = $centraldirectoryentry;
|
||||
$ThisFileInfo['zip']['entries_count']++;
|
||||
$ThisFileInfo['zip']['compressed_size'] += $centraldirectoryentry['compressed_size'];
|
||||
$ThisFileInfo['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size'];
|
||||
|
||||
if ($centraldirectoryentry['uncompressed_size'] > 0) {
|
||||
$ThisFileInfo['zip']['files'] = getid3_lib::array_merge_clobber($ThisFileInfo['zip']['files'], getid3_lib::CreateDeepArray($centraldirectoryentry['filename'], '/', $centraldirectoryentry['uncompressed_size']));
|
||||
}
|
||||
}
|
||||
|
||||
if ($ThisFileInfo['zip']['entries_count'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'No Central Directory entries found (truncated file?)';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($ThisFileInfo['zip']['end_central_directory']['comment'])) {
|
||||
$ThisFileInfo['zip']['comments']['comment'][] = $ThisFileInfo['zip']['end_central_directory']['comment'];
|
||||
}
|
||||
|
||||
if (isset($ThisFileInfo['zip']['central_directory'][0]['compression_method'])) {
|
||||
$ThisFileInfo['zip']['compression_method'] = $ThisFileInfo['zip']['central_directory'][0]['compression_method'];
|
||||
}
|
||||
if (isset($ThisFileInfo['zip']['central_directory'][0]['flags']['compression_speed'])) {
|
||||
$ThisFileInfo['zip']['compression_speed'] = $ThisFileInfo['zip']['central_directory'][0]['flags']['compression_speed'];
|
||||
}
|
||||
if (isset($ThisFileInfo['zip']['compression_method']) && ($ThisFileInfo['zip']['compression_method'] == 'store') && !isset($ThisFileInfo['zip']['compression_speed'])) {
|
||||
$ThisFileInfo['zip']['compression_speed'] = 'store';
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->getZIPentriesFilepointer($fd, $ThisFileInfo)) {
|
||||
|
||||
// central directory couldn't be found and/or parsed
|
||||
// scan through actual file data entries, recover as much as possible from probable trucated file
|
||||
if ($ThisFileInfo['zip']['compressed_size'] > ($ThisFileInfo['filesize'] - 46 - 22)) {
|
||||
$ThisFileInfo['error'][] = 'Warning: Truncated file! - Total compressed file sizes ('.$ThisFileInfo['zip']['compressed_size'].' bytes) is greater than filesize minus Central Directory and End Of Central Directory structures ('.($ThisFileInfo['filesize'] - 46 - 22).' bytes)';
|
||||
}
|
||||
$ThisFileInfo['error'][] = 'Cannot find End Of Central Directory - returned list of files in [zip][entries] array may not be complete';
|
||||
foreach ($ThisFileInfo['zip']['entries'] as $key => $valuearray) {
|
||||
$ThisFileInfo['zip']['files'][$valuearray['filename']] = $valuearray['uncompressed_size'];
|
||||
}
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
unset($ThisFileInfo['zip']);
|
||||
$ThisFileInfo['fileformat'] = '';
|
||||
$ThisFileInfo['error'][] = 'Cannot find End Of Central Directory (truncated file?)';
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getZIPHeaderFilepointerTopDown(&$fd, &$ThisFileInfo) {
|
||||
$ThisFileInfo['fileformat'] = 'zip';
|
||||
|
||||
$ThisFileInfo['zip']['compressed_size'] = 0;
|
||||
$ThisFileInfo['zip']['uncompressed_size'] = 0;
|
||||
$ThisFileInfo['zip']['entries_count'] = 0;
|
||||
|
||||
rewind($fd);
|
||||
while ($fileentry = $this->ZIPparseLocalFileHeader($fd)) {
|
||||
$ThisFileInfo['zip']['entries'][] = $fileentry;
|
||||
$ThisFileInfo['zip']['entries_count']++;
|
||||
}
|
||||
if ($ThisFileInfo['zip']['entries_count'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'No Local File Header entries found';
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['zip']['entries_count'] = 0;
|
||||
while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($fd)) {
|
||||
$ThisFileInfo['zip']['central_directory'][] = $centraldirectoryentry;
|
||||
$ThisFileInfo['zip']['entries_count']++;
|
||||
$ThisFileInfo['zip']['compressed_size'] += $centraldirectoryentry['compressed_size'];
|
||||
$ThisFileInfo['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size'];
|
||||
}
|
||||
if ($ThisFileInfo['zip']['entries_count'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'No Central Directory entries found (truncated file?)';
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($EOCD = $this->ZIPparseEndOfCentralDirectory($fd)) {
|
||||
$ThisFileInfo['zip']['end_central_directory'] = $EOCD;
|
||||
} else {
|
||||
$ThisFileInfo['error'][] = 'No End Of Central Directory entry found (truncated file?)';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($ThisFileInfo['zip']['end_central_directory']['comment'])) {
|
||||
$ThisFileInfo['zip']['comments']['comment'][] = $ThisFileInfo['zip']['end_central_directory']['comment'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function getZIPentriesFilepointer(&$fd, &$ThisFileInfo) {
|
||||
$ThisFileInfo['zip']['compressed_size'] = 0;
|
||||
$ThisFileInfo['zip']['uncompressed_size'] = 0;
|
||||
$ThisFileInfo['zip']['entries_count'] = 0;
|
||||
|
||||
rewind($fd);
|
||||
while ($fileentry = $this->ZIPparseLocalFileHeader($fd)) {
|
||||
$ThisFileInfo['zip']['entries'][] = $fileentry;
|
||||
$ThisFileInfo['zip']['entries_count']++;
|
||||
$ThisFileInfo['zip']['compressed_size'] += $fileentry['compressed_size'];
|
||||
$ThisFileInfo['zip']['uncompressed_size'] += $fileentry['uncompressed_size'];
|
||||
}
|
||||
if ($ThisFileInfo['zip']['entries_count'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'No Local File Header entries found';
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function ZIPparseLocalFileHeader(&$fd) {
|
||||
$LocalFileHeader['offset'] = ftell($fd);
|
||||
|
||||
$ZIPlocalFileHeader = fread($fd, 30);
|
||||
|
||||
$LocalFileHeader['raw']['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 0, 4));
|
||||
if ($LocalFileHeader['raw']['signature'] != 0x04034B50) {
|
||||
// invalid Local File Header Signature
|
||||
fseek($fd, $LocalFileHeader['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly
|
||||
return false;
|
||||
}
|
||||
$LocalFileHeader['raw']['extract_version'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 4, 2));
|
||||
$LocalFileHeader['raw']['general_flags'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 6, 2));
|
||||
$LocalFileHeader['raw']['compression_method'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 8, 2));
|
||||
$LocalFileHeader['raw']['last_mod_file_time'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 10, 2));
|
||||
$LocalFileHeader['raw']['last_mod_file_date'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 12, 2));
|
||||
$LocalFileHeader['raw']['crc_32'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 14, 4));
|
||||
$LocalFileHeader['raw']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 18, 4));
|
||||
$LocalFileHeader['raw']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 22, 4));
|
||||
$LocalFileHeader['raw']['filename_length'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 26, 2));
|
||||
$LocalFileHeader['raw']['extra_field_length'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 28, 2));
|
||||
|
||||
$LocalFileHeader['extract_version'] = sprintf('%1.1f', $LocalFileHeader['raw']['extract_version'] / 10);
|
||||
$LocalFileHeader['host_os'] = $this->ZIPversionOSLookup(($LocalFileHeader['raw']['extract_version'] & 0xFF00) >> 8);
|
||||
$LocalFileHeader['compression_method'] = $this->ZIPcompressionMethodLookup($LocalFileHeader['raw']['compression_method']);
|
||||
$LocalFileHeader['compressed_size'] = $LocalFileHeader['raw']['compressed_size'];
|
||||
$LocalFileHeader['uncompressed_size'] = $LocalFileHeader['raw']['uncompressed_size'];
|
||||
$LocalFileHeader['flags'] = $this->ZIPparseGeneralPurposeFlags($LocalFileHeader['raw']['general_flags'], $LocalFileHeader['raw']['compression_method']);
|
||||
$LocalFileHeader['last_modified_timestamp'] = $this->DOStime2UNIXtime($LocalFileHeader['raw']['last_mod_file_date'], $LocalFileHeader['raw']['last_mod_file_time']);
|
||||
|
||||
$FilenameExtrafieldLength = $LocalFileHeader['raw']['filename_length'] + $LocalFileHeader['raw']['extra_field_length'];
|
||||
if ($FilenameExtrafieldLength > 0) {
|
||||
$ZIPlocalFileHeader .= fread($fd, $FilenameExtrafieldLength);
|
||||
|
||||
if ($LocalFileHeader['raw']['filename_length'] > 0) {
|
||||
$LocalFileHeader['filename'] = substr($ZIPlocalFileHeader, 30, $LocalFileHeader['raw']['filename_length']);
|
||||
}
|
||||
if ($LocalFileHeader['raw']['extra_field_length'] > 0) {
|
||||
$LocalFileHeader['raw']['extra_field_data'] = substr($ZIPlocalFileHeader, 30 + $LocalFileHeader['raw']['filename_length'], $LocalFileHeader['raw']['extra_field_length']);
|
||||
}
|
||||
}
|
||||
|
||||
$LocalFileHeader['data_offset'] = ftell($fd);
|
||||
//$LocalFileHeader['compressed_data'] = fread($fd, $LocalFileHeader['raw']['compressed_size']);
|
||||
fseek($fd, $LocalFileHeader['raw']['compressed_size'], SEEK_CUR);
|
||||
|
||||
if ($LocalFileHeader['flags']['data_descriptor_used']) {
|
||||
$DataDescriptor = fread($fd, 12);
|
||||
$LocalFileHeader['data_descriptor']['crc_32'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 0, 4));
|
||||
$LocalFileHeader['data_descriptor']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 4, 4));
|
||||
$LocalFileHeader['data_descriptor']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 8, 4));
|
||||
}
|
||||
|
||||
return $LocalFileHeader;
|
||||
}
|
||||
|
||||
|
||||
function ZIPparseCentralDirectory(&$fd) {
|
||||
$CentralDirectory['offset'] = ftell($fd);
|
||||
|
||||
$ZIPcentralDirectory = fread($fd, 46);
|
||||
|
||||
$CentralDirectory['raw']['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 0, 4));
|
||||
if ($CentralDirectory['raw']['signature'] != 0x02014B50) {
|
||||
// invalid Central Directory Signature
|
||||
fseek($fd, $CentralDirectory['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly
|
||||
return false;
|
||||
}
|
||||
$CentralDirectory['raw']['create_version'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 4, 2));
|
||||
$CentralDirectory['raw']['extract_version'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 6, 2));
|
||||
$CentralDirectory['raw']['general_flags'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 8, 2));
|
||||
$CentralDirectory['raw']['compression_method'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 10, 2));
|
||||
$CentralDirectory['raw']['last_mod_file_time'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 12, 2));
|
||||
$CentralDirectory['raw']['last_mod_file_date'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 14, 2));
|
||||
$CentralDirectory['raw']['crc_32'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 16, 4));
|
||||
$CentralDirectory['raw']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 20, 4));
|
||||
$CentralDirectory['raw']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 24, 4));
|
||||
$CentralDirectory['raw']['filename_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 28, 2));
|
||||
$CentralDirectory['raw']['extra_field_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 30, 2));
|
||||
$CentralDirectory['raw']['file_comment_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 32, 2));
|
||||
$CentralDirectory['raw']['disk_number_start'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 34, 2));
|
||||
$CentralDirectory['raw']['internal_file_attrib'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 36, 2));
|
||||
$CentralDirectory['raw']['external_file_attrib'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 38, 4));
|
||||
$CentralDirectory['raw']['local_header_offset'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 42, 4));
|
||||
|
||||
$CentralDirectory['entry_offset'] = $CentralDirectory['raw']['local_header_offset'];
|
||||
$CentralDirectory['create_version'] = sprintf('%1.1f', $CentralDirectory['raw']['create_version'] / 10);
|
||||
$CentralDirectory['extract_version'] = sprintf('%1.1f', $CentralDirectory['raw']['extract_version'] / 10);
|
||||
$CentralDirectory['host_os'] = $this->ZIPversionOSLookup(($CentralDirectory['raw']['extract_version'] & 0xFF00) >> 8);
|
||||
$CentralDirectory['compression_method'] = $this->ZIPcompressionMethodLookup($CentralDirectory['raw']['compression_method']);
|
||||
$CentralDirectory['compressed_size'] = $CentralDirectory['raw']['compressed_size'];
|
||||
$CentralDirectory['uncompressed_size'] = $CentralDirectory['raw']['uncompressed_size'];
|
||||
$CentralDirectory['flags'] = $this->ZIPparseGeneralPurposeFlags($CentralDirectory['raw']['general_flags'], $CentralDirectory['raw']['compression_method']);
|
||||
$CentralDirectory['last_modified_timestamp'] = $this->DOStime2UNIXtime($CentralDirectory['raw']['last_mod_file_date'], $CentralDirectory['raw']['last_mod_file_time']);
|
||||
|
||||
$FilenameExtrafieldCommentLength = $CentralDirectory['raw']['filename_length'] + $CentralDirectory['raw']['extra_field_length'] + $CentralDirectory['raw']['file_comment_length'];
|
||||
if ($FilenameExtrafieldCommentLength > 0) {
|
||||
$FilenameExtrafieldComment = fread($fd, $FilenameExtrafieldCommentLength);
|
||||
|
||||
if ($CentralDirectory['raw']['filename_length'] > 0) {
|
||||
$CentralDirectory['filename'] = substr($FilenameExtrafieldComment, 0, $CentralDirectory['raw']['filename_length']);
|
||||
}
|
||||
if ($CentralDirectory['raw']['extra_field_length'] > 0) {
|
||||
$CentralDirectory['raw']['extra_field_data'] = substr($FilenameExtrafieldComment, $CentralDirectory['raw']['filename_length'], $CentralDirectory['raw']['extra_field_length']);
|
||||
}
|
||||
if ($CentralDirectory['raw']['file_comment_length'] > 0) {
|
||||
$CentralDirectory['file_comment'] = substr($FilenameExtrafieldComment, $CentralDirectory['raw']['filename_length'] + $CentralDirectory['raw']['extra_field_length'], $CentralDirectory['raw']['file_comment_length']);
|
||||
}
|
||||
}
|
||||
|
||||
return $CentralDirectory;
|
||||
}
|
||||
|
||||
function ZIPparseEndOfCentralDirectory(&$fd) {
|
||||
$EndOfCentralDirectory['offset'] = ftell($fd);
|
||||
|
||||
$ZIPendOfCentralDirectory = fread($fd, 22);
|
||||
|
||||
$EndOfCentralDirectory['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 0, 4));
|
||||
if ($EndOfCentralDirectory['signature'] != 0x06054B50) {
|
||||
// invalid End Of Central Directory Signature
|
||||
fseek($fd, $EndOfCentralDirectory['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly
|
||||
return false;
|
||||
}
|
||||
$EndOfCentralDirectory['disk_number_current'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 4, 2));
|
||||
$EndOfCentralDirectory['disk_number_start_directory'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 6, 2));
|
||||
$EndOfCentralDirectory['directory_entries_this_disk'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 8, 2));
|
||||
$EndOfCentralDirectory['directory_entries_total'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 10, 2));
|
||||
$EndOfCentralDirectory['directory_size'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 12, 4));
|
||||
$EndOfCentralDirectory['directory_offset'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 16, 4));
|
||||
$EndOfCentralDirectory['comment_length'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 20, 2));
|
||||
|
||||
if ($EndOfCentralDirectory['comment_length'] > 0) {
|
||||
$EndOfCentralDirectory['comment'] = fread($fd, $EndOfCentralDirectory['comment_length']);
|
||||
}
|
||||
|
||||
return $EndOfCentralDirectory;
|
||||
}
|
||||
|
||||
|
||||
function ZIPparseGeneralPurposeFlags($flagbytes, $compressionmethod) {
|
||||
$ParsedFlags['encrypted'] = (bool) ($flagbytes & 0x0001);
|
||||
|
||||
switch ($compressionmethod) {
|
||||
case 6:
|
||||
$ParsedFlags['dictionary_size'] = (($flagbytes & 0x0002) ? 8192 : 4096);
|
||||
$ParsedFlags['shannon_fano_trees'] = (($flagbytes & 0x0004) ? 3 : 2);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
case 9:
|
||||
switch (($flagbytes & 0x0006) >> 1) {
|
||||
case 0:
|
||||
$ParsedFlags['compression_speed'] = 'normal';
|
||||
break;
|
||||
case 1:
|
||||
$ParsedFlags['compression_speed'] = 'maximum';
|
||||
break;
|
||||
case 2:
|
||||
$ParsedFlags['compression_speed'] = 'fast';
|
||||
break;
|
||||
case 3:
|
||||
$ParsedFlags['compression_speed'] = 'superfast';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
$ParsedFlags['data_descriptor_used'] = (bool) ($flagbytes & 0x0008);
|
||||
|
||||
return $ParsedFlags;
|
||||
}
|
||||
|
||||
|
||||
function ZIPversionOSLookup($index) {
|
||||
static $ZIPversionOSLookup = array(
|
||||
0 => 'MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)',
|
||||
1 => 'Amiga',
|
||||
2 => 'OpenVMS',
|
||||
3 => 'Unix',
|
||||
4 => 'VM/CMS',
|
||||
5 => 'Atari ST',
|
||||
6 => 'OS/2 H.P.F.S.',
|
||||
7 => 'Macintosh',
|
||||
8 => 'Z-System',
|
||||
9 => 'CP/M',
|
||||
10 => 'Windows NTFS',
|
||||
11 => 'MVS',
|
||||
12 => 'VSE',
|
||||
13 => 'Acorn Risc',
|
||||
14 => 'VFAT',
|
||||
15 => 'Alternate MVS',
|
||||
16 => 'BeOS',
|
||||
17 => 'Tandem'
|
||||
);
|
||||
|
||||
return (isset($ZIPversionOSLookup[$index]) ? $ZIPversionOSLookup[$index] : '[unknown]');
|
||||
}
|
||||
|
||||
function ZIPcompressionMethodLookup($index) {
|
||||
static $ZIPcompressionMethodLookup = array(
|
||||
0 => 'store',
|
||||
1 => 'shrink',
|
||||
2 => 'reduce-1',
|
||||
3 => 'reduce-2',
|
||||
4 => 'reduce-3',
|
||||
5 => 'reduce-4',
|
||||
6 => 'implode',
|
||||
7 => 'tokenize',
|
||||
8 => 'deflate',
|
||||
9 => 'deflate64',
|
||||
10 => 'PKWARE Date Compression Library Imploding'
|
||||
);
|
||||
|
||||
return (isset($ZIPcompressionMethodLookup[$index]) ? $ZIPcompressionMethodLookup[$index] : '[unknown]');
|
||||
}
|
||||
|
||||
function DOStime2UNIXtime($DOSdate, $DOStime) {
|
||||
// wFatDate
|
||||
// Specifies the MS-DOS date. The date is a packed 16-bit value with the following format:
|
||||
// Bits Contents
|
||||
// 0-4 Day of the month (1-31)
|
||||
// 5-8 Month (1 = January, 2 = February, and so on)
|
||||
// 9-15 Year offset from 1980 (add 1980 to get actual year)
|
||||
|
||||
$UNIXday = ($DOSdate & 0x001F);
|
||||
$UNIXmonth = (($DOSdate & 0x01E0) >> 5);
|
||||
$UNIXyear = (($DOSdate & 0xFE00) >> 9) + 1980;
|
||||
|
||||
// wFatTime
|
||||
// Specifies the MS-DOS time. The time is a packed 16-bit value with the following format:
|
||||
// Bits Contents
|
||||
// 0-4 Second divided by 2
|
||||
// 5-10 Minute (0-59)
|
||||
// 11-15 Hour (0-23 on a 24-hour clock)
|
||||
|
||||
$UNIXsecond = ($DOStime & 0x001F) * 2;
|
||||
$UNIXminute = (($DOStime & 0x07E0) >> 5);
|
||||
$UNIXhour = (($DOStime & 0xF800) >> 11);
|
||||
|
||||
return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,70 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.bink.php //
|
||||
// module for analyzing Bink or Smacker audio-video files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_bink
|
||||
{
|
||||
|
||||
function getid3_bink(&$fd, &$ThisFileInfo) {
|
||||
|
||||
$ThisFileInfo['error'][] = 'Bink / Smacker files not properly processed by this version of getID3()';
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$fileTypeID = fread($fd, 3);
|
||||
switch ($fileTypeID) {
|
||||
case 'BIK':
|
||||
return $this->ParseBink($fd, $ThisFileInfo);
|
||||
break;
|
||||
|
||||
case 'SMK':
|
||||
return $this->ParseSmacker($fd, $ThisFileInfo);
|
||||
break;
|
||||
|
||||
default:
|
||||
$ThisFileInfo['error'][] = 'Expecting "BIK" or "SMK" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$fileTypeID.'"';
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
function ParseBink(&$fd, &$ThisFileInfo) {
|
||||
$ThisFileInfo['fileformat'] = 'bink';
|
||||
$ThisFileInfo['video']['dataformat'] = 'bink';
|
||||
|
||||
$fileData = 'BIK'.fread($fd, 13);
|
||||
|
||||
$ThisFileInfo['bink']['data_size'] = getid3_lib::LittleEndian2Int(substr($fileData, 4, 4));
|
||||
$ThisFileInfo['bink']['frame_count'] = getid3_lib::LittleEndian2Int(substr($fileData, 8, 2));
|
||||
|
||||
if (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) != ($ThisFileInfo['bink']['data_size'] + 8)) {
|
||||
$ThisFileInfo['error'][] = 'Probably truncated file: expecting '.$ThisFileInfo['bink']['data_size'].' bytes, found '.($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function ParseSmacker(&$fd, &$ThisFileInfo) {
|
||||
$ThisFileInfo['fileformat'] = 'smacker';
|
||||
$ThisFileInfo['video']['dataformat'] = 'smacker';
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,718 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// //
|
||||
// FLV module by Seth Kaufman <seth@whirl-i-gig.com> //
|
||||
// //
|
||||
// * version 0.1 (26 June 2005) //
|
||||
// //
|
||||
// minor modifications by James Heinrich <info@getid3.org> //
|
||||
// * version 0.1.1 (15 July 2005) //
|
||||
// //
|
||||
// Support for On2 VP6 codec and meta information //
|
||||
// by Steve Webster <steve.webster@featurecreep.com> //
|
||||
// * version 0.2 (22 February 2006) //
|
||||
// //
|
||||
// Modified to not read entire file into memory //
|
||||
// by James Heinrich <info@getid3.org> //
|
||||
// * version 0.3 (15 June 2006) //
|
||||
// //
|
||||
// Bugfixes for incorrectly parsed FLV dimensions //
|
||||
// and incorrect parsing of onMetaTag //
|
||||
// by Evgeny Moysevich <moysevich@gmail.com> //
|
||||
// * version 0.4 (07 December 2007) //
|
||||
// //
|
||||
// Fixed parsing of audio tags and added additional codec //
|
||||
// details. The duration is now read from onMetaTag (if //
|
||||
// exists), rather than parsing whole file //
|
||||
// by Nigel Barnes <ngbarnes@hotmail.com> //
|
||||
// * version 0.5 (21 May 2009) //
|
||||
// //
|
||||
// Better parsing of files with h264 video //
|
||||
// by Evgeny Moysevich <moysevichØgmail*com> //
|
||||
// * version 0.6 (24 May 2009) //
|
||||
// //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio-video.flv.php //
|
||||
// module for analyzing Shockwave Flash Video files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
define('GETID3_FLV_TAG_AUDIO', 8);
|
||||
define('GETID3_FLV_TAG_VIDEO', 9);
|
||||
define('GETID3_FLV_TAG_META', 18);
|
||||
|
||||
define('GETID3_FLV_VIDEO_H263', 2);
|
||||
define('GETID3_FLV_VIDEO_SCREEN', 3);
|
||||
define('GETID3_FLV_VIDEO_VP6FLV', 4);
|
||||
define('GETID3_FLV_VIDEO_VP6FLV_ALPHA', 5);
|
||||
define('GETID3_FLV_VIDEO_SCREENV2', 6);
|
||||
define('GETID3_FLV_VIDEO_H264', 7);
|
||||
|
||||
define('H264_AVC_SEQUENCE_HEADER', 0);
|
||||
define('H264_PROFILE_BASELINE', 66);
|
||||
define('H264_PROFILE_MAIN', 77);
|
||||
define('H264_PROFILE_EXTENDED', 88);
|
||||
define('H264_PROFILE_HIGH', 100);
|
||||
define('H264_PROFILE_HIGH10', 110);
|
||||
define('H264_PROFILE_HIGH422', 122);
|
||||
define('H264_PROFILE_HIGH444', 144);
|
||||
define('H264_PROFILE_HIGH444_PREDICTIVE', 244);
|
||||
|
||||
class getid3_flv
|
||||
{
|
||||
|
||||
function getid3_flv(&$fd, &$ThisFileInfo, $ReturnAllTagData=false) {
|
||||
//$start_time = microtime(true);
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
|
||||
$FLVdataLength = $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'];
|
||||
$FLVheader = fread($fd, 5);
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'flv';
|
||||
$ThisFileInfo['flv']['header']['signature'] = substr($FLVheader, 0, 3);
|
||||
$ThisFileInfo['flv']['header']['version'] = getid3_lib::BigEndian2Int(substr($FLVheader, 3, 1));
|
||||
$TypeFlags = getid3_lib::BigEndian2Int(substr($FLVheader, 4, 1));
|
||||
|
||||
if ($ThisFileInfo['flv']['header']['signature'] != 'FLV') {
|
||||
$ThisFileInfo['error'][] = 'Expecting "FLV" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$ThisFileInfo['flv']['header']['signature'].'"';
|
||||
unset($ThisFileInfo['flv']);
|
||||
unset($ThisFileInfo['fileformat']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['flv']['header']['hasAudio'] = (bool) ($TypeFlags & 0x04);
|
||||
$ThisFileInfo['flv']['header']['hasVideo'] = (bool) ($TypeFlags & 0x01);
|
||||
|
||||
$FrameSizeDataLength = getid3_lib::BigEndian2Int(fread($fd, 4));
|
||||
$FLVheaderFrameLength = 9;
|
||||
if ($FrameSizeDataLength > $FLVheaderFrameLength) {
|
||||
fseek($fd, $FrameSizeDataLength - $FLVheaderFrameLength, SEEK_CUR);
|
||||
}
|
||||
//echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'<br>';
|
||||
|
||||
$Duration = 0;
|
||||
$found_video = false;
|
||||
$found_audio = false;
|
||||
$found_meta = false;
|
||||
$tagParsed = 0;
|
||||
while (((ftell($fd) + 16) < $ThisFileInfo['avdataend']) && ($tagParsed <= 20 || !$found_meta)) {
|
||||
$ThisTagHeader = fread($fd, 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($fd) - 1 + $DataLength;
|
||||
if ($Timestamp > $Duration) {
|
||||
$Duration = $Timestamp;
|
||||
}
|
||||
|
||||
//echo __LINE__.'['.ftell($fd).']=('.$TagType.')='.number_format(microtime(true) - $start_time, 3).'<br>';
|
||||
|
||||
switch ($TagType) {
|
||||
case GETID3_FLV_TAG_AUDIO:
|
||||
if (!$found_audio) {
|
||||
$found_audio = true;
|
||||
$ThisFileInfo['flv']['audio']['audioFormat'] = ($LastHeaderByte >> 4) & 0x0F;
|
||||
$ThisFileInfo['flv']['audio']['audioRate'] = ($LastHeaderByte >> 2) & 0x03;
|
||||
$ThisFileInfo['flv']['audio']['audioSampleSize'] = ($LastHeaderByte >> 1) & 0x01;
|
||||
$ThisFileInfo['flv']['audio']['audioType'] = $LastHeaderByte & 0x01;
|
||||
}
|
||||
break;
|
||||
|
||||
case GETID3_FLV_TAG_VIDEO:
|
||||
if (!$found_video) {
|
||||
$found_video = true;
|
||||
$ThisFileInfo['flv']['video']['videoCodec'] = $LastHeaderByte & 0x07;
|
||||
|
||||
$FLVvideoHeader = fread($fd, 11);
|
||||
|
||||
if ($ThisFileInfo['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H264) {
|
||||
// this code block contributed by: moysevichØgmail*com
|
||||
|
||||
$AVCPacketType = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 0, 1));
|
||||
if ($AVCPacketType == H264_AVC_SEQUENCE_HEADER) {
|
||||
// read AVCDecoderConfigurationRecord
|
||||
$configurationVersion = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 1));
|
||||
$AVCProfileIndication = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 1));
|
||||
$profile_compatibility = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 1));
|
||||
$lengthSizeMinusOne = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 7, 1));
|
||||
$numOfSequenceParameterSets = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 8, 1));
|
||||
|
||||
if (($numOfSequenceParameterSets & 0x1F) != 0) {
|
||||
// there is at least one SequenceParameterSet
|
||||
// read size of the first SequenceParameterSet
|
||||
//$spsSize = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 9, 2));
|
||||
$spsSize = getid3_lib::LittleEndian2Int(substr($FLVvideoHeader, 9, 2));
|
||||
// read the first SequenceParameterSet
|
||||
$sps = fread($fd, $spsSize);
|
||||
if (strlen($sps) == $spsSize) { // make sure that whole SequenceParameterSet was red
|
||||
$spsReader = new AVCSequenceParameterSetReader($sps);
|
||||
$spsReader->readData();
|
||||
$ThisFileInfo['video']['resolution_x'] = $spsReader->getWidth();
|
||||
$ThisFileInfo['video']['resolution_y'] = $spsReader->getHeight();
|
||||
}
|
||||
}
|
||||
}
|
||||
// end: moysevichØgmail*com
|
||||
|
||||
} elseif ($ThisFileInfo['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H263) {
|
||||
|
||||
$PictureSizeType = (getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 3, 2))) >> 7;
|
||||
$PictureSizeType = $PictureSizeType & 0x0007;
|
||||
$ThisFileInfo['flv']['header']['videoSizeType'] = $PictureSizeType;
|
||||
switch ($PictureSizeType) {
|
||||
case 0:
|
||||
//$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2));
|
||||
//$PictureSizeEnc <<= 1;
|
||||
//$ThisFileInfo['video']['resolution_x'] = ($PictureSizeEnc & 0xFF00) >> 8;
|
||||
//$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 2));
|
||||
//$PictureSizeEnc <<= 1;
|
||||
//$ThisFileInfo['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;
|
||||
$ThisFileInfo['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFF;
|
||||
$ThisFileInfo['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;
|
||||
$ThisFileInfo['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFFFF;
|
||||
$ThisFileInfo['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFFFF;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$ThisFileInfo['video']['resolution_x'] = 352;
|
||||
$ThisFileInfo['video']['resolution_y'] = 288;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$ThisFileInfo['video']['resolution_x'] = 176;
|
||||
$ThisFileInfo['video']['resolution_y'] = 144;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
$ThisFileInfo['video']['resolution_x'] = 128;
|
||||
$ThisFileInfo['video']['resolution_y'] = 96;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
$ThisFileInfo['video']['resolution_x'] = 320;
|
||||
$ThisFileInfo['video']['resolution_y'] = 240;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
$ThisFileInfo['video']['resolution_x'] = 160;
|
||||
$ThisFileInfo['video']['resolution_y'] = 120;
|
||||
break;
|
||||
|
||||
default:
|
||||
$ThisFileInfo['video']['resolution_x'] = 0;
|
||||
$ThisFileInfo['video']['resolution_y'] = 0;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
$ThisFileInfo['video']['pixel_aspect_ratio'] = $ThisFileInfo['video']['resolution_x'] / $ThisFileInfo['video']['resolution_y'];
|
||||
}
|
||||
break;
|
||||
|
||||
// Meta tag
|
||||
case GETID3_FLV_TAG_META:
|
||||
if (!$found_meta) {
|
||||
$found_meta = true;
|
||||
fseek($fd, -1, SEEK_CUR);
|
||||
$datachunk = fread($fd, $DataLength);
|
||||
$AMFstream = new AMFStream($datachunk);
|
||||
$reader = new AMFReader($AMFstream);
|
||||
$eventName = $reader->readData();
|
||||
$ThisFileInfo['flv']['meta'][$eventName] = $reader->readData();
|
||||
unset($reader);
|
||||
|
||||
$copykeys = array('framerate'=>'frame_rate', 'width'=>'resolution_x', 'height'=>'resolution_y', 'audiodatarate'=>'bitrate', 'videodatarate'=>'bitrate');
|
||||
foreach ($copykeys as $sourcekey => $destkey) {
|
||||
if (isset($ThisFileInfo['flv']['meta']['onMetaData'][$sourcekey])) {
|
||||
switch ($sourcekey) {
|
||||
case 'width':
|
||||
case 'height':
|
||||
$ThisFileInfo['video'][$destkey] = intval(round($ThisFileInfo['flv']['meta']['onMetaData'][$sourcekey]));
|
||||
break;
|
||||
case 'audiodatarate':
|
||||
$ThisFileInfo['audio'][$destkey] = $ThisFileInfo['flv']['meta']['onMetaData'][$sourcekey];
|
||||
break;
|
||||
case 'videodatarate':
|
||||
case 'frame_rate':
|
||||
default:
|
||||
$ThisFileInfo['video'][$destkey] = $ThisFileInfo['flv']['meta']['onMetaData'][$sourcekey];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// noop
|
||||
break;
|
||||
}
|
||||
|
||||
fseek($fd, $NextOffset, SEEK_SET);
|
||||
|
||||
// Increase parsed tag count: break out of loop if more than 20 tags parsed
|
||||
$tagParsed++;
|
||||
}
|
||||
|
||||
$ThisFileInfo['playtime_seconds'] = $Duration / 1000;
|
||||
if ($ThisFileInfo['playtime_seconds'] > 0) {
|
||||
$ThisFileInfo['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
|
||||
}
|
||||
|
||||
if ($ThisFileInfo['flv']['header']['hasAudio']) {
|
||||
$ThisFileInfo['audio']['codec'] = $this->FLVaudioFormat($ThisFileInfo['flv']['audio']['audioFormat']);
|
||||
$ThisFileInfo['audio']['sample_rate'] = $this->FLVaudioRate($ThisFileInfo['flv']['audio']['audioRate']);
|
||||
$ThisFileInfo['audio']['bits_per_sample'] = $this->FLVaudioBitDepth($ThisFileInfo['flv']['audio']['audioSampleSize']);
|
||||
|
||||
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['flv']['audio']['audioType'] + 1; // 0=mono,1=stereo
|
||||
$ThisFileInfo['audio']['lossless'] = ($ThisFileInfo['flv']['audio']['audioFormat'] ? false : true); // 0=uncompressed
|
||||
$ThisFileInfo['audio']['dataformat'] = 'flv';
|
||||
}
|
||||
if (!empty($ThisFileInfo['flv']['header']['hasVideo'])) {
|
||||
$ThisFileInfo['video']['codec'] = $this->FLVvideoCodec($ThisFileInfo['flv']['video']['videoCodec']);
|
||||
$ThisFileInfo['video']['dataformat'] = 'flv';
|
||||
$ThisFileInfo['video']['lossless'] = false;
|
||||
}
|
||||
|
||||
// Set information from meta
|
||||
if (isset($ThisFileInfo['flv']['meta']['onMetaData']['duration'])) {
|
||||
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['flv']['meta']['onMetaData']['duration'];
|
||||
$ThisFileInfo['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
|
||||
}
|
||||
if (isset($ThisFileInfo['flv']['meta']['onMetaData']['audiocodecid'])) {
|
||||
$ThisFileInfo['audio']['codec'] = $this->FLVaudioFormat($ThisFileInfo['flv']['meta']['onMetaData']['audiocodecid']);
|
||||
}
|
||||
if (isset($ThisFileInfo['flv']['meta']['onMetaData']['videocodecid'])) {
|
||||
$ThisFileInfo['video']['codec'] = $this->FLVvideoCodec($ThisFileInfo['flv']['meta']['onMetaData']['videocodecid']);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function FLVaudioFormat($id) {
|
||||
$FLVaudioFormat = array(
|
||||
0 => 'Linear PCM, platform endian',
|
||||
1 => 'ADPCM',
|
||||
2 => 'mp3',
|
||||
3 => 'Linear PCM, little endian',
|
||||
4 => 'Nellymoser 16kHz mono',
|
||||
5 => 'Nellymoser 8kHz mono',
|
||||
6 => 'Nellymoser',
|
||||
7 => 'G.711A-law logarithmic PCM',
|
||||
8 => 'G.711 mu-law logarithmic PCM',
|
||||
9 => 'reserved',
|
||||
10 => 'AAC',
|
||||
11 => false, // unknown?
|
||||
12 => false, // unknown?
|
||||
13 => false, // unknown?
|
||||
14 => 'mp3 8kHz',
|
||||
15 => 'Device-specific sound',
|
||||
);
|
||||
return (isset($FLVaudioFormat[$id]) ? $FLVaudioFormat[$id] : false);
|
||||
}
|
||||
|
||||
function FLVaudioRate($id) {
|
||||
$FLVaudioRate = array(
|
||||
0 => 5500,
|
||||
1 => 11025,
|
||||
2 => 22050,
|
||||
3 => 44100,
|
||||
);
|
||||
return (isset($FLVaudioRate[$id]) ? $FLVaudioRate[$id] : false);
|
||||
}
|
||||
|
||||
function FLVaudioBitDepth($id) {
|
||||
$FLVaudioBitDepth = array(
|
||||
0 => 8,
|
||||
1 => 16,
|
||||
);
|
||||
return (isset($FLVaudioBitDepth[$id]) ? $FLVaudioBitDepth[$id] : false);
|
||||
}
|
||||
|
||||
function FLVvideoCodec($id) {
|
||||
$FLVvideoCodec = array(
|
||||
GETID3_FLV_VIDEO_H263 => 'Sorenson H.263',
|
||||
GETID3_FLV_VIDEO_SCREEN => 'Screen video',
|
||||
GETID3_FLV_VIDEO_VP6FLV => 'On2 VP6',
|
||||
GETID3_FLV_VIDEO_VP6FLV_ALPHA => 'On2 VP6 with alpha channel',
|
||||
GETID3_FLV_VIDEO_SCREENV2 => 'Screen video v2',
|
||||
GETID3_FLV_VIDEO_H264 => 'Sorenson H.264',
|
||||
);
|
||||
return (isset($FLVvideoCodec[$id]) ? $FLVvideoCodec[$id] : false);
|
||||
}
|
||||
}
|
||||
|
||||
class AMFStream {
|
||||
var $bytes;
|
||||
var $pos;
|
||||
|
||||
function AMFStream(&$bytes) {
|
||||
$this->bytes =& $bytes;
|
||||
$this->pos = 0;
|
||||
}
|
||||
|
||||
function readByte() {
|
||||
return getid3_lib::BigEndian2Int(substr($this->bytes, $this->pos++, 1));
|
||||
}
|
||||
|
||||
function readInt() {
|
||||
return ($this->readByte() << 8) + $this->readByte();
|
||||
}
|
||||
|
||||
function readLong() {
|
||||
return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte();
|
||||
}
|
||||
|
||||
function readDouble() {
|
||||
return getid3_lib::BigEndian2Float($this->read(8));
|
||||
}
|
||||
|
||||
function readUTF() {
|
||||
$length = $this->readInt();
|
||||
return $this->read($length);
|
||||
}
|
||||
|
||||
function readLongUTF() {
|
||||
$length = $this->readLong();
|
||||
return $this->read($length);
|
||||
}
|
||||
|
||||
function read($length) {
|
||||
$val = substr($this->bytes, $this->pos, $length);
|
||||
$this->pos += $length;
|
||||
return $val;
|
||||
}
|
||||
|
||||
function peekByte() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readByte();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
|
||||
function peekInt() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readInt();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
|
||||
function peekLong() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readLong();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
|
||||
function peekDouble() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readDouble();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
|
||||
function peekUTF() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readUTF();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
|
||||
function peekLongUTF() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readLongUTF();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
|
||||
class AMFReader {
|
||||
var $stream;
|
||||
|
||||
function AMFReader(&$stream) {
|
||||
$this->stream =& $stream;
|
||||
}
|
||||
|
||||
function readData() {
|
||||
$value = null;
|
||||
|
||||
$type = $this->stream->readByte();
|
||||
switch ($type) {
|
||||
|
||||
// Double
|
||||
case 0:
|
||||
$value = $this->readDouble();
|
||||
break;
|
||||
|
||||
// Boolean
|
||||
case 1:
|
||||
$value = $this->readBoolean();
|
||||
break;
|
||||
|
||||
// String
|
||||
case 2:
|
||||
$value = $this->readString();
|
||||
break;
|
||||
|
||||
// Object
|
||||
case 3:
|
||||
$value = $this->readObject();
|
||||
break;
|
||||
|
||||
// null
|
||||
case 6:
|
||||
return null;
|
||||
break;
|
||||
|
||||
// Mixed array
|
||||
case 8:
|
||||
$value = $this->readMixedArray();
|
||||
break;
|
||||
|
||||
// Array
|
||||
case 10:
|
||||
$value = $this->readArray();
|
||||
break;
|
||||
|
||||
// Date
|
||||
case 11:
|
||||
$value = $this->readDate();
|
||||
break;
|
||||
|
||||
// Long string
|
||||
case 13:
|
||||
$value = $this->readLongString();
|
||||
break;
|
||||
|
||||
// XML (handled as string)
|
||||
case 15:
|
||||
$value = $this->readXML();
|
||||
break;
|
||||
|
||||
// Typed object (handled as object)
|
||||
case 16:
|
||||
$value = $this->readTypedObject();
|
||||
break;
|
||||
|
||||
// Long string
|
||||
default:
|
||||
$value = '(unknown or unsupported data type)';
|
||||
break;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
function readDouble() {
|
||||
return $this->stream->readDouble();
|
||||
}
|
||||
|
||||
function readBoolean() {
|
||||
return $this->stream->readByte() == 1;
|
||||
}
|
||||
|
||||
function readString() {
|
||||
return $this->stream->readUTF();
|
||||
}
|
||||
|
||||
function readObject() {
|
||||
// Get highest numerical index - ignored
|
||||
// $highestIndex = $this->stream->readLong();
|
||||
|
||||
$data = array();
|
||||
|
||||
while ($key = $this->stream->readUTF()) {
|
||||
$data[$key] = $this->readData();
|
||||
}
|
||||
// Mixed array record ends with empty string (0x00 0x00) and 0x09
|
||||
if (($key == '') && ($this->stream->peekByte() == 0x09)) {
|
||||
// Consume byte
|
||||
$this->stream->readByte();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
function readMixedArray() {
|
||||
// Get highest numerical index - ignored
|
||||
$highestIndex = $this->stream->readLong();
|
||||
|
||||
$data = array();
|
||||
|
||||
while ($key = $this->stream->readUTF()) {
|
||||
if (is_numeric($key)) {
|
||||
$key = (float) $key;
|
||||
}
|
||||
$data[$key] = $this->readData();
|
||||
}
|
||||
// Mixed array record ends with empty string (0x00 0x00) and 0x09
|
||||
if (($key == '') && ($this->stream->peekByte() == 0x09)) {
|
||||
// Consume byte
|
||||
$this->stream->readByte();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
function readArray() {
|
||||
$length = $this->stream->readLong();
|
||||
$data = array();
|
||||
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$data[] = $this->readData();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
function readDate() {
|
||||
$timestamp = $this->stream->readDouble();
|
||||
$timezone = $this->stream->readInt();
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
function readLongString() {
|
||||
return $this->stream->readLongUTF();
|
||||
}
|
||||
|
||||
function readXML() {
|
||||
return $this->stream->readLongUTF();
|
||||
}
|
||||
|
||||
function readTypedObject() {
|
||||
$className = $this->stream->readUTF();
|
||||
return $this->readObject();
|
||||
}
|
||||
}
|
||||
|
||||
class AVCSequenceParameterSetReader {
|
||||
var $sps;
|
||||
var $start = 0;
|
||||
var $currentBytes = 0;
|
||||
var $currentBits = 0;
|
||||
var $width;
|
||||
var $height;
|
||||
|
||||
function AVCSequenceParameterSetReader($sps) {
|
||||
$this->sps = $sps;
|
||||
}
|
||||
|
||||
function readData() {
|
||||
$this->skipBits(8);
|
||||
$this->skipBits(8);
|
||||
$profile = $this->getBits(8); // read profile
|
||||
$this->skipBits(16);
|
||||
$this->expGolombUe(); // read sps id
|
||||
if (in_array($profile, array(H264_PROFILE_HIGH, H264_PROFILE_HIGH10, H264_PROFILE_HIGH422, H264_PROFILE_HIGH444, H264_PROFILE_HIGH444_PREDICTIVE))) {
|
||||
if ($this->expGolombUe() == 3) {
|
||||
$this->skipBits(1);
|
||||
}
|
||||
$this->expGolombUe();
|
||||
$this->expGolombUe();
|
||||
$this->skipBits(1);
|
||||
if ($this->getBit()) {
|
||||
for ($i = 0; $i < 8; $i++) {
|
||||
if ($this->getBit()) {
|
||||
$size = $i < 6 ? 16 : 64;
|
||||
$lastScale = 8;
|
||||
$nextScale = 8;
|
||||
for ($j = 0; $j < $size; $j++) {
|
||||
if ($nextScale != 0) {
|
||||
$deltaScale = $this->expGolombUe();
|
||||
$nextScale = ($lastScale + $deltaScale + 256) % 256;
|
||||
}
|
||||
if ($nextScale != 0) {
|
||||
$lastScale = $nextScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$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;
|
||||
}
|
||||
|
||||
function skipBits($bits) {
|
||||
$newBits = $this->currentBits + $bits;
|
||||
$this->currentBytes += (int)floor($newBits / 8);
|
||||
$this->currentBits = $newBits % 8;
|
||||
}
|
||||
|
||||
function getBit() {
|
||||
$result = (getid3_lib::BigEndian2Int(substr($this->sps, $this->currentBytes, 1)) >> (7 - $this->currentBits)) & 0x01;
|
||||
$this->skipBits(1);
|
||||
return $result;
|
||||
}
|
||||
|
||||
function getBits($bits) {
|
||||
$result = 0;
|
||||
for ($i = 0; $i < $bits; $i++) {
|
||||
$result = ($result << 1) + $this->getBit();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function expGolombUe() {
|
||||
$significantBits = 0;
|
||||
$bit = $this->getBit();
|
||||
while ($bit == 0) {
|
||||
$significantBits++;
|
||||
$bit = $this->getBit();
|
||||
}
|
||||
return (1 << $significantBits) + $this->getBits($significantBits) - 1;
|
||||
}
|
||||
|
||||
function expGolombSe() {
|
||||
$result = $this->expGolombUe();
|
||||
if (($result & 0x01) == 0) {
|
||||
return -($result >> 1);
|
||||
} else {
|
||||
return ($result + 1) >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
function getWidth() {
|
||||
return $this->width;
|
||||
}
|
||||
|
||||
function getHeight() {
|
||||
return $this->height;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,292 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio-video.mpeg.php //
|
||||
// module for analyzing MPEG files //
|
||||
// dependencies: module.audio.mp3.php //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
|
||||
|
||||
define('GETID3_MPEG_VIDEO_PICTURE_START', "\x00\x00\x01\x00");
|
||||
define('GETID3_MPEG_VIDEO_USER_DATA_START', "\x00\x00\x01\xB2");
|
||||
define('GETID3_MPEG_VIDEO_SEQUENCE_HEADER', "\x00\x00\x01\xB3");
|
||||
define('GETID3_MPEG_VIDEO_SEQUENCE_ERROR', "\x00\x00\x01\xB4");
|
||||
define('GETID3_MPEG_VIDEO_EXTENSION_START', "\x00\x00\x01\xB5");
|
||||
define('GETID3_MPEG_VIDEO_SEQUENCE_END', "\x00\x00\x01\xB7");
|
||||
define('GETID3_MPEG_VIDEO_GROUP_START', "\x00\x00\x01\xB8");
|
||||
define('GETID3_MPEG_AUDIO_START', "\x00\x00\x01\xC0");
|
||||
|
||||
|
||||
class getid3_mpeg
|
||||
{
|
||||
|
||||
function getid3_mpeg(&$fd, &$ThisFileInfo) {
|
||||
if ($ThisFileInfo['avdataend'] <= $ThisFileInfo['avdataoffset']) {
|
||||
$ThisFileInfo['error'][] = '"avdataend" ('.$ThisFileInfo['avdataend'].') is unexpectedly less-than-or-equal-to "avdataoffset" ('.$ThisFileInfo['avdataoffset'].')';
|
||||
return false;
|
||||
}
|
||||
$ThisFileInfo['fileformat'] = 'mpeg';
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$MPEGstreamData = fread($fd, min(100000, $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']));
|
||||
$MPEGstreamDataLength = strlen($MPEGstreamData);
|
||||
|
||||
$foundVideo = true;
|
||||
$VideoChunkOffset = 0;
|
||||
while (substr($MPEGstreamData, $VideoChunkOffset++, 4) !== GETID3_MPEG_VIDEO_SEQUENCE_HEADER) {
|
||||
if ($VideoChunkOffset >= $MPEGstreamDataLength) {
|
||||
$foundVideo = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($foundVideo) {
|
||||
|
||||
// Start code 32 bits
|
||||
// horizontal frame size 12 bits
|
||||
// vertical frame size 12 bits
|
||||
// pixel aspect ratio 4 bits
|
||||
// frame rate 4 bits
|
||||
// bitrate 18 bits
|
||||
// marker bit 1 bit
|
||||
// VBV buffer size 10 bits
|
||||
// constrained parameter flag 1 bit
|
||||
// intra quant. matrix flag 1 bit
|
||||
// intra quant. matrix values 512 bits (present if matrix flag == 1)
|
||||
// non-intra quant. matrix flag 1 bit
|
||||
// non-intra quant. matrix values 512 bits (present if matrix flag == 1)
|
||||
|
||||
$ThisFileInfo['video']['dataformat'] = 'mpeg';
|
||||
|
||||
$VideoChunkOffset += (strlen(GETID3_MPEG_VIDEO_SEQUENCE_HEADER) - 1);
|
||||
|
||||
$FrameSizeDWORD = getid3_lib::BigEndian2Int(substr($MPEGstreamData, $VideoChunkOffset, 3));
|
||||
$VideoChunkOffset += 3;
|
||||
|
||||
$AspectRatioFrameRateDWORD = getid3_lib::BigEndian2Int(substr($MPEGstreamData, $VideoChunkOffset, 1));
|
||||
$VideoChunkOffset += 1;
|
||||
|
||||
$assortedinformation = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 4));
|
||||
$VideoChunkOffset += 4;
|
||||
|
||||
$ThisFileInfo['mpeg']['video']['raw']['framesize_horizontal'] = ($FrameSizeDWORD & 0xFFF000) >> 12; // 12 bits for horizontal frame size
|
||||
$ThisFileInfo['mpeg']['video']['raw']['framesize_vertical'] = ($FrameSizeDWORD & 0x000FFF); // 12 bits for vertical frame size
|
||||
$ThisFileInfo['mpeg']['video']['raw']['pixel_aspect_ratio'] = ($AspectRatioFrameRateDWORD & 0xF0) >> 4;
|
||||
$ThisFileInfo['mpeg']['video']['raw']['frame_rate'] = ($AspectRatioFrameRateDWORD & 0x0F);
|
||||
|
||||
$ThisFileInfo['mpeg']['video']['framesize_horizontal'] = $ThisFileInfo['mpeg']['video']['raw']['framesize_horizontal'];
|
||||
$ThisFileInfo['mpeg']['video']['framesize_vertical'] = $ThisFileInfo['mpeg']['video']['raw']['framesize_vertical'];
|
||||
|
||||
$ThisFileInfo['mpeg']['video']['pixel_aspect_ratio'] = $this->MPEGvideoAspectRatioLookup($ThisFileInfo['mpeg']['video']['raw']['pixel_aspect_ratio']);
|
||||
$ThisFileInfo['mpeg']['video']['pixel_aspect_ratio_text'] = $this->MPEGvideoAspectRatioTextLookup($ThisFileInfo['mpeg']['video']['raw']['pixel_aspect_ratio']);
|
||||
$ThisFileInfo['mpeg']['video']['frame_rate'] = $this->MPEGvideoFramerateLookup($ThisFileInfo['mpeg']['video']['raw']['frame_rate']);
|
||||
|
||||
$ThisFileInfo['mpeg']['video']['raw']['bitrate'] = getid3_lib::Bin2Dec(substr($assortedinformation, 0, 18));
|
||||
$ThisFileInfo['mpeg']['video']['raw']['marker_bit'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 18, 1));
|
||||
$ThisFileInfo['mpeg']['video']['raw']['vbv_buffer_size'] = getid3_lib::Bin2Dec(substr($assortedinformation, 19, 10));
|
||||
$ThisFileInfo['mpeg']['video']['raw']['constrained_param_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 29, 1));
|
||||
$ThisFileInfo['mpeg']['video']['raw']['intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 30, 1));
|
||||
if ($ThisFileInfo['mpeg']['video']['raw']['intra_quant_flag']) {
|
||||
|
||||
// read 512 bits
|
||||
$ThisFileInfo['mpeg']['video']['raw']['intra_quant'] = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 64));
|
||||
$VideoChunkOffset += 64;
|
||||
|
||||
$ThisFileInfo['mpeg']['video']['raw']['non_intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($ThisFileInfo['mpeg']['video']['raw']['intra_quant'], 511, 1));
|
||||
$ThisFileInfo['mpeg']['video']['raw']['intra_quant'] = getid3_lib::Bin2Dec(substr($assortedinformation, 31, 1)).substr(getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 64)), 0, 511);
|
||||
|
||||
if ($ThisFileInfo['mpeg']['video']['raw']['non_intra_quant_flag']) {
|
||||
$ThisFileInfo['mpeg']['video']['raw']['non_intra_quant'] = substr($MPEGstreamData, $VideoChunkOffset, 64);
|
||||
$VideoChunkOffset += 64;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$ThisFileInfo['mpeg']['video']['raw']['non_intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 31, 1));
|
||||
if ($ThisFileInfo['mpeg']['video']['raw']['non_intra_quant_flag']) {
|
||||
$ThisFileInfo['mpeg']['video']['raw']['non_intra_quant'] = substr($MPEGstreamData, $VideoChunkOffset, 64);
|
||||
$VideoChunkOffset += 64;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($ThisFileInfo['mpeg']['video']['raw']['bitrate'] == 0x3FFFF) { // 18 set bits
|
||||
|
||||
$ThisFileInfo['warning'][] = 'This version of getID3() ['.GETID3_VERSION.'] cannot determine average bitrate of VBR MPEG video files';
|
||||
$ThisFileInfo['mpeg']['video']['bitrate_mode'] = 'vbr';
|
||||
|
||||
} else {
|
||||
|
||||
$ThisFileInfo['mpeg']['video']['bitrate'] = $ThisFileInfo['mpeg']['video']['raw']['bitrate'] * 400;
|
||||
$ThisFileInfo['mpeg']['video']['bitrate_mode'] = 'cbr';
|
||||
$ThisFileInfo['video']['bitrate'] = $ThisFileInfo['mpeg']['video']['bitrate'];
|
||||
|
||||
}
|
||||
|
||||
$ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['mpeg']['video']['framesize_horizontal'];
|
||||
$ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['mpeg']['video']['framesize_vertical'];
|
||||
$ThisFileInfo['video']['frame_rate'] = $ThisFileInfo['mpeg']['video']['frame_rate'];
|
||||
$ThisFileInfo['video']['bitrate_mode'] = $ThisFileInfo['mpeg']['video']['bitrate_mode'];
|
||||
$ThisFileInfo['video']['pixel_aspect_ratio'] = $ThisFileInfo['mpeg']['video']['pixel_aspect_ratio'];
|
||||
$ThisFileInfo['video']['lossless'] = false;
|
||||
$ThisFileInfo['video']['bits_per_sample'] = 24;
|
||||
|
||||
} else {
|
||||
|
||||
$ThisFileInfo['error'][] = 'Could not find start of video block in the first 100,000 bytes (or before end of file) - this might not be an MPEG-video file?';
|
||||
|
||||
}
|
||||
|
||||
//0x000001B3 begins the sequence_header of every MPEG video stream.
|
||||
//But in MPEG-2, this header must immediately be followed by an
|
||||
//extension_start_code (0x000001B5) with a sequence_extension ID (1).
|
||||
//(This extension contains all the additional MPEG-2 stuff.)
|
||||
//MPEG-1 doesn't have this extension, so that's a sure way to tell the
|
||||
//difference between MPEG-1 and MPEG-2 video streams.
|
||||
|
||||
if (substr($MPEGstreamData, $VideoChunkOffset, 4) == GETID3_MPEG_VIDEO_EXTENSION_START) {
|
||||
$ThisFileInfo['video']['codec'] = 'MPEG-2';
|
||||
} else {
|
||||
$ThisFileInfo['video']['codec'] = 'MPEG-1';
|
||||
}
|
||||
|
||||
|
||||
$AudioChunkOffset = 0;
|
||||
while (true) {
|
||||
while (substr($MPEGstreamData, $AudioChunkOffset++, 4) !== GETID3_MPEG_AUDIO_START) {
|
||||
if ($AudioChunkOffset >= $MPEGstreamDataLength) {
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = 0; $i <= 7; $i++) {
|
||||
// some files have the MPEG-audio header 8 bytes after the end of the $00 $00 $01 $C0 signature, some have it up to 13 bytes (or more?) after
|
||||
// I have no idea why or what the difference is, so this is a stupid hack.
|
||||
// If anybody has any better idea of what's going on, please let me know - info@getid3.org
|
||||
|
||||
$dummy = $ThisFileInfo;
|
||||
if (getid3_mp3::decodeMPEGaudioHeader($fd, ($AudioChunkOffset + 3) + 8 + $i, $dummy, false)) {
|
||||
$ThisFileInfo = $dummy;
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
|
||||
$ThisFileInfo['audio']['lossless'] = false;
|
||||
break 2;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary hack to account for interleaving overhead:
|
||||
if (!empty($ThisFileInfo['video']['bitrate']) && !empty($ThisFileInfo['audio']['bitrate'])) {
|
||||
$ThisFileInfo['playtime_seconds'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / ($ThisFileInfo['video']['bitrate'] + $ThisFileInfo['audio']['bitrate']);
|
||||
|
||||
// Interleaved MPEG audio/video files have a certain amount of overhead that varies
|
||||
// by both video and audio bitrates, and not in any sensible, linear/logarithmic patter
|
||||
// Use interpolated lookup tables to approximately guess how much is overhead, because
|
||||
// playtime is calculated as filesize / total-bitrate
|
||||
$ThisFileInfo['playtime_seconds'] *= $this->MPEGsystemNonOverheadPercentage($ThisFileInfo['video']['bitrate'], $ThisFileInfo['audio']['bitrate']);
|
||||
|
||||
//switch ($ThisFileInfo['video']['bitrate']) {
|
||||
// case('5000000'):
|
||||
// $multiplier = 0.93292642112380355828048824319889;
|
||||
// break;
|
||||
// case('5500000'):
|
||||
// $multiplier = 0.93582895375200989965359777343219;
|
||||
// break;
|
||||
// case('6000000'):
|
||||
// $multiplier = 0.93796247714820932532911373859139;
|
||||
// break;
|
||||
// case('7000000'):
|
||||
// $multiplier = 0.9413264083635103463010117778776;
|
||||
// break;
|
||||
// default:
|
||||
// $multiplier = 1;
|
||||
// break;
|
||||
//}
|
||||
//$ThisFileInfo['playtime_seconds'] *= $multiplier;
|
||||
//$ThisFileInfo['warning'][] = 'Interleaved MPEG audio/video playtime may be inaccurate. With current hack should be within a few seconds of accurate. Report to info@getid3.org if off by more than 10 seconds.';
|
||||
if ($ThisFileInfo['video']['bitrate'] < 50000) {
|
||||
$ThisFileInfo['warning'][] = 'Interleaved MPEG audio/video playtime may be slightly inaccurate for video bitrates below 100kbps. Except in extreme low-bitrate situations, error should be less than 1%. Report to info@getid3.org if greater than this.';
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function MPEGsystemNonOverheadPercentage($VideoBitrate, $AudioBitrate) {
|
||||
$OverheadPercentage = 0;
|
||||
|
||||
$AudioBitrate = max(min($AudioBitrate / 1000, 384), 32); // limit to range of 32kbps - 384kbps (should be only legal bitrates, but maybe VBR?)
|
||||
$VideoBitrate = max(min($VideoBitrate / 1000, 10000), 10); // limit to range of 10kbps - 10Mbps (beyond that curves flatten anyways, no big loss)
|
||||
|
||||
|
||||
//OMBB[audiobitrate] = array(video-10kbps, video-100kbps, video-1000kbps, video-10000kbps)
|
||||
$OverheadMultiplierByBitrate[32] = array(0, 0.9676287944368530, 0.9802276264360310, 0.9844916183244460, 0.9852821845179940);
|
||||
$OverheadMultiplierByBitrate[48] = array(0, 0.9779100089209830, 0.9787770035359320, 0.9846738664076130, 0.9852683013799960);
|
||||
$OverheadMultiplierByBitrate[56] = array(0, 0.9731249855367600, 0.9776624308938040, 0.9832606361852130, 0.9843922606633340);
|
||||
$OverheadMultiplierByBitrate[64] = array(0, 0.9755642683275760, 0.9795256705493390, 0.9836573009193170, 0.9851122539404470);
|
||||
$OverheadMultiplierByBitrate[96] = array(0, 0.9788025247497290, 0.9798553314148700, 0.9822956869792560, 0.9834815119124690);
|
||||
$OverheadMultiplierByBitrate[128] = array(0, 0.9816940050925480, 0.9821675936072120, 0.9829756927470870, 0.9839763420152050);
|
||||
$OverheadMultiplierByBitrate[160] = array(0, 0.9825894094561180, 0.9820913399073960, 0.9823907143253970, 0.9832821783651570);
|
||||
$OverheadMultiplierByBitrate[192] = array(0, 0.9832038474336260, 0.9825731694317960, 0.9821028622712400, 0.9828262076447620);
|
||||
$OverheadMultiplierByBitrate[224] = array(0, 0.9836516298538770, 0.9824718601823890, 0.9818302180625380, 0.9823735101626480);
|
||||
$OverheadMultiplierByBitrate[256] = array(0, 0.9845863022094920, 0.9837229411967540, 0.9824521662210830, 0.9828645172100790);
|
||||
$OverheadMultiplierByBitrate[320] = array(0, 0.9849565280263180, 0.9837683142805110, 0.9822885275960400, 0.9824424382727190);
|
||||
$OverheadMultiplierByBitrate[384] = array(0, 0.9856094774357600, 0.9844573394432720, 0.9825970399837330, 0.9824673808303890);
|
||||
|
||||
$BitrateToUseMin = 32;
|
||||
$BitrateToUseMax = 32;
|
||||
$previousBitrate = 32;
|
||||
foreach ($OverheadMultiplierByBitrate as $key => $value) {
|
||||
if ($AudioBitrate >= $previousBitrate) {
|
||||
$BitrateToUseMin = $previousBitrate;
|
||||
}
|
||||
if ($AudioBitrate < $key) {
|
||||
$BitrateToUseMax = $key;
|
||||
break;
|
||||
}
|
||||
$previousBitrate = $key;
|
||||
}
|
||||
$FactorA = ($BitrateToUseMax - $AudioBitrate) / ($BitrateToUseMax - $BitrateToUseMin);
|
||||
|
||||
$VideoBitrateLog10 = log10($VideoBitrate);
|
||||
$VideoFactorMin1 = $OverheadMultiplierByBitrate[$BitrateToUseMin][floor($VideoBitrateLog10)];
|
||||
$VideoFactorMin2 = $OverheadMultiplierByBitrate[$BitrateToUseMax][floor($VideoBitrateLog10)];
|
||||
$VideoFactorMax1 = $OverheadMultiplierByBitrate[$BitrateToUseMin][ceil($VideoBitrateLog10)];
|
||||
$VideoFactorMax2 = $OverheadMultiplierByBitrate[$BitrateToUseMax][ceil($VideoBitrateLog10)];
|
||||
$FactorV = $VideoBitrateLog10 - floor($VideoBitrateLog10);
|
||||
|
||||
$OverheadPercentage = $VideoFactorMin1 * $FactorA * $FactorV;
|
||||
$OverheadPercentage += $VideoFactorMin2 * (1 - $FactorA) * $FactorV;
|
||||
$OverheadPercentage += $VideoFactorMax1 * $FactorA * (1 - $FactorV);
|
||||
$OverheadPercentage += $VideoFactorMax2 * (1 - $FactorA) * (1 - $FactorV);
|
||||
|
||||
return $OverheadPercentage;
|
||||
}
|
||||
|
||||
|
||||
function MPEGvideoFramerateLookup($rawframerate) {
|
||||
$MPEGvideoFramerateLookup = array(0, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60);
|
||||
return (isset($MPEGvideoFramerateLookup[$rawframerate]) ? (float) $MPEGvideoFramerateLookup[$rawframerate] : (float) 0);
|
||||
}
|
||||
|
||||
function MPEGvideoAspectRatioLookup($rawaspectratio) {
|
||||
$MPEGvideoAspectRatioLookup = array(0, 1, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815, 1.0255, 1.0695, 1.0950, 1.1575, 1.2015, 0);
|
||||
return (isset($MPEGvideoAspectRatioLookup[$rawaspectratio]) ? (float) $MPEGvideoAspectRatioLookup[$rawaspectratio] : (float) 0);
|
||||
}
|
||||
|
||||
function MPEGvideoAspectRatioTextLookup($rawaspectratio) {
|
||||
$MPEGvideoAspectRatioTextLookup = array('forbidden', 'square pixels', '0.6735', '16:9, 625 line, PAL', '0.7615', '0.8055', '16:9, 525 line, NTSC', '0.8935', '4:3, 625 line, PAL, CCIR601', '0.9815', '1.0255', '1.0695', '4:3, 525 line, NTSC, CCIR601', '1.1575', '1.2015', 'reserved');
|
||||
return (isset($MPEGvideoAspectRatioTextLookup[$rawaspectratio]) ? $MPEGvideoAspectRatioTextLookup[$rawaspectratio] : '');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,224 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.nsv.php //
|
||||
// module for analyzing Nullsoft NSV files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_nsv
|
||||
{
|
||||
|
||||
function getid3_nsv(&$fd, &$ThisFileInfo) {
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$NSVheader = fread($fd, 4);
|
||||
|
||||
switch ($NSVheader) {
|
||||
case 'NSVs':
|
||||
if ($this->getNSVsHeaderFilepointer($fd, $ThisFileInfo, 0)) {
|
||||
$ThisFileInfo['fileformat'] = 'nsv';
|
||||
$ThisFileInfo['audio']['dataformat'] = 'nsv';
|
||||
$ThisFileInfo['video']['dataformat'] = 'nsv';
|
||||
$ThisFileInfo['audio']['lossless'] = false;
|
||||
$ThisFileInfo['video']['lossless'] = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NSVf':
|
||||
if ($this->getNSVfHeaderFilepointer($fd, $ThisFileInfo, 0)) {
|
||||
$ThisFileInfo['fileformat'] = 'nsv';
|
||||
$ThisFileInfo['audio']['dataformat'] = 'nsv';
|
||||
$ThisFileInfo['video']['dataformat'] = 'nsv';
|
||||
$ThisFileInfo['audio']['lossless'] = false;
|
||||
$ThisFileInfo['video']['lossless'] = false;
|
||||
$this->getNSVsHeaderFilepointer($fd, $ThisFileInfo, $ThisFileInfo['nsv']['NSVf']['header_length']);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$ThisFileInfo['error'][] = 'Expecting "NSVs" or "NSVf" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$NSVheader.'"';
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isset($ThisFileInfo['nsv']['NSVf'])) {
|
||||
$ThisFileInfo['warning'][] = 'NSVf header not present - cannot calculate playtime or bitrate';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getNSVsHeaderFilepointer(&$fd, &$ThisFileInfo, $fileoffset) {
|
||||
fseek($fd, $fileoffset, SEEK_SET);
|
||||
$NSVsheader = fread($fd, 28);
|
||||
$offset = 0;
|
||||
|
||||
$ThisFileInfo['nsv']['NSVs']['identifier'] = substr($NSVsheader, $offset, 4);
|
||||
$offset += 4;
|
||||
|
||||
if ($ThisFileInfo['nsv']['NSVs']['identifier'] != 'NSVs') {
|
||||
$ThisFileInfo['error'][] = 'expected "NSVs" at offset ('.$fileoffset.'), found "'.$ThisFileInfo['nsv']['NSVs']['identifier'].'" instead';
|
||||
unset($ThisFileInfo['nsv']['NSVs']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['nsv']['NSVs']['offset'] = $fileoffset;
|
||||
|
||||
$ThisFileInfo['nsv']['NSVs']['video_codec'] = substr($NSVsheader, $offset, 4);
|
||||
$offset += 4;
|
||||
$ThisFileInfo['nsv']['NSVs']['audio_codec'] = substr($NSVsheader, $offset, 4);
|
||||
$offset += 4;
|
||||
$ThisFileInfo['nsv']['NSVs']['resolution_x'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$ThisFileInfo['nsv']['NSVs']['resolution_y'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 2));
|
||||
$offset += 2;
|
||||
|
||||
$ThisFileInfo['nsv']['NSVs']['framerate_index'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
//$ThisFileInfo['nsv']['NSVs']['unknown1b'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
//$ThisFileInfo['nsv']['NSVs']['unknown1c'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
//$ThisFileInfo['nsv']['NSVs']['unknown1d'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
//$ThisFileInfo['nsv']['NSVs']['unknown2a'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
//$ThisFileInfo['nsv']['NSVs']['unknown2b'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
//$ThisFileInfo['nsv']['NSVs']['unknown2c'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
//$ThisFileInfo['nsv']['NSVs']['unknown2d'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
|
||||
switch ($ThisFileInfo['nsv']['NSVs']['audio_codec']) {
|
||||
case 'PCM ':
|
||||
$ThisFileInfo['nsv']['NSVs']['bits_channel'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
$ThisFileInfo['nsv']['NSVs']['channels'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
$ThisFileInfo['nsv']['NSVs']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 2));
|
||||
$offset += 2;
|
||||
|
||||
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['nsv']['NSVs']['sample_rate'];
|
||||
break;
|
||||
|
||||
case 'MP3 ':
|
||||
case 'NONE':
|
||||
default:
|
||||
//$ThisFileInfo['nsv']['NSVs']['unknown3'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 4));
|
||||
$offset += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
$ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['nsv']['NSVs']['resolution_x'];
|
||||
$ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['nsv']['NSVs']['resolution_y'];
|
||||
$ThisFileInfo['nsv']['NSVs']['frame_rate'] = $this->NSVframerateLookup($ThisFileInfo['nsv']['NSVs']['framerate_index']);
|
||||
$ThisFileInfo['video']['frame_rate'] = $ThisFileInfo['nsv']['NSVs']['frame_rate'];
|
||||
$ThisFileInfo['video']['bits_per_sample'] = 24;
|
||||
$ThisFileInfo['video']['pixel_aspect_ratio'] = (float) 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getNSVfHeaderFilepointer(&$fd, &$ThisFileInfo, $fileoffset, $getTOCoffsets=false) {
|
||||
fseek($fd, $fileoffset, SEEK_SET);
|
||||
$NSVfheader = fread($fd, 28);
|
||||
$offset = 0;
|
||||
|
||||
$ThisFileInfo['nsv']['NSVf']['identifier'] = substr($NSVfheader, $offset, 4);
|
||||
$offset += 4;
|
||||
|
||||
if ($ThisFileInfo['nsv']['NSVf']['identifier'] != 'NSVf') {
|
||||
$ThisFileInfo['error'][] = 'expected "NSVf" at offset ('.$fileoffset.'), found "'.$ThisFileInfo['nsv']['NSVf']['identifier'].'" instead';
|
||||
unset($ThisFileInfo['nsv']['NSVf']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['nsv']['NSVs']['offset'] = $fileoffset;
|
||||
|
||||
$ThisFileInfo['nsv']['NSVf']['header_length'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$ThisFileInfo['nsv']['NSVf']['file_size'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
if ($ThisFileInfo['nsv']['NSVf']['file_size'] > $ThisFileInfo['avdataend']) {
|
||||
$ThisFileInfo['warning'][] = 'truncated file - NSVf header indicates '.$ThisFileInfo['nsv']['NSVf']['file_size'].' bytes, file actually '.$ThisFileInfo['avdataend'].' bytes';
|
||||
}
|
||||
|
||||
$ThisFileInfo['nsv']['NSVf']['playtime_ms'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$ThisFileInfo['nsv']['NSVf']['meta_size'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$ThisFileInfo['nsv']['NSVf']['TOC_entries_1'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$ThisFileInfo['nsv']['NSVf']['TOC_entries_2'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
if ($ThisFileInfo['nsv']['NSVf']['playtime_ms'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'Corrupt NSV file: NSVf.playtime_ms == zero';
|
||||
return false;
|
||||
}
|
||||
|
||||
$NSVfheader .= fread($fd, $ThisFileInfo['nsv']['NSVf']['meta_size'] + (4 * $ThisFileInfo['nsv']['NSVf']['TOC_entries_1']) + (4 * $ThisFileInfo['nsv']['NSVf']['TOC_entries_2']));
|
||||
$NSVfheaderlength = strlen($NSVfheader);
|
||||
$ThisFileInfo['nsv']['NSVf']['metadata'] = substr($NSVfheader, $offset, $ThisFileInfo['nsv']['NSVf']['meta_size']);
|
||||
$offset += $ThisFileInfo['nsv']['NSVf']['meta_size'];
|
||||
|
||||
if ($getTOCoffsets) {
|
||||
$TOCcounter = 0;
|
||||
while ($TOCcounter < $ThisFileInfo['nsv']['NSVf']['TOC_entries_1']) {
|
||||
if ($TOCcounter < $ThisFileInfo['nsv']['NSVf']['TOC_entries_1']) {
|
||||
$ThisFileInfo['nsv']['NSVf']['TOC_1'][$TOCcounter] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$TOCcounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trim($ThisFileInfo['nsv']['NSVf']['metadata']) != '') {
|
||||
$ThisFileInfo['nsv']['NSVf']['metadata'] = str_replace('`', "\x01", $ThisFileInfo['nsv']['NSVf']['metadata']);
|
||||
$CommentPairArray = explode("\x01".' ', $ThisFileInfo['nsv']['NSVf']['metadata']);
|
||||
foreach ($CommentPairArray as $CommentPair) {
|
||||
if (strstr($CommentPair, '='."\x01")) {
|
||||
list($key, $value) = explode('='."\x01", $CommentPair, 2);
|
||||
$ThisFileInfo['nsv']['comments'][strtolower($key)][] = trim(str_replace("\x01", '', $value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['nsv']['NSVf']['playtime_ms'] / 1000;
|
||||
$ThisFileInfo['bitrate'] = ($ThisFileInfo['nsv']['NSVf']['file_size'] * 8) / $ThisFileInfo['playtime_seconds'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function NSVframerateLookup($framerateindex) {
|
||||
if ($framerateindex <= 127) {
|
||||
return (float) $framerateindex;
|
||||
}
|
||||
|
||||
static $NSVframerateLookup = array();
|
||||
if (empty($NSVframerateLookup)) {
|
||||
$NSVframerateLookup[129] = (float) 29.970;
|
||||
$NSVframerateLookup[131] = (float) 23.976;
|
||||
$NSVframerateLookup[133] = (float) 14.985;
|
||||
$NSVframerateLookup[197] = (float) 59.940;
|
||||
$NSVframerateLookup[199] = (float) 47.952;
|
||||
}
|
||||
return (isset($NSVframerateLookup[$framerateindex]) ? $NSVframerateLookup[$framerateindex] : false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,150 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio-video.swf.php //
|
||||
// module for analyzing Shockwave Flash files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_swf
|
||||
{
|
||||
|
||||
function getid3_swf(&$fd, &$ThisFileInfo, $ReturnAllTagData=false) {
|
||||
//$start_time = microtime(true);
|
||||
$ThisFileInfo['fileformat'] = 'swf';
|
||||
$ThisFileInfo['video']['dataformat'] = 'swf';
|
||||
|
||||
// http://www.openswf.org/spec/SWFfileformat.html
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
|
||||
$SWFfileData = fread($fd, $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']); // 8 + 2 + 2 + max(9) bytes NOT including Frame_Size RECT data
|
||||
|
||||
$ThisFileInfo['swf']['header']['signature'] = substr($SWFfileData, 0, 3);
|
||||
switch ($ThisFileInfo['swf']['header']['signature']) {
|
||||
case 'FWS':
|
||||
$ThisFileInfo['swf']['header']['compressed'] = false;
|
||||
break;
|
||||
|
||||
case 'CWS':
|
||||
$ThisFileInfo['swf']['header']['compressed'] = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
$ThisFileInfo['error'][] = 'Expecting "FWS" or "CWS" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$ThisFileInfo['swf']['header']['signature'].'"';
|
||||
unset($ThisFileInfo['swf']);
|
||||
unset($ThisFileInfo['fileformat']);
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
$ThisFileInfo['swf']['header']['version'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 3, 1));
|
||||
$ThisFileInfo['swf']['header']['length'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 4, 4));
|
||||
|
||||
if ($ThisFileInfo['swf']['header']['compressed']) {
|
||||
|
||||
$SWFHead = substr($SWFfileData, 0, 8);
|
||||
$SWFfileData = substr($SWFfileData, 8);
|
||||
ob_start();
|
||||
if ($decompressed = gzuncompress($SWFfileData)) {
|
||||
|
||||
ob_end_clean();
|
||||
$SWFfileData = $SWFHead.$decompressed;
|
||||
|
||||
} else {
|
||||
|
||||
$errormessage = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$ThisFileInfo['error'][] = 'Error decompressing compressed SWF data ('.strlen($SWFfileData).' bytes compressed, should be '.($ThisFileInfo['swf']['header']['length'] - 8).' bytes uncompressed)';
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$FrameSizeBitsPerValue = (ord(substr($SWFfileData, 8, 1)) & 0xF8) >> 3;
|
||||
$FrameSizeDataLength = ceil((5 + (4 * $FrameSizeBitsPerValue)) / 8);
|
||||
$FrameSizeDataString = str_pad(decbin(ord(substr($SWFfileData, 8, 1)) & 0x07), 3, '0', STR_PAD_LEFT);
|
||||
for ($i = 1; $i < $FrameSizeDataLength; $i++) {
|
||||
$FrameSizeDataString .= str_pad(decbin(ord(substr($SWFfileData, 8 + $i, 1))), 8, '0', STR_PAD_LEFT);
|
||||
}
|
||||
list($X1, $X2, $Y1, $Y2) = explode("\n", wordwrap($FrameSizeDataString, $FrameSizeBitsPerValue, "\n", 1));
|
||||
$ThisFileInfo['swf']['header']['frame_width'] = getid3_lib::Bin2Dec($X2);
|
||||
$ThisFileInfo['swf']['header']['frame_height'] = getid3_lib::Bin2Dec($Y2);
|
||||
|
||||
// http://www-lehre.informatik.uni-osnabrueck.de/~fbstark/diplom/docs/swf/Flash_Uncovered.htm
|
||||
// Next in the header is the frame rate, which is kind of weird.
|
||||
// It is supposed to be stored as a 16bit integer, but the first byte
|
||||
// (or last depending on how you look at it) is completely ignored.
|
||||
// Example: 0x000C -> 0x0C -> 12 So the frame rate is 12 fps.
|
||||
|
||||
// Byte at (8 + $FrameSizeDataLength) is always zero and ignored
|
||||
$ThisFileInfo['swf']['header']['frame_rate'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 9 + $FrameSizeDataLength, 1));
|
||||
$ThisFileInfo['swf']['header']['frame_count'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 10 + $FrameSizeDataLength, 2));
|
||||
|
||||
$ThisFileInfo['video']['frame_rate'] = $ThisFileInfo['swf']['header']['frame_rate'];
|
||||
$ThisFileInfo['video']['resolution_x'] = intval(round($ThisFileInfo['swf']['header']['frame_width'] / 20));
|
||||
$ThisFileInfo['video']['resolution_y'] = intval(round($ThisFileInfo['swf']['header']['frame_height'] / 20));
|
||||
$ThisFileInfo['video']['pixel_aspect_ratio'] = (float) 1;
|
||||
|
||||
if (($ThisFileInfo['swf']['header']['frame_count'] > 0) && ($ThisFileInfo['swf']['header']['frame_rate'] > 0)) {
|
||||
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['swf']['header']['frame_count'] / $ThisFileInfo['swf']['header']['frame_rate'];
|
||||
}
|
||||
//echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'<br>';
|
||||
|
||||
|
||||
// SWF tags
|
||||
|
||||
$CurrentOffset = 12 + $FrameSizeDataLength;
|
||||
$SWFdataLength = strlen($SWFfileData);
|
||||
|
||||
while ($CurrentOffset < $SWFdataLength) {
|
||||
//echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'<br>';
|
||||
|
||||
$TagIDTagLength = getid3_lib::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 2));
|
||||
$TagID = ($TagIDTagLength & 0xFFFC) >> 6;
|
||||
$TagLength = ($TagIDTagLength & 0x003F);
|
||||
$CurrentOffset += 2;
|
||||
if ($TagLength == 0x3F) {
|
||||
$TagLength = getid3_lib::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 4));
|
||||
$CurrentOffset += 4;
|
||||
}
|
||||
|
||||
unset($TagData);
|
||||
$TagData['offset'] = $CurrentOffset;
|
||||
$TagData['size'] = $TagLength;
|
||||
$TagData['id'] = $TagID;
|
||||
$TagData['data'] = substr($SWFfileData, $CurrentOffset, $TagLength);
|
||||
switch ($TagID) {
|
||||
case 0: // end of movie
|
||||
break 2;
|
||||
|
||||
case 9: // Set background color
|
||||
//$ThisFileInfo['swf']['tags'][] = $TagData;
|
||||
$ThisFileInfo['swf']['bgcolor'] = strtoupper(str_pad(dechex(getid3_lib::BigEndian2Int($TagData['data'])), 6, '0', STR_PAD_LEFT));
|
||||
break;
|
||||
|
||||
default:
|
||||
if ($ReturnAllTagData) {
|
||||
$ThisFileInfo['swf']['tags'][] = $TagData;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$CurrentOffset += $TagLength;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,58 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.aa.php //
|
||||
// module for analyzing Audible Audiobook files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_aa
|
||||
{
|
||||
|
||||
function getid3_aa(&$fd, &$ThisFileInfo) {
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$AAheader = fread($fd, 8);
|
||||
|
||||
$magic = "\x57\x90\x75\x36";
|
||||
if (substr($AAheader, 4, 4) != $magic) {
|
||||
$ThisFileInfo['error'][] = 'Expecting "'.PrintHexBytes($magic).'" at offset '.$ThisFileInfo['avdataoffset'].', found "'.PrintHexBytes(substr($AAheader, 4, 4)).'"';
|
||||
return false;
|
||||
}
|
||||
|
||||
// shortcut
|
||||
$ThisFileInfo['aa'] = array();
|
||||
$thisfile_au = &$ThisFileInfo['aa'];
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'aa';
|
||||
$ThisFileInfo['audio']['dataformat'] = 'aa';
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr'; // is it?
|
||||
$thisfile_au['encoding'] = 'ISO-8859-1';
|
||||
|
||||
$thisfile_au['filesize'] = getid3_lib::BigEndian2Int(substr($AUheader, 0, 4));
|
||||
if ($thisfile_au['filesize'] > ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'])) {
|
||||
$ThisFileInfo['warning'][] = 'Possible truncated file - expecting "'.$thisfile_au['filesize'].'" bytes of data, only found '.($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']).' bytes"';
|
||||
}
|
||||
|
||||
$ThisFileInfo['audio']['bits_per_sample'] = 16; // is it?
|
||||
$ThisFileInfo['audio']['sample_rate'] = $thisfile_au['sample_rate'];
|
||||
$ThisFileInfo['audio']['channels'] = $thisfile_au['channels'];
|
||||
|
||||
//$ThisFileInfo['playtime_seconds'] = 0;
|
||||
//$ThisFileInfo['audio']['bitrate'] = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,541 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.aac.php //
|
||||
// module for analyzing AAC Audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_aac
|
||||
{
|
||||
|
||||
// new combined constructor
|
||||
function getid3_aac(&$fd, &$ThisFileInfo, $option) {
|
||||
if ($option === 'adif') {
|
||||
$this->getAACADIFheaderFilepointer($fd, $ThisFileInfo);
|
||||
} elseif ($option === 'adts') {
|
||||
$this->getAACADTSheaderFilepointer($fd, $ThisFileInfo);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getAACADIFheaderFilepointer(&$fd, &$ThisFileInfo) {
|
||||
$ThisFileInfo['fileformat'] = 'aac';
|
||||
$ThisFileInfo['audio']['dataformat'] = 'aac';
|
||||
$ThisFileInfo['audio']['lossless'] = false;
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$AACheader = fread($fd, 1024);
|
||||
$offset = 0;
|
||||
|
||||
if (substr($AACheader, 0, 4) == 'ADIF') {
|
||||
|
||||
// http://faac.sourceforge.net/wiki/index.php?page=ADIF
|
||||
|
||||
// http://libmpeg.org/mpeg4/doc/w2203tfs.pdf
|
||||
// adif_header() {
|
||||
// adif_id 32
|
||||
// copyright_id_present 1
|
||||
// if( copyright_id_present )
|
||||
// copyright_id 72
|
||||
// original_copy 1
|
||||
// home 1
|
||||
// bitstream_type 1
|
||||
// bitrate 23
|
||||
// num_program_config_elements 4
|
||||
// for (i = 0; i < num_program_config_elements + 1; i++ ) {
|
||||
// if( bitstream_type == '0' )
|
||||
// adif_buffer_fullness 20
|
||||
// program_config_element()
|
||||
// }
|
||||
// }
|
||||
|
||||
$AACheaderBitstream = getid3_lib::BigEndian2Bin($AACheader);
|
||||
$bitoffset = 0;
|
||||
|
||||
$ThisFileInfo['aac']['header_type'] = 'ADIF';
|
||||
$bitoffset += 32;
|
||||
$ThisFileInfo['aac']['header']['mpeg_version'] = 4;
|
||||
|
||||
$ThisFileInfo['aac']['header']['copyright'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
|
||||
$bitoffset += 1;
|
||||
if ($ThisFileInfo['aac']['header']['copyright']) {
|
||||
$ThisFileInfo['aac']['header']['copyright_id'] = getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 72));
|
||||
$bitoffset += 72;
|
||||
}
|
||||
$ThisFileInfo['aac']['header']['original_copy'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
|
||||
$bitoffset += 1;
|
||||
$ThisFileInfo['aac']['header']['home'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
|
||||
$bitoffset += 1;
|
||||
$ThisFileInfo['aac']['header']['is_vbr'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
|
||||
$bitoffset += 1;
|
||||
if ($ThisFileInfo['aac']['header']['is_vbr']) {
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
|
||||
$ThisFileInfo['aac']['header']['bitrate_max'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23));
|
||||
$bitoffset += 23;
|
||||
} else {
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
|
||||
$ThisFileInfo['aac']['header']['bitrate'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23));
|
||||
$bitoffset += 23;
|
||||
$ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['aac']['header']['bitrate'];
|
||||
}
|
||||
if ($ThisFileInfo['audio']['bitrate'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'Corrupt AAC file: bitrate_audio == zero';
|
||||
return false;
|
||||
}
|
||||
$ThisFileInfo['aac']['header']['num_program_configs'] = 1 + getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
|
||||
for ($i = 0; $i < $ThisFileInfo['aac']['header']['num_program_configs']; $i++) {
|
||||
// http://www.audiocoding.com/wiki/index.php?page=program_config_element
|
||||
|
||||
// buffer_fullness 20
|
||||
|
||||
// element_instance_tag 4
|
||||
// object_type 2
|
||||
// sampling_frequency_index 4
|
||||
// num_front_channel_elements 4
|
||||
// num_side_channel_elements 4
|
||||
// num_back_channel_elements 4
|
||||
// num_lfe_channel_elements 2
|
||||
// num_assoc_data_elements 3
|
||||
// num_valid_cc_elements 4
|
||||
// mono_mixdown_present 1
|
||||
// mono_mixdown_element_number 4 if mono_mixdown_present == 1
|
||||
// stereo_mixdown_present 1
|
||||
// stereo_mixdown_element_number 4 if stereo_mixdown_present == 1
|
||||
// matrix_mixdown_idx_present 1
|
||||
// matrix_mixdown_idx 2 if matrix_mixdown_idx_present == 1
|
||||
// pseudo_surround_enable 1 if matrix_mixdown_idx_present == 1
|
||||
// for (i = 0; i < num_front_channel_elements; i++) {
|
||||
// front_element_is_cpe[i] 1
|
||||
// front_element_tag_select[i] 4
|
||||
// }
|
||||
// for (i = 0; i < num_side_channel_elements; i++) {
|
||||
// side_element_is_cpe[i] 1
|
||||
// side_element_tag_select[i] 4
|
||||
// }
|
||||
// for (i = 0; i < num_back_channel_elements; i++) {
|
||||
// back_element_is_cpe[i] 1
|
||||
// back_element_tag_select[i] 4
|
||||
// }
|
||||
// for (i = 0; i < num_lfe_channel_elements; i++) {
|
||||
// lfe_element_tag_select[i] 4
|
||||
// }
|
||||
// for (i = 0; i < num_assoc_data_elements; i++) {
|
||||
// assoc_data_element_tag_select[i] 4
|
||||
// }
|
||||
// for (i = 0; i < num_valid_cc_elements; i++) {
|
||||
// cc_element_is_ind_sw[i] 1
|
||||
// valid_cc_element_tag_select[i] 4
|
||||
// }
|
||||
// byte_alignment() VAR
|
||||
// comment_field_bytes 8
|
||||
// for (i = 0; i < comment_field_bytes; i++) {
|
||||
// comment_field_data[i] 8
|
||||
// }
|
||||
|
||||
if (!$ThisFileInfo['aac']['header']['is_vbr']) {
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['buffer_fullness'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 20));
|
||||
$bitoffset += 20;
|
||||
}
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['element_instance_tag'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['object_type'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
|
||||
$bitoffset += 2;
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['sampling_frequency_index'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['num_front_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['num_side_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['num_back_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['num_lfe_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
|
||||
$bitoffset += 2;
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['num_assoc_data_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 3));
|
||||
$bitoffset += 3;
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['num_valid_cc_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['mono_mixdown_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
if ($ThisFileInfo['aac']['program_configs'][$i]['mono_mixdown_present']) {
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['mono_mixdown_element_number'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
}
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['stereo_mixdown_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
if ($ThisFileInfo['aac']['program_configs'][$i]['stereo_mixdown_present']) {
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['stereo_mixdown_element_number'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
}
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['matrix_mixdown_idx_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
if ($ThisFileInfo['aac']['program_configs'][$i]['matrix_mixdown_idx_present']) {
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['matrix_mixdown_idx'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
|
||||
$bitoffset += 2;
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['pseudo_surround_enable'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
}
|
||||
for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_front_channel_elements']; $j++) {
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['front_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['front_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
}
|
||||
for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_side_channel_elements']; $j++) {
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['side_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['side_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
}
|
||||
for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_back_channel_elements']; $j++) {
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['back_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['back_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
}
|
||||
for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_lfe_channel_elements']; $j++) {
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['lfe_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
}
|
||||
for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_assoc_data_elements']; $j++) {
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['assoc_data_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
}
|
||||
for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_valid_cc_elements']; $j++) {
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['cc_element_is_ind_sw'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['valid_cc_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
}
|
||||
|
||||
$bitoffset = ceil($bitoffset / 8) * 8;
|
||||
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['comment_field_bytes'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 8));
|
||||
$bitoffset += 8;
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['comment_field'] = getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 8 * $ThisFileInfo['aac']['program_configs'][$i]['comment_field_bytes']));
|
||||
$bitoffset += 8 * $ThisFileInfo['aac']['program_configs'][$i]['comment_field_bytes'];
|
||||
|
||||
|
||||
$ThisFileInfo['aac']['header']['profile_text'] = $this->AACprofileLookup($ThisFileInfo['aac']['program_configs'][$i]['object_type'], $ThisFileInfo['aac']['header']['mpeg_version']);
|
||||
$ThisFileInfo['aac']['program_configs'][$i]['sampling_frequency'] = $this->AACsampleRateLookup($ThisFileInfo['aac']['program_configs'][$i]['sampling_frequency_index']);
|
||||
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['aac']['program_configs'][$i]['sampling_frequency'];
|
||||
$ThisFileInfo['audio']['channels'] = $this->AACchannelCountCalculate($ThisFileInfo['aac']['program_configs'][$i]);
|
||||
if ($ThisFileInfo['aac']['program_configs'][$i]['comment_field']) {
|
||||
$ThisFileInfo['aac']['comments'][] = $ThisFileInfo['aac']['program_configs'][$i]['comment_field'];
|
||||
}
|
||||
}
|
||||
$ThisFileInfo['playtime_seconds'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['audio']['bitrate'];
|
||||
|
||||
$ThisFileInfo['audio']['encoder_options'] = $ThisFileInfo['aac']['header_type'].' '.$ThisFileInfo['aac']['header']['profile_text'];
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
unset($ThisFileInfo['fileformat']);
|
||||
unset($ThisFileInfo['aac']);
|
||||
$ThisFileInfo['error'][] = 'AAC-ADIF synch not found at offset '.$ThisFileInfo['avdataoffset'].' (expected "ADIF", found "'.substr($AACheader, 0, 4).'" instead)';
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function getAACADTSheaderFilepointer(&$fd, &$ThisFileInfo, $MaxFramesToScan=1000000, $ReturnExtendedInfo=false) {
|
||||
// based loosely on code from AACfile by Jurgen Faul <jfaulØgmx.de>
|
||||
// http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html
|
||||
|
||||
|
||||
// http://faac.sourceforge.net/wiki/index.php?page=ADTS
|
||||
|
||||
// * ADTS Fixed Header: these don't change from frame to frame
|
||||
// syncword 12 always: '111111111111'
|
||||
// ID 1 0: MPEG-4, 1: MPEG-2
|
||||
// layer 2 always: '00'
|
||||
// protection_absent 1
|
||||
// profile 2
|
||||
// sampling_frequency_index 4
|
||||
// private_bit 1
|
||||
// channel_configuration 3
|
||||
// original/copy 1
|
||||
// home 1
|
||||
// emphasis 2 only if ID == 0 (ie MPEG-4)
|
||||
|
||||
// * ADTS Variable Header: these can change from frame to frame
|
||||
// copyright_identification_bit 1
|
||||
// copyright_identification_start 1
|
||||
// aac_frame_length 13 length of the frame including header (in bytes)
|
||||
// adts_buffer_fullness 11 0x7FF indicates VBR
|
||||
// no_raw_data_blocks_in_frame 2
|
||||
|
||||
// * ADTS Error check
|
||||
// crc_check 16 only if protection_absent == 0
|
||||
|
||||
$byteoffset = 0;
|
||||
$framenumber = 0;
|
||||
|
||||
// Init bit pattern array
|
||||
static $decbin = array();
|
||||
|
||||
// Populate $bindec
|
||||
for ($i = 0; $i < 256; $i++) {
|
||||
$decbin[chr($i)] = str_pad(decbin($i), 8, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
// used to calculate bitrate below
|
||||
$BitrateCache = array();
|
||||
|
||||
|
||||
while (true) {
|
||||
// breaks out when end-of-file encountered, or invalid data found,
|
||||
// or MaxFramesToScan frames have been scanned
|
||||
|
||||
if (!getid3_lib::intValueSupported($byteoffset)) {
|
||||
$ThisFileInfo['warning'][] = 'Unable to parse AAC file beyond '.ftell($fd).' (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)';
|
||||
return false;
|
||||
}
|
||||
fseek($fd, $byteoffset, SEEK_SET);
|
||||
|
||||
// First get substring
|
||||
$substring = fread($fd, 10);
|
||||
$substringlength = strlen($substring);
|
||||
if ($substringlength != 10) {
|
||||
$ThisFileInfo['error'][] = 'Failed to read 10 bytes at offset '.(ftell($fd) - $substringlength).' (only read '.$substringlength.' bytes)';
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialise $AACheaderBitstream
|
||||
$AACheaderBitstream = '';
|
||||
|
||||
// Loop thru substring chars
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$AACheaderBitstream .= $decbin[$substring{$i}];
|
||||
}
|
||||
|
||||
$bitoffset = 0;
|
||||
|
||||
$synctest = bindec(substr($AACheaderBitstream, $bitoffset, 12));
|
||||
|
||||
$bitoffset += 12;
|
||||
if ($synctest != 0x0FFF) {
|
||||
$ThisFileInfo['error'][] = 'Synch pattern (0x0FFF) not found at offset '.(ftell($fd) - 10).' (found 0x0'.strtoupper(dechex($synctest)).' instead)';
|
||||
if ($ThisFileInfo['fileformat'] == 'aac') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Gather info for first frame only - this takes time to do 1000 times!
|
||||
if ($framenumber > 0) {
|
||||
|
||||
if (!$AACheaderBitstream[$bitoffset]) {
|
||||
|
||||
// MPEG-4
|
||||
$bitoffset += 20;
|
||||
|
||||
} else {
|
||||
|
||||
// MPEG-2
|
||||
$bitoffset += 18;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$ThisFileInfo['aac']['header_type'] = 'ADTS';
|
||||
$ThisFileInfo['aac']['header']['synch'] = $synctest;
|
||||
$ThisFileInfo['fileformat'] = 'aac';
|
||||
$ThisFileInfo['audio']['dataformat'] = 'aac';
|
||||
|
||||
$ThisFileInfo['aac']['header']['mpeg_version'] = ((substr($AACheaderBitstream, $bitoffset, 1) == '0') ? 4 : 2);
|
||||
$bitoffset += 1;
|
||||
$ThisFileInfo['aac']['header']['layer'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
|
||||
$bitoffset += 2;
|
||||
if ($ThisFileInfo['aac']['header']['layer'] != 0) {
|
||||
$ThisFileInfo['error'][] = 'Layer error - expected 0x00, found 0x'.dechex($ThisFileInfo['aac']['header']['layer']).' instead';
|
||||
return false;
|
||||
}
|
||||
$ThisFileInfo['aac']['header']['crc_present'] = ((substr($AACheaderBitstream, $bitoffset, 1) == '0') ? true : false);
|
||||
$bitoffset += 1;
|
||||
$ThisFileInfo['aac']['header']['profile_id'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
|
||||
$bitoffset += 2;
|
||||
$ThisFileInfo['aac']['header']['profile_text'] = $this->AACprofileLookup($ThisFileInfo['aac']['header']['profile_id'], $ThisFileInfo['aac']['header']['mpeg_version']);
|
||||
|
||||
$ThisFileInfo['aac']['header']['sample_frequency_index'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
$ThisFileInfo['aac']['header']['sample_frequency'] = $this->AACsampleRateLookup($ThisFileInfo['aac']['header']['sample_frequency_index']);
|
||||
if ($ThisFileInfo['aac']['header']['sample_frequency'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'Corrupt AAC file: sample_frequency == zero';
|
||||
return false;
|
||||
}
|
||||
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['aac']['header']['sample_frequency'];
|
||||
|
||||
$ThisFileInfo['aac']['header']['private'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
$ThisFileInfo['aac']['header']['channel_configuration'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 3));
|
||||
$bitoffset += 3;
|
||||
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['aac']['header']['channel_configuration'];
|
||||
$ThisFileInfo['aac']['header']['original'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
$ThisFileInfo['aac']['header']['home'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
|
||||
if ($ThisFileInfo['aac']['header']['mpeg_version'] == 4) {
|
||||
$ThisFileInfo['aac']['header']['emphasis'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
|
||||
$bitoffset += 2;
|
||||
}
|
||||
|
||||
if ($ReturnExtendedInfo) {
|
||||
|
||||
$ThisFileInfo['aac'][$framenumber]['copyright_id_bit'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
$ThisFileInfo['aac'][$framenumber]['copyright_id_start'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
|
||||
} else {
|
||||
|
||||
$bitoffset += 2;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$FrameLength = bindec(substr($AACheaderBitstream, $bitoffset, 13));
|
||||
|
||||
if (!isset($BitrateCache[$FrameLength])) {
|
||||
$BitrateCache[$FrameLength] = ($ThisFileInfo['aac']['header']['sample_frequency'] / 1024) * $FrameLength * 8;
|
||||
}
|
||||
getid3_lib::safe_inc($ThisFileInfo['aac']['bitrate_distribution'][$BitrateCache[$FrameLength]], 1);
|
||||
|
||||
$ThisFileInfo['aac'][$framenumber]['aac_frame_length'] = $FrameLength;
|
||||
$bitoffset += 13;
|
||||
$ThisFileInfo['aac'][$framenumber]['adts_buffer_fullness'] = bindec(substr($AACheaderBitstream, $bitoffset, 11));
|
||||
$bitoffset += 11;
|
||||
if ($ThisFileInfo['aac'][$framenumber]['adts_buffer_fullness'] == 0x07FF) {
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
|
||||
} else {
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
|
||||
}
|
||||
$ThisFileInfo['aac'][$framenumber]['num_raw_data_blocks'] = bindec(substr($AACheaderBitstream, $bitoffset, 2));
|
||||
$bitoffset += 2;
|
||||
|
||||
if ($ThisFileInfo['aac']['header']['crc_present']) {
|
||||
//$ThisFileInfo['aac'][$framenumber]['crc'] = bindec(substr($AACheaderBitstream, $bitoffset, 16));
|
||||
$bitoffset += 16;
|
||||
}
|
||||
|
||||
if (!$ReturnExtendedInfo) {
|
||||
unset($ThisFileInfo['aac'][$framenumber]);
|
||||
}
|
||||
|
||||
$byteoffset += $FrameLength;
|
||||
if ((++$framenumber < $MaxFramesToScan) && (($byteoffset + 10) < $ThisFileInfo['avdataend'])) {
|
||||
|
||||
// keep scanning
|
||||
|
||||
} else {
|
||||
|
||||
$ThisFileInfo['aac']['frames'] = $framenumber;
|
||||
$ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avdataend'] / $byteoffset) * (($framenumber * 1024) / $ThisFileInfo['aac']['header']['sample_frequency']); // (1 / % of file scanned) * (samples / (samples/sec)) = seconds
|
||||
if ($ThisFileInfo['playtime_seconds'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'Corrupt AAC file: playtime_seconds == zero';
|
||||
return false;
|
||||
}
|
||||
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
|
||||
ksort($ThisFileInfo['aac']['bitrate_distribution']);
|
||||
|
||||
$ThisFileInfo['audio']['encoder_options'] = $ThisFileInfo['aac']['header_type'].' '.$ThisFileInfo['aac']['header']['profile_text'];
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
// should never get here.
|
||||
}
|
||||
|
||||
function AACsampleRateLookup($samplerateid) {
|
||||
static $AACsampleRateLookup = array();
|
||||
if (empty($AACsampleRateLookup)) {
|
||||
$AACsampleRateLookup[0] = 96000;
|
||||
$AACsampleRateLookup[1] = 88200;
|
||||
$AACsampleRateLookup[2] = 64000;
|
||||
$AACsampleRateLookup[3] = 48000;
|
||||
$AACsampleRateLookup[4] = 44100;
|
||||
$AACsampleRateLookup[5] = 32000;
|
||||
$AACsampleRateLookup[6] = 24000;
|
||||
$AACsampleRateLookup[7] = 22050;
|
||||
$AACsampleRateLookup[8] = 16000;
|
||||
$AACsampleRateLookup[9] = 12000;
|
||||
$AACsampleRateLookup[10] = 11025;
|
||||
$AACsampleRateLookup[11] = 8000;
|
||||
$AACsampleRateLookup[12] = 0;
|
||||
$AACsampleRateLookup[13] = 0;
|
||||
$AACsampleRateLookup[14] = 0;
|
||||
$AACsampleRateLookup[15] = 0;
|
||||
}
|
||||
return (isset($AACsampleRateLookup[$samplerateid]) ? $AACsampleRateLookup[$samplerateid] : 'invalid');
|
||||
}
|
||||
|
||||
function AACprofileLookup($profileid, $mpegversion) {
|
||||
static $AACprofileLookup = array();
|
||||
if (empty($AACprofileLookup)) {
|
||||
$AACprofileLookup[2][0] = 'Main profile';
|
||||
$AACprofileLookup[2][1] = 'Low Complexity profile (LC)';
|
||||
$AACprofileLookup[2][2] = 'Scalable Sample Rate profile (SSR)';
|
||||
$AACprofileLookup[2][3] = '(reserved)';
|
||||
$AACprofileLookup[4][0] = 'AAC_MAIN';
|
||||
$AACprofileLookup[4][1] = 'AAC_LC';
|
||||
$AACprofileLookup[4][2] = 'AAC_SSR';
|
||||
$AACprofileLookup[4][3] = 'AAC_LTP';
|
||||
}
|
||||
return (isset($AACprofileLookup[$mpegversion][$profileid]) ? $AACprofileLookup[$mpegversion][$profileid] : 'invalid');
|
||||
}
|
||||
|
||||
function AACchannelCountCalculate($program_configs) {
|
||||
$channels = 0;
|
||||
for ($i = 0; $i < $program_configs['num_front_channel_elements']; $i++) {
|
||||
$channels++;
|
||||
if ($program_configs['front_element_is_cpe'][$i]) {
|
||||
// each front element is channel pair (CPE = Channel Pair Element)
|
||||
$channels++;
|
||||
}
|
||||
}
|
||||
for ($i = 0; $i < $program_configs['num_side_channel_elements']; $i++) {
|
||||
$channels++;
|
||||
if ($program_configs['side_element_is_cpe'][$i]) {
|
||||
// each side element is channel pair (CPE = Channel Pair Element)
|
||||
$channels++;
|
||||
}
|
||||
}
|
||||
for ($i = 0; $i < $program_configs['num_back_channel_elements']; $i++) {
|
||||
$channels++;
|
||||
if ($program_configs['back_element_is_cpe'][$i]) {
|
||||
// each back element is channel pair (CPE = Channel Pair Element)
|
||||
$channels++;
|
||||
}
|
||||
}
|
||||
for ($i = 0; $i < $program_configs['num_lfe_channel_elements']; $i++) {
|
||||
$channels++;
|
||||
}
|
||||
return $channels;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,497 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.ac3.php //
|
||||
// module for analyzing AC-3 (aka Dolby Digital) audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_ac3
|
||||
{
|
||||
|
||||
function getid3_ac3(&$fd, &$ThisFileInfo) {
|
||||
|
||||
///AH
|
||||
$ThisFileInfo['ac3']['raw']['bsi'] = array();
|
||||
$thisfile_ac3 = &$ThisFileInfo['ac3'];
|
||||
$thisfile_ac3_raw = &$thisfile_ac3['raw'];
|
||||
$thisfile_ac3_raw_bsi = &$thisfile_ac3_raw['bsi'];
|
||||
|
||||
|
||||
// http://www.atsc.org/standards/a_52a.pdf
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'ac3';
|
||||
$ThisFileInfo['audio']['dataformat'] = 'ac3';
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
|
||||
$ThisFileInfo['audio']['lossless'] = false;
|
||||
|
||||
// An AC-3 serial coded audio bit stream is made up of a sequence of synchronization frames
|
||||
// Each synchronization frame contains 6 coded audio blocks (AB), each of which represent 256
|
||||
// new audio samples per channel. A synchronization information (SI) header at the beginning
|
||||
// of each frame contains information needed to acquire and maintain synchronization. A
|
||||
// bit stream information (BSI) header follows SI, and contains parameters describing the coded
|
||||
// audio service. The coded audio blocks may be followed by an auxiliary data (Aux) field. At the
|
||||
// end of each frame is an error check field that includes a CRC word for error detection. An
|
||||
// additional CRC word is located in the SI header, the use of which, by a decoder, is optional.
|
||||
//
|
||||
// syncinfo() | bsi() | AB0 | AB1 | AB2 | AB3 | AB4 | AB5 | Aux | CRC
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$AC3header['syncinfo'] = fread($fd, 5);
|
||||
$thisfile_ac3_raw['synchinfo']['synchword'] = substr($AC3header['syncinfo'], 0, 2);
|
||||
|
||||
if ($thisfile_ac3_raw['synchinfo']['synchword'] != "\x0B\x77") {
|
||||
|
||||
$ThisFileInfo['error'][] = 'Expecting "\x0B\x77" at offset '.$ThisFileInfo['avdataoffset'].', found \x'.strtoupper(dechex($AC3header['syncinfo']{0})).'\x'.strtoupper(dechex($AC3header['syncinfo']{1})).' instead';
|
||||
unset($thisfile_ac3);
|
||||
return false;
|
||||
|
||||
} else {
|
||||
|
||||
// syncinfo() {
|
||||
// syncword 16
|
||||
// crc1 16
|
||||
// fscod 2
|
||||
// frmsizecod 6
|
||||
// } /* end of syncinfo */
|
||||
|
||||
$thisfile_ac3_raw['synchinfo']['crc1'] = getid3_lib::LittleEndian2Int(substr($AC3header['syncinfo'], 2, 2));
|
||||
$ac3_synchinfo_fscod_frmsizecod = getid3_lib::LittleEndian2Int(substr($AC3header['syncinfo'], 4, 1));
|
||||
$thisfile_ac3_raw['synchinfo']['fscod'] = ($ac3_synchinfo_fscod_frmsizecod & 0xC0) >> 6;
|
||||
$thisfile_ac3_raw['synchinfo']['frmsizecod'] = ($ac3_synchinfo_fscod_frmsizecod & 0x3F);
|
||||
|
||||
$thisfile_ac3['sample_rate'] = $this->AC3sampleRateCodeLookup($thisfile_ac3_raw['synchinfo']['fscod']);
|
||||
if ($thisfile_ac3_raw['synchinfo']['fscod'] <= 3) {
|
||||
$ThisFileInfo['audio']['sample_rate'] = $thisfile_ac3['sample_rate'];
|
||||
}
|
||||
|
||||
$thisfile_ac3['frame_length'] = $this->AC3frameSizeLookup($thisfile_ac3_raw['synchinfo']['frmsizecod'], $thisfile_ac3_raw['synchinfo']['fscod']);
|
||||
$thisfile_ac3['bitrate'] = $this->AC3bitrateLookup($thisfile_ac3_raw['synchinfo']['frmsizecod']);
|
||||
$ThisFileInfo['audio']['bitrate'] = $thisfile_ac3['bitrate'];
|
||||
|
||||
$AC3header['bsi'] = getid3_lib::BigEndian2Bin(fread($fd, 15));
|
||||
$ac3_bsi_offset = 0;
|
||||
|
||||
$thisfile_ac3_raw_bsi['bsid'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 5));
|
||||
$ac3_bsi_offset += 5;
|
||||
if ($thisfile_ac3_raw_bsi['bsid'] > 8) {
|
||||
// Decoders which can decode version 8 will thus be able to decode version numbers less than 8.
|
||||
// If this standard is extended by the addition of additional elements or features, a value of bsid greater than 8 will be used.
|
||||
// Decoders built to this version of the standard will not be able to decode versions with bsid greater than 8.
|
||||
$ThisFileInfo['error'][] = 'Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 8';
|
||||
unset($thisfile_ac3);
|
||||
return false;
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['bsmod'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 3));
|
||||
$ac3_bsi_offset += 3;
|
||||
$thisfile_ac3_raw_bsi['acmod'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 3));
|
||||
$ac3_bsi_offset += 3;
|
||||
|
||||
$thisfile_ac3['service_type'] = $this->AC3serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']);
|
||||
$ac3_coding_mode = $this->AC3audioCodingModeLookup($thisfile_ac3_raw_bsi['acmod']);
|
||||
foreach($ac3_coding_mode as $key => $value) {
|
||||
$thisfile_ac3[$key] = $value;
|
||||
}
|
||||
switch ($thisfile_ac3_raw_bsi['acmod']) {
|
||||
case 0:
|
||||
case 1:
|
||||
$ThisFileInfo['audio']['channelmode'] = 'mono';
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
$ThisFileInfo['audio']['channelmode'] = 'stereo';
|
||||
break;
|
||||
default:
|
||||
$ThisFileInfo['audio']['channelmode'] = 'surround';
|
||||
break;
|
||||
}
|
||||
$ThisFileInfo['audio']['channels'] = $thisfile_ac3['num_channels'];
|
||||
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] & 0x01) {
|
||||
// If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream.
|
||||
$thisfile_ac3_raw_bsi['cmixlev'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 2));
|
||||
$ac3_bsi_offset += 2;
|
||||
$thisfile_ac3['center_mix_level'] = $this->AC3centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']);
|
||||
}
|
||||
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) {
|
||||
// If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream.
|
||||
$thisfile_ac3_raw_bsi['surmixlev'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 2));
|
||||
$ac3_bsi_offset += 2;
|
||||
$thisfile_ac3['surround_mix_level'] = $this->AC3surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']);
|
||||
}
|
||||
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] == 0x02) {
|
||||
// When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround.
|
||||
$thisfile_ac3_raw_bsi['dsurmod'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 2));
|
||||
$ac3_bsi_offset += 2;
|
||||
$thisfile_ac3['dolby_surround_mode'] = $this->AC3dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['lfeon'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
|
||||
$ac3_bsi_offset += 1;
|
||||
$thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['lfeon'];
|
||||
if ($thisfile_ac3_raw_bsi['lfeon']) {
|
||||
//$ThisFileInfo['audio']['channels']++;
|
||||
$ThisFileInfo['audio']['channels'] .= '.1';
|
||||
}
|
||||
|
||||
$thisfile_ac3['channels_enabled'] = $this->AC3channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['lfeon']);
|
||||
|
||||
// This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1–31.
|
||||
// The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
|
||||
$thisfile_ac3_raw_bsi['dialnorm'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 5));
|
||||
$ac3_bsi_offset += 5;
|
||||
$thisfile_ac3['dialogue_normalization'] = '-'.$thisfile_ac3_raw_bsi['dialnorm'].'dB';
|
||||
|
||||
$thisfile_ac3_raw_bsi['compre_flag'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
|
||||
$ac3_bsi_offset += 1;
|
||||
if ($thisfile_ac3_raw_bsi['compre_flag']) {
|
||||
$thisfile_ac3_raw_bsi['compr'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 8));
|
||||
$ac3_bsi_offset += 8;
|
||||
$thisfile_ac3['heavy_compression'] = $this->AC3heavyCompression($thisfile_ac3_raw_bsi['compr']);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['langcode_flag'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
|
||||
$ac3_bsi_offset += 1;
|
||||
if ($thisfile_ac3_raw_bsi['langcode_flag']) {
|
||||
$thisfile_ac3_raw_bsi['langcod'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 8));
|
||||
$ac3_bsi_offset += 8;
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['audprodie'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
|
||||
$ac3_bsi_offset += 1;
|
||||
if ($thisfile_ac3_raw_bsi['audprodie']) {
|
||||
$thisfile_ac3_raw_bsi['mixlevel'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 5));
|
||||
$ac3_bsi_offset += 5;
|
||||
$thisfile_ac3_raw_bsi['roomtyp'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 2));
|
||||
$ac3_bsi_offset += 2;
|
||||
|
||||
$thisfile_ac3['mixing_level'] = (80 + $thisfile_ac3_raw_bsi['mixlevel']).'dB';
|
||||
$thisfile_ac3['room_type'] = $this->AC3roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp']);
|
||||
}
|
||||
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] == 0x00) {
|
||||
// If acmod is 0, then two completely independent program channels (dual mono)
|
||||
// are encoded into the bit stream, and are referenced as Ch1, Ch2. In this case,
|
||||
// a number of additional items are present in BSI or audblk to fully describe Ch2.
|
||||
|
||||
|
||||
// This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1–31.
|
||||
// The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
|
||||
$thisfile_ac3_raw_bsi['dialnorm2'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 5));
|
||||
$ac3_bsi_offset += 5;
|
||||
$thisfile_ac3['dialogue_normalization2'] = '-'.$thisfile_ac3_raw_bsi['dialnorm2'].'dB';
|
||||
|
||||
$thisfile_ac3_raw_bsi['compre_flag2'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
|
||||
$ac3_bsi_offset += 1;
|
||||
if ($thisfile_ac3_raw_bsi['compre_flag2']) {
|
||||
$thisfile_ac3_raw_bsi['compr2'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 8));
|
||||
$ac3_bsi_offset += 8;
|
||||
$thisfile_ac3['heavy_compression2'] = $this->AC3heavyCompression($thisfile_ac3_raw_bsi['compr2']);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['langcode_flag2'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
|
||||
$ac3_bsi_offset += 1;
|
||||
if ($thisfile_ac3_raw_bsi['langcode_flag2']) {
|
||||
$thisfile_ac3_raw_bsi['langcod2'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 8));
|
||||
$ac3_bsi_offset += 8;
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['audprodie2'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
|
||||
$ac3_bsi_offset += 1;
|
||||
if ($thisfile_ac3_raw_bsi['audprodie2']) {
|
||||
$thisfile_ac3_raw_bsi['mixlevel2'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 5));
|
||||
$ac3_bsi_offset += 5;
|
||||
$thisfile_ac3_raw_bsi['roomtyp2'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 2));
|
||||
$ac3_bsi_offset += 2;
|
||||
|
||||
$thisfile_ac3['mixing_level2'] = (80 + $thisfile_ac3_raw_bsi['mixlevel2']).'dB';
|
||||
$thisfile_ac3['room_type2'] = $this->AC3roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp2']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['copyright'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
|
||||
$ac3_bsi_offset += 1;
|
||||
|
||||
$thisfile_ac3_raw_bsi['original'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
|
||||
$ac3_bsi_offset += 1;
|
||||
|
||||
$thisfile_ac3_raw_bsi['timecode1_flag'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
|
||||
$ac3_bsi_offset += 1;
|
||||
if ($thisfile_ac3_raw_bsi['timecode1_flag']) {
|
||||
$thisfile_ac3_raw_bsi['timecode1'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 14));
|
||||
$ac3_bsi_offset += 14;
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['timecode2_flag'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
|
||||
$ac3_bsi_offset += 1;
|
||||
if ($thisfile_ac3_raw_bsi['timecode2_flag']) {
|
||||
$thisfile_ac3_raw_bsi['timecode2'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 14));
|
||||
$ac3_bsi_offset += 14;
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['addbsi_flag'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
|
||||
$ac3_bsi_offset += 1;
|
||||
if ($thisfile_ac3_raw_bsi['addbsi_flag']) {
|
||||
$thisfile_ac3_raw_bsi['addbsi_length'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 6));
|
||||
$ac3_bsi_offset += 6;
|
||||
|
||||
$AC3header['bsi'] .= getid3_lib::BigEndian2Bin(fread($fd, $thisfile_ac3_raw_bsi['addbsi_length']));
|
||||
|
||||
$thisfile_ac3_raw_bsi['addbsi_data'] = substr($AC3header['bsi'], $ac3_bsi_offset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8);
|
||||
$ac3_bsi_offset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function AC3sampleRateCodeLookup($fscod) {
|
||||
static $AC3sampleRateCodeLookup = array(
|
||||
0 => 48000,
|
||||
1 => 44100,
|
||||
2 => 32000,
|
||||
3 => 'reserved' // If the reserved code is indicated, the decoder should not attempt to decode audio and should mute.
|
||||
);
|
||||
return (isset($AC3sampleRateCodeLookup[$fscod]) ? $AC3sampleRateCodeLookup[$fscod] : false);
|
||||
}
|
||||
|
||||
function AC3serviceTypeLookup($bsmod, $acmod) {
|
||||
static $AC3serviceTypeLookup = array();
|
||||
if (empty($AC3serviceTypeLookup)) {
|
||||
for ($i = 0; $i <= 7; $i++) {
|
||||
$AC3serviceTypeLookup[0][$i] = 'main audio service: complete main (CM)';
|
||||
$AC3serviceTypeLookup[1][$i] = 'main audio service: music and effects (ME)';
|
||||
$AC3serviceTypeLookup[2][$i] = 'associated service: visually impaired (VI)';
|
||||
$AC3serviceTypeLookup[3][$i] = 'associated service: hearing impaired (HI)';
|
||||
$AC3serviceTypeLookup[4][$i] = 'associated service: dialogue (D)';
|
||||
$AC3serviceTypeLookup[5][$i] = 'associated service: commentary (C)';
|
||||
$AC3serviceTypeLookup[6][$i] = 'associated service: emergency (E)';
|
||||
}
|
||||
|
||||
$AC3serviceTypeLookup[7][1] = 'associated service: voice over (VO)';
|
||||
for ($i = 2; $i <= 7; $i++) {
|
||||
$AC3serviceTypeLookup[7][$i] = 'main audio service: karaoke';
|
||||
}
|
||||
}
|
||||
return (isset($AC3serviceTypeLookup[$bsmod][$acmod]) ? $AC3serviceTypeLookup[$bsmod][$acmod] : false);
|
||||
}
|
||||
|
||||
function AC3audioCodingModeLookup($acmod) {
|
||||
static $AC3audioCodingModeLookup = array();
|
||||
if (empty($AC3audioCodingModeLookup)) {
|
||||
// array(channel configuration, # channels (not incl LFE), channel order)
|
||||
$AC3audioCodingModeLookup = array (
|
||||
0 => array('channel_config'=>'1+1', 'num_channels'=>2, 'channel_order'=>'Ch1,Ch2'),
|
||||
1 => array('channel_config'=>'1/0', 'num_channels'=>1, 'channel_order'=>'C'),
|
||||
2 => array('channel_config'=>'2/0', 'num_channels'=>2, 'channel_order'=>'L,R'),
|
||||
3 => array('channel_config'=>'3/0', 'num_channels'=>3, 'channel_order'=>'L,C,R'),
|
||||
4 => array('channel_config'=>'2/1', 'num_channels'=>3, 'channel_order'=>'L,R,S'),
|
||||
5 => array('channel_config'=>'3/1', 'num_channels'=>4, 'channel_order'=>'L,C,R,S'),
|
||||
6 => array('channel_config'=>'2/2', 'num_channels'=>4, 'channel_order'=>'L,R,SL,SR'),
|
||||
7 => array('channel_config'=>'3/2', 'num_channels'=>5, 'channel_order'=>'L,C,R,SL,SR')
|
||||
);
|
||||
}
|
||||
return (isset($AC3audioCodingModeLookup[$acmod]) ? $AC3audioCodingModeLookup[$acmod] : false);
|
||||
}
|
||||
|
||||
function AC3centerMixLevelLookup($cmixlev) {
|
||||
static $AC3centerMixLevelLookup;
|
||||
if (empty($AC3centerMixLevelLookup)) {
|
||||
$AC3centerMixLevelLookup = array(
|
||||
0 => pow(2, -3.0 / 6), // 0.707 (–3.0 dB)
|
||||
1 => pow(2, -4.5 / 6), // 0.595 (–4.5 dB)
|
||||
2 => pow(2, -6.0 / 6), // 0.500 (–6.0 dB)
|
||||
3 => 'reserved'
|
||||
);
|
||||
}
|
||||
return (isset($AC3centerMixLevelLookup[$cmixlev]) ? $AC3centerMixLevelLookup[$cmixlev] : false);
|
||||
}
|
||||
|
||||
function AC3surroundMixLevelLookup($surmixlev) {
|
||||
static $AC3surroundMixLevelLookup;
|
||||
if (empty($AC3surroundMixLevelLookup)) {
|
||||
$AC3surroundMixLevelLookup = array(
|
||||
0 => pow(2, -3.0 / 6),
|
||||
1 => pow(2, -6.0 / 6),
|
||||
2 => 0,
|
||||
3 => 'reserved'
|
||||
);
|
||||
}
|
||||
return (isset($AC3surroundMixLevelLookup[$surmixlev]) ? $AC3surroundMixLevelLookup[$surmixlev] : false);
|
||||
}
|
||||
|
||||
function AC3dolbySurroundModeLookup($dsurmod) {
|
||||
static $AC3dolbySurroundModeLookup = array(
|
||||
0 => 'not indicated',
|
||||
1 => 'Not Dolby Surround encoded',
|
||||
2 => 'Dolby Surround encoded',
|
||||
3 => 'reserved'
|
||||
);
|
||||
return (isset($AC3dolbySurroundModeLookup[$dsurmod]) ? $AC3dolbySurroundModeLookup[$dsurmod] : false);
|
||||
}
|
||||
|
||||
function AC3channelsEnabledLookup($acmod, $lfeon) {
|
||||
$AC3channelsEnabledLookup = array(
|
||||
'ch1'=>(bool) ($acmod == 0),
|
||||
'ch2'=>(bool) ($acmod == 0),
|
||||
'left'=>(bool) ($acmod > 1),
|
||||
'right'=>(bool) ($acmod > 1),
|
||||
'center'=>(bool) ($acmod & 0x01),
|
||||
'surround_mono'=>false,
|
||||
'surround_left'=>false,
|
||||
'surround_right'=>false,
|
||||
'lfe'=>$lfeon);
|
||||
switch ($acmod) {
|
||||
case 4:
|
||||
case 5:
|
||||
$AC3channelsEnabledLookup['surround_mono'] = true;
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
$AC3channelsEnabledLookup['surround_left'] = true;
|
||||
$AC3channelsEnabledLookup['surround_right'] = true;
|
||||
break;
|
||||
}
|
||||
return $AC3channelsEnabledLookup;
|
||||
}
|
||||
|
||||
function AC3heavyCompression($compre) {
|
||||
// The first four bits indicate gain changes in 6.02dB increments which can be
|
||||
// implemented with an arithmetic shift operation. The following four bits
|
||||
// indicate linear gain changes, and require a 5-bit multiply.
|
||||
// We will represent the two 4-bit fields of compr as follows:
|
||||
// X0 X1 X2 X3 . Y4 Y5 Y6 Y7
|
||||
// The meaning of the X values is most simply described by considering X to represent a 4-bit
|
||||
// signed integer with values from –8 to +7. The gain indicated by X is then (X + 1) * 6.02 dB. The
|
||||
// following table shows this in detail.
|
||||
|
||||
// Meaning of 4 msb of compr
|
||||
// 7 +48.16 dB
|
||||
// 6 +42.14 dB
|
||||
// 5 +36.12 dB
|
||||
// 4 +30.10 dB
|
||||
// 3 +24.08 dB
|
||||
// 2 +18.06 dB
|
||||
// 1 +12.04 dB
|
||||
// 0 +6.02 dB
|
||||
// -1 0 dB
|
||||
// -2 –6.02 dB
|
||||
// -3 –12.04 dB
|
||||
// -4 –18.06 dB
|
||||
// -5 –24.08 dB
|
||||
// -6 –30.10 dB
|
||||
// -7 –36.12 dB
|
||||
// -8 –42.14 dB
|
||||
|
||||
$fourbit = str_pad(decbin(($compre & 0xF0) >> 4), 4, '0', STR_PAD_LEFT);
|
||||
if ($fourbit{0} == '1') {
|
||||
$log_gain = -8 + bindec(substr($fourbit, 1));
|
||||
} else {
|
||||
$log_gain = bindec(substr($fourbit, 1));
|
||||
}
|
||||
$log_gain = ($log_gain + 1) * getid3_lib::RGADamplitude2dB(2);
|
||||
|
||||
// The value of Y is a linear representation of a gain change of up to –6 dB. Y is considered to
|
||||
// be an unsigned fractional integer, with a leading value of 1, or: 0.1 Y4 Y5 Y6 Y7 (base 2). Y can
|
||||
// represent values between 0.111112 (or 31/32) and 0.100002 (or 1/2). Thus, Y can represent gain
|
||||
// changes from –0.28 dB to –6.02 dB.
|
||||
|
||||
$lin_gain = (16 + ($compre & 0x0F)) / 32;
|
||||
|
||||
// The combination of X and Y values allows compr to indicate gain changes from
|
||||
// 48.16 – 0.28 = +47.89 dB, to
|
||||
// –42.14 – 6.02 = –48.16 dB.
|
||||
|
||||
return $log_gain - $lin_gain;
|
||||
}
|
||||
|
||||
function AC3roomTypeLookup($roomtyp) {
|
||||
static $AC3roomTypeLookup = array(
|
||||
0 => 'not indicated',
|
||||
1 => 'large room, X curve monitor',
|
||||
2 => 'small room, flat monitor',
|
||||
3 => 'reserved'
|
||||
);
|
||||
return (isset($AC3roomTypeLookup[$roomtyp]) ? $AC3roomTypeLookup[$roomtyp] : false);
|
||||
}
|
||||
|
||||
function AC3frameSizeLookup($frmsizecod, $fscod) {
|
||||
$padding = (bool) ($frmsizecod % 2);
|
||||
$framesizeid = floor($frmsizecod / 2);
|
||||
|
||||
static $AC3frameSizeLookup = array();
|
||||
if (empty($AC3frameSizeLookup)) {
|
||||
$AC3frameSizeLookup = array (
|
||||
0 => array(128, 138, 192),
|
||||
1 => array(40, 160, 174, 240),
|
||||
2 => array(48, 192, 208, 288),
|
||||
3 => array(56, 224, 242, 336),
|
||||
4 => array(64, 256, 278, 384),
|
||||
5 => array(80, 320, 348, 480),
|
||||
6 => array(96, 384, 416, 576),
|
||||
7 => array(112, 448, 486, 672),
|
||||
8 => array(128, 512, 556, 768),
|
||||
9 => array(160, 640, 696, 960),
|
||||
10 => array(192, 768, 834, 1152),
|
||||
11 => array(224, 896, 974, 1344),
|
||||
12 => array(256, 1024, 1114, 1536),
|
||||
13 => array(320, 1280, 1392, 1920),
|
||||
14 => array(384, 1536, 1670, 2304),
|
||||
15 => array(448, 1792, 1950, 2688),
|
||||
16 => array(512, 2048, 2228, 3072),
|
||||
17 => array(576, 2304, 2506, 3456),
|
||||
18 => array(640, 2560, 2786, 3840)
|
||||
);
|
||||
}
|
||||
if (($fscod == 1) && $padding) {
|
||||
// frame lengths are padded by 1 word (16 bits) at 44100
|
||||
$AC3frameSizeLookup[$frmsizecod] += 2;
|
||||
}
|
||||
return (isset($AC3frameSizeLookup[$framesizeid][$fscod]) ? $AC3frameSizeLookup[$framesizeid][$fscod] : false);
|
||||
}
|
||||
|
||||
function AC3bitrateLookup($frmsizecod) {
|
||||
$framesizeid = floor($frmsizecod / 2);
|
||||
|
||||
static $AC3bitrateLookup = array(
|
||||
0 => 32000,
|
||||
1 => 40000,
|
||||
2 => 48000,
|
||||
3 => 56000,
|
||||
4 => 64000,
|
||||
5 => 80000,
|
||||
6 => 96000,
|
||||
7 => 112000,
|
||||
8 => 128000,
|
||||
9 => 160000,
|
||||
10 => 192000,
|
||||
11 => 224000,
|
||||
12 => 256000,
|
||||
13 => 320000,
|
||||
14 => 384000,
|
||||
15 => 448000,
|
||||
16 => 512000,
|
||||
17 => 576000,
|
||||
18 => 640000
|
||||
);
|
||||
return (isset($AC3bitrateLookup[$framesizeid]) ? $AC3bitrateLookup[$framesizeid] : false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,125 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.avr.php //
|
||||
// module for analyzing AVR Audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_avr
|
||||
{
|
||||
|
||||
function getid3_avr(&$fd, &$ThisFileInfo) {
|
||||
|
||||
// http://cui.unige.ch/OSG/info/AudioFormats/ap11.html
|
||||
// http://www.btinternet.com/~AnthonyJ/Atari/programming/avr_format.html
|
||||
// offset type length name comments
|
||||
// ---------------------------------------------------------------------
|
||||
// 0 char 4 ID format ID == "2BIT"
|
||||
// 4 char 8 name sample name (unused space filled with 0)
|
||||
// 12 short 1 mono/stereo 0=mono, -1 (0xFFFF)=stereo
|
||||
// With stereo, samples are alternated,
|
||||
// the first voice is the left :
|
||||
// (LRLRLRLRLRLRLRLRLR...)
|
||||
// 14 short 1 resolution 8, 12 or 16 (bits)
|
||||
// 16 short 1 signed or not 0=unsigned, -1 (0xFFFF)=signed
|
||||
// 18 short 1 loop or not 0=no loop, -1 (0xFFFF)=loop on
|
||||
// 20 short 1 MIDI note 0xFFnn, where 0 <= nn <= 127
|
||||
// 0xFFFF means "no MIDI note defined"
|
||||
// 22 byte 1 Replay speed Frequence in the Replay software
|
||||
// 0=5.485 Khz, 1=8.084 Khz, 2=10.971 Khz,
|
||||
// 3=16.168 Khz, 4=21.942 Khz, 5=32.336 Khz
|
||||
// 6=43.885 Khz, 7=47.261 Khz
|
||||
// -1 (0xFF)=no defined Frequence
|
||||
// 23 byte 3 sample rate in Hertz
|
||||
// 26 long 1 size in bytes (2 * bytes in stereo)
|
||||
// 30 long 1 loop begin 0 for no loop
|
||||
// 34 long 1 loop size equal to 'size' for no loop
|
||||
// 38 short 2 Reserved, MIDI keyboard split */
|
||||
// 40 short 2 Reserved, sample compression */
|
||||
// 42 short 2 Reserved */
|
||||
// 44 char 20; Additional filename space, used if (name[7] != 0)
|
||||
// 64 byte 64 user data
|
||||
// 128 bytes ? sample data (12 bits samples are coded on 16 bits:
|
||||
// 0000 xxxx xxxx xxxx)
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Note that all values are in motorola (big-endian) format, and that long is
|
||||
// assumed to be 4 bytes, and short 2 bytes.
|
||||
// When reading the samples, you should handle both signed and unsigned data,
|
||||
// and be prepared to convert 16->8 bit, or mono->stereo if needed. To convert
|
||||
// 8-bit data between signed/unsigned just add 127 to the sample values.
|
||||
// Simularly for 16-bit data you should add 32769
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'avr';
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$AVRheader = fread($fd, 128);
|
||||
|
||||
$ThisFileInfo['avr']['raw']['magic'] = substr($AVRheader, 0, 4);
|
||||
if ($ThisFileInfo['avr']['raw']['magic'] != '2BIT') {
|
||||
$ThisFileInfo['error'][] = 'Expecting "2BIT" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$ThisFileInfo['avr']['raw']['magic'].'"';
|
||||
unset($ThisFileInfo['fileformat']);
|
||||
unset($ThisFileInfo['avr']);
|
||||
return false;
|
||||
}
|
||||
$ThisFileInfo['avdataoffset'] += 128;
|
||||
|
||||
$ThisFileInfo['avr']['sample_name'] = rtrim(substr($AVRheader, 4, 8));
|
||||
$ThisFileInfo['avr']['raw']['mono'] = getid3_lib::BigEndian2Int(substr($AVRheader, 12, 2));
|
||||
$ThisFileInfo['avr']['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($AVRheader, 14, 2));
|
||||
$ThisFileInfo['avr']['raw']['signed'] = getid3_lib::BigEndian2Int(substr($AVRheader, 16, 2));
|
||||
$ThisFileInfo['avr']['raw']['loop'] = getid3_lib::BigEndian2Int(substr($AVRheader, 18, 2));
|
||||
$ThisFileInfo['avr']['raw']['midi'] = getid3_lib::BigEndian2Int(substr($AVRheader, 20, 2));
|
||||
$ThisFileInfo['avr']['raw']['replay_freq'] = getid3_lib::BigEndian2Int(substr($AVRheader, 22, 1));
|
||||
$ThisFileInfo['avr']['sample_rate'] = getid3_lib::BigEndian2Int(substr($AVRheader, 23, 3));
|
||||
$ThisFileInfo['avr']['sample_length'] = getid3_lib::BigEndian2Int(substr($AVRheader, 26, 4));
|
||||
$ThisFileInfo['avr']['loop_start'] = getid3_lib::BigEndian2Int(substr($AVRheader, 30, 4));
|
||||
$ThisFileInfo['avr']['loop_end'] = getid3_lib::BigEndian2Int(substr($AVRheader, 34, 4));
|
||||
$ThisFileInfo['avr']['midi_split'] = getid3_lib::BigEndian2Int(substr($AVRheader, 38, 2));
|
||||
$ThisFileInfo['avr']['sample_compression'] = getid3_lib::BigEndian2Int(substr($AVRheader, 40, 2));
|
||||
$ThisFileInfo['avr']['reserved'] = getid3_lib::BigEndian2Int(substr($AVRheader, 42, 2));
|
||||
$ThisFileInfo['avr']['sample_name_extra'] = rtrim(substr($AVRheader, 44, 20));
|
||||
$ThisFileInfo['avr']['comment'] = rtrim(substr($AVRheader, 64, 64));
|
||||
|
||||
$ThisFileInfo['avr']['flags']['stereo'] = (($ThisFileInfo['avr']['raw']['mono'] == 0) ? false : true);
|
||||
$ThisFileInfo['avr']['flags']['signed'] = (($ThisFileInfo['avr']['raw']['signed'] == 0) ? false : true);
|
||||
$ThisFileInfo['avr']['flags']['loop'] = (($ThisFileInfo['avr']['raw']['loop'] == 0) ? false : true);
|
||||
|
||||
$ThisFileInfo['avr']['midi_notes'] = array();
|
||||
if (($ThisFileInfo['avr']['raw']['midi'] & 0xFF00) != 0xFF00) {
|
||||
$ThisFileInfo['avr']['midi_notes'][] = ($ThisFileInfo['avr']['raw']['midi'] & 0xFF00) >> 8;
|
||||
}
|
||||
if (($ThisFileInfo['avr']['raw']['midi'] & 0x00FF) != 0x00FF) {
|
||||
$ThisFileInfo['avr']['midi_notes'][] = ($ThisFileInfo['avr']['raw']['midi'] & 0x00FF);
|
||||
}
|
||||
|
||||
if (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) != ($ThisFileInfo['avr']['sample_length'] * (($ThisFileInfo['avr']['bits_per_sample'] == 8) ? 1 : 2))) {
|
||||
$ThisFileInfo['warning'][] = 'Probable truncated file: expecting '.($ThisFileInfo['avr']['sample_length'] * (($ThisFileInfo['avr']['bits_per_sample'] == 8) ? 1 : 2)).' bytes of audio data, found '.($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']);
|
||||
}
|
||||
|
||||
$ThisFileInfo['audio']['dataformat'] = 'avr';
|
||||
$ThisFileInfo['audio']['lossless'] = true;
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
|
||||
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['avr']['bits_per_sample'];
|
||||
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['avr']['sample_rate'];
|
||||
$ThisFileInfo['audio']['channels'] = ($ThisFileInfo['avr']['flags']['stereo'] ? 2 : 1);
|
||||
$ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avr']['sample_length'] / $ThisFileInfo['audio']['channels']) / $ThisFileInfo['avr']['sample_rate'];
|
||||
$ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['avr']['sample_length'] * (($ThisFileInfo['avr']['bits_per_sample'] == 8) ? 8 : 16)) / $ThisFileInfo['playtime_seconds'];
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,221 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.la.php //
|
||||
// module for analyzing BONK audio files //
|
||||
// dependencies: module.tag.id3v2.php (optional) //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_bonk
|
||||
{
|
||||
function getid3_bonk(&$fd, &$ThisFileInfo) {
|
||||
|
||||
// shortcut
|
||||
$ThisFileInfo['bonk'] = array();
|
||||
$thisfile_bonk = &$ThisFileInfo['bonk'];
|
||||
|
||||
$thisfile_bonk['dataoffset'] = $ThisFileInfo['avdataoffset'];
|
||||
$thisfile_bonk['dataend'] = $ThisFileInfo['avdataend'];
|
||||
|
||||
if (!getid3_lib::intValueSupported($thisfile_bonk['dataend'])) {
|
||||
|
||||
$ThisFileInfo['warning'][] = 'Unable to parse BONK file from end (v0.6+ preferred method) because PHP filesystem functions only support up to '.round(PHP_INT_MAX / 1073741824).'GB';
|
||||
|
||||
} else {
|
||||
|
||||
// scan-from-end method, for v0.6 and higher
|
||||
fseek($fd, $thisfile_bonk['dataend'] - 8, SEEK_SET);
|
||||
$PossibleBonkTag = fread($fd, 8);
|
||||
while ($this->BonkIsValidTagName(substr($PossibleBonkTag, 4, 4), true)) {
|
||||
$BonkTagSize = getid3_lib::LittleEndian2Int(substr($PossibleBonkTag, 0, 4));
|
||||
fseek($fd, 0 - $BonkTagSize, SEEK_CUR);
|
||||
$BonkTagOffset = ftell($fd);
|
||||
$TagHeaderTest = fread($fd, 5);
|
||||
if (($TagHeaderTest{0} != "\x00") || (substr($PossibleBonkTag, 4, 4) != strtolower(substr($PossibleBonkTag, 4, 4)))) {
|
||||
$ThisFileInfo['error'][] = 'Expecting "Ø'.strtoupper(substr($PossibleBonkTag, 4, 4)).'" at offset '.$BonkTagOffset.', found "'.$TagHeaderTest.'"';
|
||||
return false;
|
||||
}
|
||||
$BonkTagName = substr($TagHeaderTest, 1, 4);
|
||||
|
||||
$thisfile_bonk[$BonkTagName]['size'] = $BonkTagSize;
|
||||
$thisfile_bonk[$BonkTagName]['offset'] = $BonkTagOffset;
|
||||
$this->HandleBonkTags($fd, $BonkTagName, $ThisFileInfo);
|
||||
$NextTagEndOffset = $BonkTagOffset - 8;
|
||||
if ($NextTagEndOffset < $thisfile_bonk['dataoffset']) {
|
||||
if (empty($ThisFileInfo['audio']['encoder'])) {
|
||||
$ThisFileInfo['audio']['encoder'] = 'Extended BONK v0.9+';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
fseek($fd, $NextTagEndOffset, SEEK_SET);
|
||||
$PossibleBonkTag = fread($fd, 8);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// seek-from-beginning method for v0.4 and v0.5
|
||||
if (empty($thisfile_bonk['BONK'])) {
|
||||
fseek($fd, $thisfile_bonk['dataoffset'], SEEK_SET);
|
||||
do {
|
||||
$TagHeaderTest = fread($fd, 5);
|
||||
switch ($TagHeaderTest) {
|
||||
case "\x00".'BONK':
|
||||
if (empty($ThisFileInfo['audio']['encoder'])) {
|
||||
$ThisFileInfo['audio']['encoder'] = 'BONK v0.4';
|
||||
}
|
||||
break;
|
||||
|
||||
case "\x00".'INFO':
|
||||
$ThisFileInfo['audio']['encoder'] = 'Extended BONK v0.5';
|
||||
break;
|
||||
|
||||
default:
|
||||
break 2;
|
||||
}
|
||||
$BonkTagName = substr($TagHeaderTest, 1, 4);
|
||||
$thisfile_bonk[$BonkTagName]['size'] = $thisfile_bonk['dataend'] - $thisfile_bonk['dataoffset'];
|
||||
$thisfile_bonk[$BonkTagName]['offset'] = $thisfile_bonk['dataoffset'];
|
||||
$this->HandleBonkTags($fd, $BonkTagName, $ThisFileInfo);
|
||||
|
||||
} while (true);
|
||||
}
|
||||
|
||||
// parse META block for v0.6 - v0.8
|
||||
if (empty($thisfile_bonk['INFO']) && isset($thisfile_bonk['META']['tags']['info'])) {
|
||||
fseek($fd, $thisfile_bonk['META']['tags']['info'], SEEK_SET);
|
||||
$TagHeaderTest = fread($fd, 5);
|
||||
if ($TagHeaderTest == "\x00".'INFO') {
|
||||
$ThisFileInfo['audio']['encoder'] = 'Extended BONK v0.6 - v0.8';
|
||||
|
||||
$BonkTagName = substr($TagHeaderTest, 1, 4);
|
||||
$thisfile_bonk[$BonkTagName]['size'] = $thisfile_bonk['dataend'] - $thisfile_bonk['dataoffset'];
|
||||
$thisfile_bonk[$BonkTagName]['offset'] = $thisfile_bonk['dataoffset'];
|
||||
$this->HandleBonkTags($fd, $BonkTagName, $ThisFileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($ThisFileInfo['audio']['encoder'])) {
|
||||
$ThisFileInfo['audio']['encoder'] = 'Extended BONK v0.9+';
|
||||
}
|
||||
if (empty($thisfile_bonk['BONK'])) {
|
||||
unset($ThisFileInfo['bonk']);
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
function HandleBonkTags(&$fd, &$BonkTagName, &$ThisFileInfo) {
|
||||
|
||||
switch ($BonkTagName) {
|
||||
case 'BONK':
|
||||
// shortcut
|
||||
$thisfile_bonk_BONK = &$ThisFileInfo['bonk']['BONK'];
|
||||
|
||||
$BonkData = "\x00".'BONK'.fread($fd, 17);
|
||||
$thisfile_bonk_BONK['version'] = getid3_lib::LittleEndian2Int(substr($BonkData, 5, 1));
|
||||
$thisfile_bonk_BONK['number_samples'] = getid3_lib::LittleEndian2Int(substr($BonkData, 6, 4));
|
||||
$thisfile_bonk_BONK['sample_rate'] = getid3_lib::LittleEndian2Int(substr($BonkData, 10, 4));
|
||||
|
||||
$thisfile_bonk_BONK['channels'] = getid3_lib::LittleEndian2Int(substr($BonkData, 14, 1));
|
||||
$thisfile_bonk_BONK['lossless'] = (bool) getid3_lib::LittleEndian2Int(substr($BonkData, 15, 1));
|
||||
$thisfile_bonk_BONK['joint_stereo'] = (bool) getid3_lib::LittleEndian2Int(substr($BonkData, 16, 1));
|
||||
$thisfile_bonk_BONK['number_taps'] = getid3_lib::LittleEndian2Int(substr($BonkData, 17, 2));
|
||||
$thisfile_bonk_BONK['downsampling_ratio'] = getid3_lib::LittleEndian2Int(substr($BonkData, 19, 1));
|
||||
$thisfile_bonk_BONK['samples_per_packet'] = getid3_lib::LittleEndian2Int(substr($BonkData, 20, 2));
|
||||
|
||||
$ThisFileInfo['avdataoffset'] = $thisfile_bonk_BONK['offset'] + 5 + 17;
|
||||
$ThisFileInfo['avdataend'] = $thisfile_bonk_BONK['offset'] + $thisfile_bonk_BONK['size'];
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'bonk';
|
||||
$ThisFileInfo['audio']['dataformat'] = 'bonk';
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr'; // assumed
|
||||
$ThisFileInfo['audio']['channels'] = $thisfile_bonk_BONK['channels'];
|
||||
$ThisFileInfo['audio']['sample_rate'] = $thisfile_bonk_BONK['sample_rate'];
|
||||
$ThisFileInfo['audio']['channelmode'] = ($thisfile_bonk_BONK['joint_stereo'] ? 'joint stereo' : 'stereo');
|
||||
$ThisFileInfo['audio']['lossless'] = $thisfile_bonk_BONK['lossless'];
|
||||
$ThisFileInfo['audio']['codec'] = 'bonk';
|
||||
|
||||
$ThisFileInfo['playtime_seconds'] = $thisfile_bonk_BONK['number_samples'] / ($thisfile_bonk_BONK['sample_rate'] * $thisfile_bonk_BONK['channels']);
|
||||
if ($ThisFileInfo['playtime_seconds'] > 0) {
|
||||
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['bonk']['dataend'] - $ThisFileInfo['bonk']['dataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'INFO':
|
||||
// shortcut
|
||||
$thisfile_bonk_INFO = &$ThisFileInfo['bonk']['INFO'];
|
||||
|
||||
$thisfile_bonk_INFO['version'] = getid3_lib::LittleEndian2Int(fread($fd, 1));
|
||||
$thisfile_bonk_INFO['entries_count'] = 0;
|
||||
$NextInfoDataPair = fread($fd, 5);
|
||||
if (!$this->BonkIsValidTagName(substr($NextInfoDataPair, 1, 4))) {
|
||||
while (!feof($fd)) {
|
||||
//$CurrentSeekInfo['offset'] = getid3_lib::LittleEndian2Int(substr($NextInfoDataPair, 0, 4));
|
||||
//$CurrentSeekInfo['nextbit'] = getid3_lib::LittleEndian2Int(substr($NextInfoDataPair, 4, 1));
|
||||
//$thisfile_bonk_INFO[] = $CurrentSeekInfo;
|
||||
|
||||
$NextInfoDataPair = fread($fd, 5);
|
||||
if ($this->BonkIsValidTagName(substr($NextInfoDataPair, 1, 4))) {
|
||||
fseek($fd, -5, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
$thisfile_bonk_INFO['entries_count']++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'META':
|
||||
$BonkData = "\x00".'META'.fread($fd, $ThisFileInfo['bonk']['META']['size'] - 5);
|
||||
$ThisFileInfo['bonk']['META']['version'] = getid3_lib::LittleEndian2Int(substr($BonkData, 5, 1));
|
||||
|
||||
$MetaTagEntries = floor(((strlen($BonkData) - 8) - 6) / 8); // BonkData - xxxxmeta - ØMETA
|
||||
$offset = 6;
|
||||
for ($i = 0; $i < $MetaTagEntries; $i++) {
|
||||
$MetaEntryTagName = substr($BonkData, $offset, 4);
|
||||
$offset += 4;
|
||||
$MetaEntryTagOffset = getid3_lib::LittleEndian2Int(substr($BonkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$ThisFileInfo['bonk']['META']['tags'][$MetaEntryTagName] = $MetaEntryTagOffset;
|
||||
}
|
||||
break;
|
||||
|
||||
case ' ID3':
|
||||
$ThisFileInfo['audio']['encoder'] = 'Extended BONK v0.9+';
|
||||
|
||||
// ID3v2 checking is optional
|
||||
if (class_exists('getid3_id3v2')) {
|
||||
$ThisFileInfo['bonk'][' ID3']['valid'] = new getid3_id3v2($fd, $ThisFileInfo, $ThisFileInfo['bonk'][' ID3']['offset'] + 2);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$ThisFileInfo['warning'][] = 'Unexpected Bonk tag "'.$BonkTagName.'" at offset '.$ThisFileInfo['bonk'][$BonkTagName]['offset'];
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function BonkIsValidTagName($PossibleBonkTag, $ignorecase=false) {
|
||||
static $BonkIsValidTagName = array('BONK', 'INFO', ' ID3', 'META');
|
||||
foreach ($BonkIsValidTagName as $validtagname) {
|
||||
if ($validtagname == $PossibleBonkTag) {
|
||||
return true;
|
||||
} elseif ($ignorecase && (strtolower($validtagname) == strtolower($PossibleBonkTag))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,74 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.dss.php //
|
||||
// module for analyzing Digital Speech Standard (DSS) files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_dss
|
||||
{
|
||||
|
||||
function getid3_dss(&$fd, &$ThisFileInfo) {
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$DSSheader = fread($fd, 1256);
|
||||
|
||||
if (!preg_match('#^(\x02|\x03)dss', $DSSheader)) {
|
||||
$ThisFileInfo['error'][] = 'Expecting "[x02-x03]dss" at offset '.$ThisFileInfo['avdataoffset'].', found "'.substr($DSSheader, 0, 4).'"';
|
||||
return false;
|
||||
}
|
||||
|
||||
// some structure information taken from http://cpansearch.perl.org/src/RGIBSON/Audio-DSS-0.02/lib/Audio/DSS.pm
|
||||
|
||||
// shortcut
|
||||
$ThisFileInfo['dss'] = array();
|
||||
$thisfile_dss = &$ThisFileInfo['dss'];
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'dss';
|
||||
$ThisFileInfo['audio']['dataformat'] = 'dss';
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
|
||||
//$thisfile_dss['encoding'] = 'ISO-8859-1';
|
||||
|
||||
$thisfile_dss['version'] = ord(substr($DSSheader, 0, 1));
|
||||
$thisfile_dss['date_create'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 38, 12));
|
||||
$thisfile_dss['date_complete'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 50, 12));
|
||||
//$thisfile_dss['length'] = intval(substr($DSSheader, 62, 6)); // I thought time was in seconds, it's actually HHMMSS
|
||||
$thisfile_dss['length'] = intval((substr($DSSheader, 62, 2) * 3600) + (substr($DSSheader, 64, 2) * 60) + substr($DSSheader, 66, 2));
|
||||
$thisfile_dss['priority'] = ord(substr($DSSheader, 793, 1));
|
||||
$thisfile_dss['comments'] = trim(substr($DSSheader, 798, 100));
|
||||
|
||||
|
||||
//$ThisFileInfo['audio']['bits_per_sample'] = ?;
|
||||
//$ThisFileInfo['audio']['sample_rate'] = ?;
|
||||
$ThisFileInfo['audio']['channels'] = 1;
|
||||
|
||||
$ThisFileInfo['playtime_seconds'] = $thisfile_dss['length'];
|
||||
$ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['filesize'] * 8) / $ThisFileInfo['playtime_seconds'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function DSSdateStringToUnixDate($datestring) {
|
||||
$y = substr($datestring, 0, 2);
|
||||
$m = substr($datestring, 2, 2);
|
||||
$d = substr($datestring, 4, 2);
|
||||
$h = substr($datestring, 6, 2);
|
||||
$i = substr($datestring, 8, 2);
|
||||
$s = substr($datestring, 10, 2);
|
||||
$y += (($y < 95) ? 2000 : 1900);
|
||||
return mktime($h, $i, $s, $m, $d, $y);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,239 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.dts.php //
|
||||
// module for analyzing DTS Audio files //
|
||||
// dependencies: NONE //
|
||||
// //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_dts
|
||||
{
|
||||
|
||||
function getid3_dts(&$fd, &$ThisFileInfo) {
|
||||
// Specs taken from "DTS Coherent Acoustics;Core and Extensions, ETSI TS 102 114 V1.2.1 (2002-12)"
|
||||
// (http://pda.etsi.org/pda/queryform.asp)
|
||||
// With thanks to Gambit <macteam@users.sourceforge.net> http://mac.sourceforge.net/atl/
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'dts';
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$DTSheader = fread($fd, 16);
|
||||
|
||||
$ThisFileInfo['dts']['raw']['magic'] = getid3_lib::BigEndian2Int(substr($DTSheader, 0, 4));
|
||||
if ($ThisFileInfo['dts']['raw']['magic'] != 0x7FFE8001) {
|
||||
$ThisFileInfo['error'][] = 'Expecting "0x7FFE8001" at offset '.$ThisFileInfo['avdataoffset'].', found "0x'.str_pad(strtoupper(dechex($ThisFileInfo['dts']['raw']['magic'])), 8, '0', STR_PAD_LEFT).'"';
|
||||
unset($ThisFileInfo['fileformat']);
|
||||
unset($ThisFileInfo['dts']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$fhBS = getid3_lib::BigEndian2Bin(substr($DTSheader, 4, 12));
|
||||
$bsOffset = 0;
|
||||
$ThisFileInfo['dts']['raw']['frame_type'] = bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
|
||||
$ThisFileInfo['dts']['raw']['deficit_samples'] = bindec(substr($fhBS, $bsOffset, 5)); $bsOffset += 5;
|
||||
$ThisFileInfo['dts']['flags']['crc_present'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
|
||||
$ThisFileInfo['dts']['raw']['pcm_sample_blocks'] = bindec(substr($fhBS, $bsOffset, 7)); $bsOffset += 7;
|
||||
$ThisFileInfo['dts']['raw']['frame_byte_size'] = bindec(substr($fhBS, $bsOffset, 14)); $bsOffset += 14;
|
||||
$ThisFileInfo['dts']['raw']['channel_arrangement'] = bindec(substr($fhBS, $bsOffset, 6)); $bsOffset += 6;
|
||||
$ThisFileInfo['dts']['raw']['sample_frequency'] = bindec(substr($fhBS, $bsOffset, 4)); $bsOffset += 4;
|
||||
$ThisFileInfo['dts']['raw']['bitrate'] = bindec(substr($fhBS, $bsOffset, 5)); $bsOffset += 5;
|
||||
$ThisFileInfo['dts']['flags']['embedded_downmix'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
|
||||
$ThisFileInfo['dts']['flags']['dynamicrange'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
|
||||
$ThisFileInfo['dts']['flags']['timestamp'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
|
||||
$ThisFileInfo['dts']['flags']['auxdata'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
|
||||
$ThisFileInfo['dts']['flags']['hdcd'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
|
||||
$ThisFileInfo['dts']['raw']['extension_audio'] = bindec(substr($fhBS, $bsOffset, 3)); $bsOffset += 3;
|
||||
$ThisFileInfo['dts']['flags']['extended_coding'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
|
||||
$ThisFileInfo['dts']['flags']['audio_sync_insertion'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
|
||||
$ThisFileInfo['dts']['raw']['lfe_effects'] = bindec(substr($fhBS, $bsOffset, 2)); $bsOffset += 2;
|
||||
$ThisFileInfo['dts']['flags']['predictor_history'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
|
||||
if ($ThisFileInfo['dts']['flags']['crc_present']) {
|
||||
$ThisFileInfo['dts']['raw']['crc16'] = bindec(substr($fhBS, $bsOffset, 16)); $bsOffset += 16;
|
||||
}
|
||||
$ThisFileInfo['dts']['flags']['mri_perfect_reconst'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
|
||||
$ThisFileInfo['dts']['raw']['encoder_soft_version'] = bindec(substr($fhBS, $bsOffset, 4)); $bsOffset += 4;
|
||||
$ThisFileInfo['dts']['raw']['copy_history'] = bindec(substr($fhBS, $bsOffset, 2)); $bsOffset += 2;
|
||||
$ThisFileInfo['dts']['raw']['bits_per_sample'] = bindec(substr($fhBS, $bsOffset, 2)); $bsOffset += 2;
|
||||
$ThisFileInfo['dts']['flags']['surround_es'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
|
||||
$ThisFileInfo['dts']['flags']['front_sum_diff'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
|
||||
$ThisFileInfo['dts']['flags']['surround_sum_diff'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
|
||||
$ThisFileInfo['dts']['raw']['dialog_normalization'] = bindec(substr($fhBS, $bsOffset, 4)); $bsOffset += 4;
|
||||
|
||||
|
||||
$ThisFileInfo['dts']['bitrate'] = $this->DTSbitrateLookup($ThisFileInfo['dts']['raw']['bitrate']);
|
||||
$ThisFileInfo['dts']['bits_per_sample'] = $this->DTSbitPerSampleLookup($ThisFileInfo['dts']['raw']['bits_per_sample']);
|
||||
$ThisFileInfo['dts']['sample_rate'] = $this->DTSsampleRateLookup($ThisFileInfo['dts']['raw']['sample_frequency']);
|
||||
$ThisFileInfo['dts']['dialog_normalization'] = $this->DTSdialogNormalization($ThisFileInfo['dts']['raw']['dialog_normalization'], $ThisFileInfo['dts']['raw']['encoder_soft_version']);
|
||||
$ThisFileInfo['dts']['flags']['lossless'] = (($ThisFileInfo['dts']['raw']['bitrate'] == 31) ? true : false);
|
||||
$ThisFileInfo['dts']['bitrate_mode'] = (($ThisFileInfo['dts']['raw']['bitrate'] == 30) ? 'vbr' : 'cbr');
|
||||
$ThisFileInfo['dts']['channels'] = $this->DTSnumChannelsLookup($ThisFileInfo['dts']['raw']['channel_arrangement']);
|
||||
$ThisFileInfo['dts']['channel_arrangement'] = $this->DTSchannelArrangementLookup($ThisFileInfo['dts']['raw']['channel_arrangement']);
|
||||
|
||||
$ThisFileInfo['audio']['dataformat'] = 'dts';
|
||||
$ThisFileInfo['audio']['lossless'] = $ThisFileInfo['dts']['flags']['lossless'];
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = $ThisFileInfo['dts']['bitrate_mode'];
|
||||
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['dts']['bits_per_sample'];
|
||||
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['dts']['sample_rate'];
|
||||
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['dts']['channels'];
|
||||
$ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['dts']['bitrate'];
|
||||
if (isset($ThisFileInfo['avdataend'])) {
|
||||
$ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / ($ThisFileInfo['dts']['bitrate'] / 8);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function DTSbitrateLookup($index) {
|
||||
$DTSbitrateLookup = array(
|
||||
0 => 32000,
|
||||
1 => 56000,
|
||||
2 => 64000,
|
||||
3 => 96000,
|
||||
4 => 112000,
|
||||
5 => 128000,
|
||||
6 => 192000,
|
||||
7 => 224000,
|
||||
8 => 256000,
|
||||
9 => 320000,
|
||||
10 => 384000,
|
||||
11 => 448000,
|
||||
12 => 512000,
|
||||
13 => 576000,
|
||||
14 => 640000,
|
||||
15 => 768000,
|
||||
16 => 960000,
|
||||
17 => 1024000,
|
||||
18 => 1152000,
|
||||
19 => 1280000,
|
||||
20 => 1344000,
|
||||
21 => 1408000,
|
||||
22 => 1411200,
|
||||
23 => 1472000,
|
||||
24 => 1536000,
|
||||
25 => 1920000,
|
||||
26 => 2048000,
|
||||
27 => 3072000,
|
||||
28 => 3840000,
|
||||
29 => 'open',
|
||||
30 => 'variable',
|
||||
31 => 'lossless'
|
||||
);
|
||||
return (isset($DTSbitrateLookup[$index]) ? $DTSbitrateLookup[$index] : false);
|
||||
}
|
||||
|
||||
function DTSsampleRateLookup($index) {
|
||||
$DTSsampleRateLookup = array(
|
||||
0 => 'invalid',
|
||||
1 => 8000,
|
||||
2 => 16000,
|
||||
3 => 32000,
|
||||
4 => 'invalid',
|
||||
5 => 'invalid',
|
||||
6 => 11025,
|
||||
7 => 22050,
|
||||
8 => 44100,
|
||||
9 => 'invalid',
|
||||
10 => 'invalid',
|
||||
11 => 12000,
|
||||
12 => 24000,
|
||||
13 => 48000,
|
||||
14 => 'invalid',
|
||||
15 => 'invalid'
|
||||
);
|
||||
return (isset($DTSsampleRateLookup[$index]) ? $DTSsampleRateLookup[$index] : false);
|
||||
}
|
||||
|
||||
function DTSbitPerSampleLookup($index) {
|
||||
$DTSbitPerSampleLookup = array(
|
||||
0 => 16,
|
||||
1 => 20,
|
||||
2 => 24,
|
||||
3 => 24,
|
||||
);
|
||||
return (isset($DTSbitPerSampleLookup[$index]) ? $DTSbitPerSampleLookup[$index] : false);
|
||||
}
|
||||
|
||||
function DTSnumChannelsLookup($index) {
|
||||
switch ($index) {
|
||||
case 0:
|
||||
return 1;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
return 2;
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
return 3;
|
||||
break;
|
||||
case 7:
|
||||
case 8:
|
||||
return 4;
|
||||
break;
|
||||
case 9:
|
||||
return 5;
|
||||
break;
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
return 6;
|
||||
break;
|
||||
case 13:
|
||||
return 7;
|
||||
break;
|
||||
case 14:
|
||||
case 15:
|
||||
return 8;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function DTSchannelArrangementLookup($index) {
|
||||
$DTSchannelArrangementLookup = array(
|
||||
0 => 'A',
|
||||
1 => 'A + B (dual mono)',
|
||||
2 => 'L + R (stereo)',
|
||||
3 => '(L+R) + (L-R) (sum-difference)',
|
||||
4 => 'LT + RT (left and right total)',
|
||||
5 => 'C + L + R',
|
||||
6 => 'L + R + S',
|
||||
7 => 'C + L + R + S',
|
||||
8 => 'L + R + SL + SR',
|
||||
9 => 'C + L + R + SL + SR',
|
||||
10 => 'CL + CR + L + R + SL + SR',
|
||||
11 => 'C + L + R+ LR + RR + OV',
|
||||
12 => 'CF + CR + LF + RF + LR + RR',
|
||||
13 => 'CL + C + CR + L + R + SL + SR',
|
||||
14 => 'CL + CR + L + R + SL1 + SL2 + SR1 + SR2',
|
||||
15 => 'CL + C+ CR + L + R + SL + S + SR',
|
||||
);
|
||||
return (isset($DTSchannelArrangementLookup[$index]) ? $DTSchannelArrangementLookup[$index] : 'user-defined');
|
||||
}
|
||||
|
||||
function DTSdialogNormalization($index, $version) {
|
||||
switch ($version) {
|
||||
case 7:
|
||||
return 0 - $index;
|
||||
break;
|
||||
case 6:
|
||||
return 0 - 16 - $index;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,403 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.flac.php //
|
||||
// module for analyzing FLAC and OggFLAC audio files //
|
||||
// dependencies: module.audio.ogg.php //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, true);
|
||||
|
||||
class getid3_flac
|
||||
{
|
||||
|
||||
function getid3_flac(&$fd, &$ThisFileInfo) {
|
||||
// http://flac.sourceforge.net/format.html
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$StreamMarker = fread($fd, 4);
|
||||
if ($StreamMarker != 'fLaC') {
|
||||
$ThisFileInfo['error'][] = 'Expecting "fLaC" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$StreamMarker.'"';
|
||||
return false;
|
||||
}
|
||||
$ThisFileInfo['fileformat'] = 'flac';
|
||||
$ThisFileInfo['audio']['dataformat'] = 'flac';
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
|
||||
$ThisFileInfo['audio']['lossless'] = true;
|
||||
|
||||
return getid3_flac::FLACparseMETAdata($fd, $ThisFileInfo);
|
||||
}
|
||||
|
||||
|
||||
static function FLACparseMETAdata(&$fd, &$ThisFileInfo) {
|
||||
|
||||
do {
|
||||
$METAdataBlockOffset = ftell($fd);
|
||||
$METAdataBlockHeader = fread($fd, 4);
|
||||
$METAdataLastBlockFlag = (bool) (getid3_lib::BigEndian2Int(substr($METAdataBlockHeader, 0, 1)) & 0x80);
|
||||
$METAdataBlockType = getid3_lib::BigEndian2Int(substr($METAdataBlockHeader, 0, 1)) & 0x7F;
|
||||
$METAdataBlockLength = getid3_lib::BigEndian2Int(substr($METAdataBlockHeader, 1, 3));
|
||||
$METAdataBlockTypeText = getid3_flac::FLACmetaBlockTypeLookup($METAdataBlockType);
|
||||
|
||||
if ($METAdataBlockLength < 0) {
|
||||
$ThisFileInfo['error'][] = 'corrupt or invalid METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$METAdataBlockType.') at offset '.$METAdataBlockOffset;
|
||||
break;
|
||||
}
|
||||
|
||||
$ThisFileInfo['flac'][$METAdataBlockTypeText]['raw'] = array();
|
||||
$ThisFileInfo_flac_METAdataBlockTypeText_raw = &$ThisFileInfo['flac'][$METAdataBlockTypeText]['raw'];
|
||||
|
||||
$ThisFileInfo_flac_METAdataBlockTypeText_raw['offset'] = $METAdataBlockOffset;
|
||||
$ThisFileInfo_flac_METAdataBlockTypeText_raw['last_meta_block'] = $METAdataLastBlockFlag;
|
||||
$ThisFileInfo_flac_METAdataBlockTypeText_raw['block_type'] = $METAdataBlockType;
|
||||
$ThisFileInfo_flac_METAdataBlockTypeText_raw['block_type_text'] = $METAdataBlockTypeText;
|
||||
$ThisFileInfo_flac_METAdataBlockTypeText_raw['block_length'] = $METAdataBlockLength;
|
||||
ob_start();
|
||||
$ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'] = fread($fd, $METAdataBlockLength);
|
||||
$errormessage = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$ThisFileInfo['avdataoffset'] = ftell($fd);
|
||||
|
||||
switch ($METAdataBlockTypeText) {
|
||||
case 'STREAMINFO': // 0x00
|
||||
if (!getid3_flac::FLACparseSTREAMINFO($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'], $ThisFileInfo)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PADDING': // 0x01
|
||||
// ignore
|
||||
break;
|
||||
|
||||
case 'APPLICATION': // 0x02
|
||||
if (!getid3_flac::FLACparseAPPLICATION($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'], $ThisFileInfo)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'SEEKTABLE': // 0x03
|
||||
if (!getid3_flac::FLACparseSEEKTABLE($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'], $ThisFileInfo)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'VORBIS_COMMENT': // 0x04
|
||||
$OldOffset = ftell($fd);
|
||||
fseek($fd, 0 - $METAdataBlockLength, SEEK_CUR);
|
||||
getid3_ogg::ParseVorbisCommentsFilepointer($fd, $ThisFileInfo);
|
||||
fseek($fd, $OldOffset, SEEK_SET);
|
||||
break;
|
||||
|
||||
case 'CUESHEET': // 0x05
|
||||
if (!getid3_flac::FLACparseCUESHEET($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'], $ThisFileInfo)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PICTURE': // 0x06
|
||||
if (!getid3_flac::FLACparsePICTURE($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'], $ThisFileInfo)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$ThisFileInfo['warning'][] = 'Unhandled METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$METAdataBlockType.') at offset '.$METAdataBlockOffset;
|
||||
break;
|
||||
}
|
||||
|
||||
} while ($METAdataLastBlockFlag === false);
|
||||
|
||||
|
||||
if (isset($ThisFileInfo['flac']['STREAMINFO'])) {
|
||||
$ThisFileInfo['flac']['compressed_audio_bytes'] = $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'];
|
||||
$ThisFileInfo['flac']['uncompressed_audio_bytes'] = $ThisFileInfo['flac']['STREAMINFO']['samples_stream'] * $ThisFileInfo['flac']['STREAMINFO']['channels'] * ($ThisFileInfo['flac']['STREAMINFO']['bits_per_sample'] / 8);
|
||||
if ($ThisFileInfo['flac']['uncompressed_audio_bytes'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'Corrupt FLAC file: uncompressed_audio_bytes == zero';
|
||||
return false;
|
||||
}
|
||||
$ThisFileInfo['flac']['compression_ratio'] = $ThisFileInfo['flac']['compressed_audio_bytes'] / $ThisFileInfo['flac']['uncompressed_audio_bytes'];
|
||||
}
|
||||
|
||||
// set md5_data_source - built into flac 0.5+
|
||||
if (isset($ThisFileInfo['flac']['STREAMINFO']['audio_signature'])) {
|
||||
|
||||
if ($ThisFileInfo['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) {
|
||||
|
||||
$ThisFileInfo['warning'][] = 'FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)';
|
||||
|
||||
} else {
|
||||
|
||||
$ThisFileInfo['md5_data_source'] = '';
|
||||
$md5 = $ThisFileInfo['flac']['STREAMINFO']['audio_signature'];
|
||||
for ($i = 0; $i < strlen($md5); $i++) {
|
||||
$ThisFileInfo['md5_data_source'] .= str_pad(dechex(ord($md5{$i})), 2, '00', STR_PAD_LEFT);
|
||||
}
|
||||
if (!preg_match('/^[0-9a-f]{32}$/', $ThisFileInfo['md5_data_source'])) {
|
||||
unset($ThisFileInfo['md5_data_source']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['flac']['STREAMINFO']['bits_per_sample'];
|
||||
if ($ThisFileInfo['audio']['bits_per_sample'] == 8) {
|
||||
// special case
|
||||
// must invert sign bit on all data bytes before MD5'ing to match FLAC's calculated value
|
||||
// MD5sum calculates on unsigned bytes, but FLAC calculated MD5 on 8-bit audio data as signed
|
||||
$ThisFileInfo['warning'][] = 'FLAC calculates MD5 data strangely on 8-bit audio, so the stored md5_data_source value will not match the decoded WAV file';
|
||||
}
|
||||
if (!empty($ThisFileInfo['ogg']['vendor'])) {
|
||||
$ThisFileInfo['audio']['encoder'] = $ThisFileInfo['ogg']['vendor'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static function FLACmetaBlockTypeLookup($blocktype) {
|
||||
static $FLACmetaBlockTypeLookup = array();
|
||||
if (empty($FLACmetaBlockTypeLookup)) {
|
||||
$FLACmetaBlockTypeLookup[0] = 'STREAMINFO';
|
||||
$FLACmetaBlockTypeLookup[1] = 'PADDING';
|
||||
$FLACmetaBlockTypeLookup[2] = 'APPLICATION';
|
||||
$FLACmetaBlockTypeLookup[3] = 'SEEKTABLE';
|
||||
$FLACmetaBlockTypeLookup[4] = 'VORBIS_COMMENT';
|
||||
$FLACmetaBlockTypeLookup[5] = 'CUESHEET';
|
||||
$FLACmetaBlockTypeLookup[6] = 'PICTURE';
|
||||
}
|
||||
return (isset($FLACmetaBlockTypeLookup[$blocktype]) ? $FLACmetaBlockTypeLookup[$blocktype] : 'reserved');
|
||||
}
|
||||
|
||||
static function FLACapplicationIDLookup($applicationid) {
|
||||
static $FLACapplicationIDLookup = array();
|
||||
if (empty($FLACapplicationIDLookup)) {
|
||||
// http://flac.sourceforge.net/id.html
|
||||
$FLACapplicationIDLookup[0x46746F6C] = 'flac-tools'; // 'Ftol'
|
||||
$FLACapplicationIDLookup[0x46746F6C] = 'Sound Font FLAC'; // 'SFFL'
|
||||
}
|
||||
return (isset($FLACapplicationIDLookup[$applicationid]) ? $FLACapplicationIDLookup[$applicationid] : 'reserved');
|
||||
}
|
||||
|
||||
static function FLACpictureTypeLookup($type_id) {
|
||||
static $lookup = array (
|
||||
0 => 'Other',
|
||||
1 => '32x32 pixels \'file icon\' (PNG only)',
|
||||
2 => 'Other file icon',
|
||||
3 => 'Cover (front)',
|
||||
4 => 'Cover (back)',
|
||||
5 => 'Leaflet page',
|
||||
6 => 'Media (e.g. label side of CD)',
|
||||
7 => 'Lead artist/lead performer/soloist',
|
||||
8 => 'Artist/performer',
|
||||
9 => 'Conductor',
|
||||
10 => 'Band/Orchestra',
|
||||
11 => 'Composer',
|
||||
12 => 'Lyricist/text writer',
|
||||
13 => 'Recording Location',
|
||||
14 => 'During recording',
|
||||
15 => 'During performance',
|
||||
16 => 'Movie/video screen capture',
|
||||
17 => 'A bright coloured fish',
|
||||
18 => 'Illustration',
|
||||
19 => 'Band/artist logotype',
|
||||
20 => 'Publisher/Studio logotype',
|
||||
);
|
||||
return (isset($lookup[$type_id]) ? $lookup[$type_id] : 'reserved');
|
||||
}
|
||||
|
||||
static function FLACparseSTREAMINFO($METAdataBlockData, &$ThisFileInfo) {
|
||||
$offset = 0;
|
||||
$ThisFileInfo['flac']['STREAMINFO']['min_block_size'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 2));
|
||||
$offset += 2;
|
||||
$ThisFileInfo['flac']['STREAMINFO']['max_block_size'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 2));
|
||||
$offset += 2;
|
||||
$ThisFileInfo['flac']['STREAMINFO']['min_frame_size'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 3));
|
||||
$offset += 3;
|
||||
$ThisFileInfo['flac']['STREAMINFO']['max_frame_size'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 3));
|
||||
$offset += 3;
|
||||
|
||||
$SampleRateChannelsSampleBitsStreamSamples = getid3_lib::BigEndian2Bin(substr($METAdataBlockData, $offset, 8));
|
||||
$ThisFileInfo['flac']['STREAMINFO']['sample_rate'] = getid3_lib::Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 0, 20));
|
||||
$ThisFileInfo['flac']['STREAMINFO']['channels'] = getid3_lib::Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 20, 3)) + 1;
|
||||
$ThisFileInfo['flac']['STREAMINFO']['bits_per_sample'] = getid3_lib::Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 23, 5)) + 1;
|
||||
$ThisFileInfo['flac']['STREAMINFO']['samples_stream'] = getid3_lib::Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 28, 36));
|
||||
$offset += 8;
|
||||
|
||||
$ThisFileInfo['flac']['STREAMINFO']['audio_signature'] = substr($METAdataBlockData, $offset, 16);
|
||||
$offset += 16;
|
||||
|
||||
if (!empty($ThisFileInfo['flac']['STREAMINFO']['sample_rate'])) {
|
||||
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
|
||||
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['flac']['STREAMINFO']['sample_rate'];
|
||||
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['flac']['STREAMINFO']['channels'];
|
||||
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['flac']['STREAMINFO']['bits_per_sample'];
|
||||
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['flac']['STREAMINFO']['samples_stream'] / $ThisFileInfo['flac']['STREAMINFO']['sample_rate'];
|
||||
if ($ThisFileInfo['playtime_seconds'] > 0) {
|
||||
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$ThisFileInfo['error'][] = 'Corrupt METAdata block: STREAMINFO';
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
unset($ThisFileInfo['flac']['STREAMINFO']['raw']);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static function FLACparseAPPLICATION($METAdataBlockData, &$ThisFileInfo) {
|
||||
$offset = 0;
|
||||
$ApplicationID = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 4));
|
||||
$offset += 4;
|
||||
$ThisFileInfo['flac']['APPLICATION'][$ApplicationID]['name'] = getid3_flac::FLACapplicationIDLookup($ApplicationID);
|
||||
$ThisFileInfo['flac']['APPLICATION'][$ApplicationID]['data'] = substr($METAdataBlockData, $offset);
|
||||
$offset = $METAdataBlockLength;
|
||||
|
||||
unset($ThisFileInfo['flac']['APPLICATION']['raw']);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static function FLACparseSEEKTABLE($METAdataBlockData, &$ThisFileInfo) {
|
||||
$offset = 0;
|
||||
$METAdataBlockLength = strlen($METAdataBlockData);
|
||||
$placeholderpattern = str_repeat("\xFF", 8);
|
||||
while ($offset < $METAdataBlockLength) {
|
||||
$SampleNumberString = substr($METAdataBlockData, $offset, 8);
|
||||
$offset += 8;
|
||||
if ($SampleNumberString == $placeholderpattern) {
|
||||
|
||||
// placeholder point
|
||||
getid3_lib::safe_inc($ThisFileInfo['flac']['SEEKTABLE']['placeholders'], 1);
|
||||
$offset += 10;
|
||||
|
||||
} else {
|
||||
|
||||
$SampleNumber = getid3_lib::BigEndian2Int($SampleNumberString);
|
||||
$ThisFileInfo['flac']['SEEKTABLE'][$SampleNumber]['offset'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 8));
|
||||
$offset += 8;
|
||||
$ThisFileInfo['flac']['SEEKTABLE'][$SampleNumber]['samples'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 2));
|
||||
$offset += 2;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
unset($ThisFileInfo['flac']['SEEKTABLE']['raw']);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static function FLACparseCUESHEET($METAdataBlockData, &$ThisFileInfo) {
|
||||
$offset = 0;
|
||||
$ThisFileInfo['flac']['CUESHEET']['media_catalog_number'] = trim(substr($METAdataBlockData, $offset, 128), "\0");
|
||||
$offset += 128;
|
||||
$ThisFileInfo['flac']['CUESHEET']['lead_in_samples'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 8));
|
||||
$offset += 8;
|
||||
$ThisFileInfo['flac']['CUESHEET']['flags']['is_cd'] = (bool) (getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1)) & 0x80);
|
||||
$offset += 1;
|
||||
|
||||
$offset += 258; // reserved
|
||||
|
||||
$ThisFileInfo['flac']['CUESHEET']['number_tracks'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1));
|
||||
$offset += 1;
|
||||
|
||||
for ($track = 0; $track < $ThisFileInfo['flac']['CUESHEET']['number_tracks']; $track++) {
|
||||
$TrackSampleOffset = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 8));
|
||||
$offset += 8;
|
||||
$TrackNumber = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1));
|
||||
$offset += 1;
|
||||
|
||||
$ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['sample_offset'] = $TrackSampleOffset;
|
||||
|
||||
$ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['isrc'] = substr($METAdataBlockData, $offset, 12);
|
||||
$offset += 12;
|
||||
|
||||
$TrackFlagsRaw = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1));
|
||||
$offset += 1;
|
||||
$ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['is_audio'] = (bool) ($TrackFlagsRaw & 0x80);
|
||||
$ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['pre_emphasis'] = (bool) ($TrackFlagsRaw & 0x40);
|
||||
|
||||
$offset += 13; // reserved
|
||||
|
||||
$ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1));
|
||||
$offset += 1;
|
||||
|
||||
for ($index = 0; $index < $ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points']; $index++) {
|
||||
$IndexSampleOffset = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 8));
|
||||
$offset += 8;
|
||||
$IndexNumber = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1));
|
||||
$offset += 1;
|
||||
|
||||
$offset += 3; // reserved
|
||||
|
||||
$ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['indexes'][$IndexNumber] = $IndexSampleOffset;
|
||||
}
|
||||
}
|
||||
|
||||
unset($ThisFileInfo['flac']['CUESHEET']['raw']);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static function FLACparsePICTURE($meta_data_block_data, &$ThisFileInfo) {
|
||||
$picture = &$ThisFileInfo['flac']['PICTURE'][sizeof($ThisFileInfo['flac']['PICTURE']) - 1];
|
||||
|
||||
$offset = 0;
|
||||
|
||||
$picture['typeid'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4));
|
||||
$picture['type'] = getid3_flac::FLACpictureTypeLookup($picture['typeid']);
|
||||
$offset += 4;
|
||||
|
||||
$length = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$picture['mime_type'] = substr($meta_data_block_data, $offset, $length);
|
||||
$offset += $length;
|
||||
|
||||
$length = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$picture['description'] = substr($meta_data_block_data, $offset, $length);
|
||||
$offset += $length;
|
||||
|
||||
$picture['width'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$picture['height'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$picture['color_depth'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$picture['colors_indexed'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$length = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$picture['image_data'] = substr($meta_data_block_data, $offset, $length);
|
||||
$offset += $length;
|
||||
$picture['data_length'] = strlen($picture['image_data']);
|
||||
|
||||
unset($ThisFileInfo['flac']['PICTURE']['raw']);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,228 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.la.php //
|
||||
// module for analyzing LA (LosslessAudio) audio files //
|
||||
// dependencies: module.audio.riff.php //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
|
||||
|
||||
class getid3_la
|
||||
{
|
||||
|
||||
function getid3_la(&$fd, &$ThisFileInfo) {
|
||||
$offset = 0;
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$rawdata = fread($fd, GETID3_FREAD_BUFFER_SIZE);
|
||||
|
||||
switch (substr($rawdata, $offset, 4)) {
|
||||
case 'LA02':
|
||||
case 'LA03':
|
||||
case 'LA04':
|
||||
$ThisFileInfo['fileformat'] = 'la';
|
||||
$ThisFileInfo['audio']['dataformat'] = 'la';
|
||||
$ThisFileInfo['audio']['lossless'] = true;
|
||||
|
||||
$ThisFileInfo['la']['version_major'] = (int) substr($rawdata, $offset + 2, 1);
|
||||
$ThisFileInfo['la']['version_minor'] = (int) substr($rawdata, $offset + 3, 1);
|
||||
$ThisFileInfo['la']['version'] = (float) $ThisFileInfo['la']['version_major'] + ($ThisFileInfo['la']['version_minor'] / 10);
|
||||
$offset += 4;
|
||||
|
||||
$ThisFileInfo['la']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
|
||||
$offset += 4;
|
||||
if ($ThisFileInfo['la']['uncompressed_size'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'Corrupt LA file: uncompressed_size == zero';
|
||||
return false;
|
||||
}
|
||||
|
||||
$WAVEchunk = substr($rawdata, $offset, 4);
|
||||
if ($WAVEchunk !== 'WAVE') {
|
||||
$ThisFileInfo['error'][] = 'Expected "WAVE" ('.getid3_lib::PrintHexBytes('WAVE').') at offset '.$offset.', found "'.$WAVEchunk.'" ('.getid3_lib::PrintHexBytes($WAVEchunk).') instead.';
|
||||
return false;
|
||||
}
|
||||
$offset += 4;
|
||||
|
||||
$ThisFileInfo['la']['fmt_size'] = 24;
|
||||
if ($ThisFileInfo['la']['version'] >= 0.3) {
|
||||
|
||||
$ThisFileInfo['la']['fmt_size'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
|
||||
$ThisFileInfo['la']['header_size'] = 49 + $ThisFileInfo['la']['fmt_size'] - 24;
|
||||
$offset += 4;
|
||||
|
||||
} else {
|
||||
|
||||
// version 0.2 didn't support additional data blocks
|
||||
$ThisFileInfo['la']['header_size'] = 41;
|
||||
|
||||
}
|
||||
|
||||
$fmt_chunk = substr($rawdata, $offset, 4);
|
||||
if ($fmt_chunk !== 'fmt ') {
|
||||
$ThisFileInfo['error'][] = 'Expected "fmt " ('.getid3_lib::PrintHexBytes('fmt ').') at offset '.$offset.', found "'.$fmt_chunk.'" ('.getid3_lib::PrintHexBytes($fmt_chunk).') instead.';
|
||||
return false;
|
||||
}
|
||||
$offset += 4;
|
||||
$fmt_size = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$ThisFileInfo['la']['raw']['format'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2));
|
||||
$offset += 2;
|
||||
|
||||
$ThisFileInfo['la']['channels'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2));
|
||||
$offset += 2;
|
||||
if ($ThisFileInfo['la']['channels'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'Corrupt LA file: channels == zero';
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['la']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
|
||||
$offset += 4;
|
||||
if ($ThisFileInfo['la']['sample_rate'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'Corrupt LA file: sample_rate == zero';
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['la']['bytes_per_second'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
|
||||
$offset += 4;
|
||||
$ThisFileInfo['la']['bytes_per_sample'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2));
|
||||
$offset += 2;
|
||||
$ThisFileInfo['la']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2));
|
||||
$offset += 2;
|
||||
|
||||
$ThisFileInfo['la']['samples'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$ThisFileInfo['la']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 1));
|
||||
$offset += 1;
|
||||
$ThisFileInfo['la']['flags']['seekable'] = (bool) ($ThisFileInfo['la']['raw']['flags'] & 0x01);
|
||||
if ($ThisFileInfo['la']['version'] >= 0.4) {
|
||||
$ThisFileInfo['la']['flags']['high_compression'] = (bool) ($ThisFileInfo['la']['raw']['flags'] & 0x02);
|
||||
}
|
||||
|
||||
$ThisFileInfo['la']['original_crc'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
// mikeØbevin*de
|
||||
// Basically, the blocksize/seekevery are 61440/19 in La0.4 and 73728/16
|
||||
// in earlier versions. A seekpoint is added every blocksize * seekevery
|
||||
// samples, so 4 * int(totalSamples / (blockSize * seekEvery)) should
|
||||
// give the number of bytes used for the seekpoints. Of course, if seeking
|
||||
// is disabled, there are no seekpoints stored.
|
||||
if ($ThisFileInfo['la']['version'] >= 0.4) {
|
||||
$ThisFileInfo['la']['blocksize'] = 61440;
|
||||
$ThisFileInfo['la']['seekevery'] = 19;
|
||||
} else {
|
||||
$ThisFileInfo['la']['blocksize'] = 73728;
|
||||
$ThisFileInfo['la']['seekevery'] = 16;
|
||||
}
|
||||
|
||||
$ThisFileInfo['la']['seekpoint_count'] = 0;
|
||||
if ($ThisFileInfo['la']['flags']['seekable']) {
|
||||
$ThisFileInfo['la']['seekpoint_count'] = floor($ThisFileInfo['la']['samples'] / ($ThisFileInfo['la']['blocksize'] * $ThisFileInfo['la']['seekevery']));
|
||||
|
||||
for ($i = 0; $i < $ThisFileInfo['la']['seekpoint_count']; $i++) {
|
||||
$ThisFileInfo['la']['seekpoints'][] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
|
||||
$offset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if ($ThisFileInfo['la']['version'] >= 0.3) {
|
||||
|
||||
// Following the main header information, the program outputs all of the
|
||||
// seekpoints. Following these is what I called the 'footer start',
|
||||
// i.e. the position immediately after the La audio data is finished.
|
||||
$ThisFileInfo['la']['footerstart'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
if ($ThisFileInfo['la']['footerstart'] > $ThisFileInfo['filesize']) {
|
||||
$ThisFileInfo['warning'][] = 'FooterStart value points to offset '.$ThisFileInfo['la']['footerstart'].' which is beyond end-of-file ('.$ThisFileInfo['filesize'].')';
|
||||
$ThisFileInfo['la']['footerstart'] = $ThisFileInfo['filesize'];
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// La v0.2 didn't have FooterStart value
|
||||
$ThisFileInfo['la']['footerstart'] = $ThisFileInfo['avdataend'];
|
||||
|
||||
}
|
||||
|
||||
if ($ThisFileInfo['la']['footerstart'] < $ThisFileInfo['avdataend']) {
|
||||
if ($RIFFtempfilename = tempnam(GETID3_TEMP_DIR, 'id3')) {
|
||||
if ($RIFF_fp = fopen($RIFFtempfilename, 'w+b')) {
|
||||
$RIFFdata = 'WAVE';
|
||||
if ($ThisFileInfo['la']['version'] == 0.2) {
|
||||
$RIFFdata .= substr($rawdata, 12, 24);
|
||||
} else {
|
||||
$RIFFdata .= substr($rawdata, 16, 24);
|
||||
}
|
||||
if ($ThisFileInfo['la']['footerstart'] < $ThisFileInfo['avdataend']) {
|
||||
fseek($fd, $ThisFileInfo['la']['footerstart'], SEEK_SET);
|
||||
$RIFFdata .= fread($fd, $ThisFileInfo['avdataend'] - $ThisFileInfo['la']['footerstart']);
|
||||
}
|
||||
$RIFFdata = 'RIFF'.getid3_lib::LittleEndian2String(strlen($RIFFdata), 4, false).$RIFFdata;
|
||||
fwrite($RIFF_fp, $RIFFdata, strlen($RIFFdata));
|
||||
$dummy = $ThisFileInfo;
|
||||
$dummy['filesize'] = strlen($RIFFdata);
|
||||
$dummy['avdataoffset'] = 0;
|
||||
$dummy['avdataend'] = $dummy['filesize'];
|
||||
|
||||
$riff = new getid3_riff($RIFF_fp, $dummy);
|
||||
if (empty($dummy['error'])) {
|
||||
$ThisFileInfo['riff'] = $dummy['riff'];
|
||||
} else {
|
||||
$ThisFileInfo['warning'][] = 'Error parsing RIFF portion of La file: '.implode($dummy['error']);
|
||||
}
|
||||
unset($riff);
|
||||
unset($dummy);
|
||||
fclose($RIFF_fp);
|
||||
}
|
||||
unlink($RIFFtempfilename);
|
||||
}
|
||||
}
|
||||
|
||||
// $ThisFileInfo['avdataoffset'] should be zero to begin with, but just in case it's not, include the addition anyway
|
||||
$ThisFileInfo['avdataend'] = $ThisFileInfo['avdataoffset'] + $ThisFileInfo['la']['footerstart'];
|
||||
$ThisFileInfo['avdataoffset'] = $ThisFileInfo['avdataoffset'] + $offset;
|
||||
|
||||
//$ThisFileInfo['la']['codec'] = RIFFwFormatTagLookup($ThisFileInfo['la']['raw']['format']);
|
||||
$ThisFileInfo['la']['compression_ratio'] = (float) (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['la']['uncompressed_size']);
|
||||
$ThisFileInfo['playtime_seconds'] = (float) ($ThisFileInfo['la']['samples'] / $ThisFileInfo['la']['sample_rate']) / $ThisFileInfo['la']['channels'];
|
||||
if ($ThisFileInfo['playtime_seconds'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'Corrupt LA file: playtime_seconds == zero';
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['playtime_seconds'];
|
||||
//$ThisFileInfo['audio']['codec'] = $ThisFileInfo['la']['codec'];
|
||||
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['la']['bits_per_sample'];
|
||||
break;
|
||||
|
||||
default:
|
||||
if (substr($rawdata, $offset, 2) == 'LA') {
|
||||
$ThisFileInfo['error'][] = 'This version of getID3() (v'.GETID3_VERSION.') doesn\'t support LA version '.substr($rawdata, $offset + 2, 1).'.'.substr($rawdata, $offset + 3, 1).' which this appears to be - check http://getid3.sourceforge.net for updates.';
|
||||
} else {
|
||||
$ThisFileInfo['error'][] = 'Not a LA (Lossless-Audio) file';
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['la']['channels'];
|
||||
$ThisFileInfo['audio']['sample_rate'] = (int) $ThisFileInfo['la']['sample_rate'];
|
||||
$ThisFileInfo['audio']['encoder'] = 'LA v'.$ThisFileInfo['la']['version'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,126 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.lpac.php //
|
||||
// module for analyzing LPAC Audio files //
|
||||
// dependencies: module.audio-video.riff.php //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
|
||||
|
||||
class getid3_lpac
|
||||
{
|
||||
|
||||
function getid3_lpac(&$fd, &$ThisFileInfo) {
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$LPACheader = fread($fd, 14);
|
||||
if (substr($LPACheader, 0, 4) != 'LPAC') {
|
||||
$ThisFileInfo['error'][] = 'Expected "LPAC" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$StreamMarker.'"';
|
||||
return false;
|
||||
}
|
||||
$ThisFileInfo['avdataoffset'] += 14;
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'lpac';
|
||||
$ThisFileInfo['audio']['dataformat'] = 'lpac';
|
||||
$ThisFileInfo['audio']['lossless'] = true;
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
|
||||
|
||||
$ThisFileInfo['lpac']['file_version'] = getid3_lib::BigEndian2Int(substr($LPACheader, 4, 1));
|
||||
$flags['audio_type'] = getid3_lib::BigEndian2Int(substr($LPACheader, 5, 1));
|
||||
$ThisFileInfo['lpac']['total_samples']= getid3_lib::BigEndian2Int(substr($LPACheader, 6, 4));
|
||||
$flags['parameters'] = getid3_lib::BigEndian2Int(substr($LPACheader, 10, 4));
|
||||
|
||||
$ThisFileInfo['lpac']['flags']['is_wave'] = (bool) ($flags['audio_type'] & 0x40);
|
||||
$ThisFileInfo['lpac']['flags']['stereo'] = (bool) ($flags['audio_type'] & 0x04);
|
||||
$ThisFileInfo['lpac']['flags']['24_bit'] = (bool) ($flags['audio_type'] & 0x02);
|
||||
$ThisFileInfo['lpac']['flags']['16_bit'] = (bool) ($flags['audio_type'] & 0x01);
|
||||
|
||||
if ($ThisFileInfo['lpac']['flags']['24_bit'] && $ThisFileInfo['lpac']['flags']['16_bit']) {
|
||||
$ThisFileInfo['warning'][] = '24-bit and 16-bit flags cannot both be set';
|
||||
}
|
||||
|
||||
$ThisFileInfo['lpac']['flags']['fast_compress'] = (bool) ($flags['parameters'] & 0x40000000);
|
||||
$ThisFileInfo['lpac']['flags']['random_access'] = (bool) ($flags['parameters'] & 0x08000000);
|
||||
$ThisFileInfo['lpac']['block_length'] = pow(2, (($flags['parameters'] & 0x07000000) >> 24)) * 256;
|
||||
$ThisFileInfo['lpac']['flags']['adaptive_prediction_order'] = (bool) ($flags['parameters'] & 0x00800000);
|
||||
$ThisFileInfo['lpac']['flags']['adaptive_quantization'] = (bool) ($flags['parameters'] & 0x00400000);
|
||||
$ThisFileInfo['lpac']['flags']['joint_stereo'] = (bool) ($flags['parameters'] & 0x00040000);
|
||||
$ThisFileInfo['lpac']['quantization'] = ($flags['parameters'] & 0x00001F00) >> 8;
|
||||
$ThisFileInfo['lpac']['max_prediction_order'] = ($flags['parameters'] & 0x0000003F);
|
||||
|
||||
if ($ThisFileInfo['lpac']['flags']['fast_compress'] && ($ThisFileInfo['lpac']['max_prediction_order'] != 3)) {
|
||||
$ThisFileInfo['warning'][] = 'max_prediction_order expected to be "3" if fast_compress is true, actual value is "'.$ThisFileInfo['lpac']['max_prediction_order'].'"';
|
||||
}
|
||||
switch ($ThisFileInfo['lpac']['file_version']) {
|
||||
case 6:
|
||||
if ($ThisFileInfo['lpac']['flags']['adaptive_quantization']) {
|
||||
$ThisFileInfo['warning'][] = 'adaptive_quantization expected to be false in LPAC file stucture v6, actually true';
|
||||
}
|
||||
if ($ThisFileInfo['lpac']['quantization'] != 20) {
|
||||
$ThisFileInfo['warning'][] = 'Quantization expected to be 20 in LPAC file stucture v6, actually '.$ThisFileInfo['lpac']['flags']['Q'];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
//$ThisFileInfo['warning'][] = 'This version of getID3() only supports LPAC file format version 6, this file is version '.$ThisFileInfo['lpac']['file_version'].' - please report to info@getid3.org';
|
||||
break;
|
||||
}
|
||||
|
||||
$dummy = $ThisFileInfo;
|
||||
$riff = new getid3_riff($fd, $dummy);
|
||||
unset($riff);
|
||||
$ThisFileInfo['avdataoffset'] = $dummy['avdataoffset'];
|
||||
$ThisFileInfo['riff'] = $dummy['riff'];
|
||||
$ThisFileInfo['error'] = $dummy['error'];
|
||||
$ThisFileInfo['warning'] = $dummy['warning'];
|
||||
$ThisFileInfo['lpac']['comments']['comment'] = $dummy['comments'];
|
||||
$ThisFileInfo['audio']['sample_rate'] = $dummy['audio']['sample_rate'];
|
||||
|
||||
$ThisFileInfo['audio']['channels'] = ($ThisFileInfo['lpac']['flags']['stereo'] ? 2 : 1);
|
||||
|
||||
if ($ThisFileInfo['lpac']['flags']['24_bit']) {
|
||||
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['riff']['audio'][0]['bits_per_sample'];
|
||||
} elseif ($ThisFileInfo['lpac']['flags']['16_bit']) {
|
||||
$ThisFileInfo['audio']['bits_per_sample'] = 16;
|
||||
} else {
|
||||
$ThisFileInfo['audio']['bits_per_sample'] = 8;
|
||||
}
|
||||
|
||||
if ($ThisFileInfo['lpac']['flags']['fast_compress']) {
|
||||
// fast
|
||||
$ThisFileInfo['audio']['encoder_options'] = '-1';
|
||||
} else {
|
||||
switch ($ThisFileInfo['lpac']['max_prediction_order']) {
|
||||
case 20: // simple
|
||||
$ThisFileInfo['audio']['encoder_options'] = '-2';
|
||||
break;
|
||||
case 30: // medium
|
||||
$ThisFileInfo['audio']['encoder_options'] = '-3';
|
||||
break;
|
||||
case 40: // high
|
||||
$ThisFileInfo['audio']['encoder_options'] = '-4';
|
||||
break;
|
||||
case 60: // extrahigh
|
||||
$ThisFileInfo['audio']['encoder_options'] = '-5';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['lpac']['total_samples'] / $ThisFileInfo['audio']['sample_rate'];
|
||||
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,101 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.mod.php //
|
||||
// module for analyzing MOD Audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_mod
|
||||
{
|
||||
|
||||
// new combined constructor
|
||||
function getid3_mod(&$fd, &$ThisFileInfo, $option) {
|
||||
|
||||
if ($option === 'mod') {
|
||||
$this->getMODheaderFilepointer($fd, $ThisFileInfo);
|
||||
}
|
||||
elseif ($option === 'xm') {
|
||||
$this->getXMheaderFilepointer($fd, $ThisFileInfo);
|
||||
}
|
||||
elseif ($option === 'it') {
|
||||
$this->getITheaderFilepointer($fd, $ThisFileInfo);
|
||||
}
|
||||
elseif ($option === 's3m') {
|
||||
$this->getS3MheaderFilepointer($fd, $ThisFileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getMODheaderFilepointer(&$fd, &$ThisFileInfo) {
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'] + 1080);
|
||||
$FormatID = fread($fd, 4);
|
||||
if (!preg_match('#^(M.K.|[5-9]CHN|[1-3][0-9]CH)$#', $FormatID)) {
|
||||
$ThisFileInfo['error'][] = 'This is not a known type of MOD file';
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'mod';
|
||||
|
||||
$ThisFileInfo['error'][] = 'MOD parsing not enabled in this version of getID3()';
|
||||
return false;
|
||||
}
|
||||
|
||||
function getXMheaderFilepointer(&$fd, &$ThisFileInfo) {
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset']);
|
||||
$FormatID = fread($fd, 15);
|
||||
if (!preg_match('#^Extended Module$#', $FormatID)) {
|
||||
$ThisFileInfo['error'][] = 'This is not a known type of XM-MOD file';
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'xm';
|
||||
|
||||
$ThisFileInfo['error'][] = 'XM-MOD parsing not enabled in this version of getID3()';
|
||||
return false;
|
||||
}
|
||||
|
||||
function getS3MheaderFilepointer(&$fd, &$ThisFileInfo) {
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'] + 44);
|
||||
$FormatID = fread($fd, 4);
|
||||
if (!preg_match('#^SCRM$#', $FormatID)) {
|
||||
$ThisFileInfo['error'][] = 'This is not a ScreamTracker MOD file';
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['fileformat'] = 's3m';
|
||||
|
||||
$ThisFileInfo['error'][] = 'ScreamTracker parsing not enabled in this version of getID3()';
|
||||
return false;
|
||||
}
|
||||
|
||||
function getITheaderFilepointer(&$fd, &$ThisFileInfo) {
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset']);
|
||||
$FormatID = fread($fd, 4);
|
||||
if (!preg_match('#^IMPM$#', $FormatID)) {
|
||||
$ThisFileInfo['error'][] = 'This is not an ImpulseTracker MOD file';
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'it';
|
||||
|
||||
$ThisFileInfo['error'][] = 'ImpulseTracker parsing not enabled in this version of getID3()';
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,574 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.ogg.php //
|
||||
// module for analyzing Ogg Vorbis, OggFLAC and Speex files //
|
||||
// dependencies: module.audio.flac.php //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.flac.php', __FILE__, true);
|
||||
|
||||
class getid3_ogg
|
||||
{
|
||||
|
||||
function getid3_ogg(&$fd, &$ThisFileInfo) {
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'ogg';
|
||||
|
||||
// Warn about illegal tags - only vorbiscomments are allowed
|
||||
if (isset($ThisFileInfo['id3v2'])) {
|
||||
$ThisFileInfo['warning'][] = 'Illegal ID3v2 tag present.';
|
||||
}
|
||||
if (isset($ThisFileInfo['id3v1'])) {
|
||||
$ThisFileInfo['warning'][] = 'Illegal ID3v1 tag present.';
|
||||
}
|
||||
if (isset($ThisFileInfo['ape'])) {
|
||||
$ThisFileInfo['warning'][] = 'Illegal APE tag present.';
|
||||
}
|
||||
|
||||
|
||||
// Page 1 - Stream Header
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
|
||||
$oggpageinfo = getid3_ogg::ParseOggPageHeader($fd);
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
|
||||
|
||||
if (ftell($fd) >= GETID3_FREAD_BUFFER_SIZE) {
|
||||
$ThisFileInfo['error'][] = 'Could not find start of Ogg page in the first '.GETID3_FREAD_BUFFER_SIZE.' bytes (this might not be an Ogg-Vorbis file?)';
|
||||
unset($ThisFileInfo['fileformat']);
|
||||
unset($ThisFileInfo['ogg']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$filedata = fread($fd, $oggpageinfo['page_length']);
|
||||
$filedataoffset = 0;
|
||||
|
||||
if (substr($filedata, 0, 4) == 'fLaC') {
|
||||
|
||||
$ThisFileInfo['audio']['dataformat'] = 'flac';
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
|
||||
$ThisFileInfo['audio']['lossless'] = true;
|
||||
|
||||
} elseif (substr($filedata, 1, 6) == 'vorbis') {
|
||||
|
||||
$this->ParseVorbisPageHeader($filedata, $filedataoffset, $ThisFileInfo, $oggpageinfo);
|
||||
|
||||
} elseif (substr($filedata, 0, 8) == 'Speex ') {
|
||||
|
||||
// http://www.speex.org/manual/node10.html
|
||||
|
||||
$ThisFileInfo['audio']['dataformat'] = 'speex';
|
||||
$ThisFileInfo['mime_type'] = 'audio/speex';
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'abr';
|
||||
$ThisFileInfo['audio']['lossless'] = false;
|
||||
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_string'] = substr($filedata, $filedataoffset, 8); // hard-coded to 'Speex '
|
||||
$filedataoffset += 8;
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version'] = substr($filedata, $filedataoffset, 20);
|
||||
$filedataoffset += 20;
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version_id'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['header_size'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode_bitstream_version'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['bitrate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['framesize'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['frames_per_packet'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['extra_headers'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved1'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved2'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
|
||||
$ThisFileInfo['speex']['speex_version'] = trim($ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version']);
|
||||
$ThisFileInfo['speex']['sample_rate'] = $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate'];
|
||||
$ThisFileInfo['speex']['channels'] = $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels'];
|
||||
$ThisFileInfo['speex']['vbr'] = (bool) $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr'];
|
||||
$ThisFileInfo['speex']['band_type'] = getid3_ogg::SpeexBandModeLookup($ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode']);
|
||||
|
||||
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['speex']['sample_rate'];
|
||||
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['speex']['channels'];
|
||||
if ($ThisFileInfo['speex']['vbr']) {
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$ThisFileInfo['error'][] = 'Expecting either "Speex " or "vorbis" identifier strings, found neither';
|
||||
unset($ThisFileInfo['ogg']);
|
||||
unset($ThisFileInfo['mime_type']);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Page 2 - Comment Header
|
||||
|
||||
$oggpageinfo = getid3_ogg::ParseOggPageHeader($fd);
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
|
||||
|
||||
switch ($ThisFileInfo['audio']['dataformat']) {
|
||||
|
||||
case 'vorbis':
|
||||
$filedata = fread($fd, $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, 0, 1));
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, 1, 6); // hard-coded to 'vorbis'
|
||||
|
||||
getid3_ogg::ParseVorbisCommentsFilepointer($fd, $ThisFileInfo);
|
||||
break;
|
||||
|
||||
case 'flac':
|
||||
if (!getid3_flac::FLACparseMETAdata($fd, $ThisFileInfo)) {
|
||||
$ThisFileInfo['error'][] = 'Failed to parse FLAC headers';
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'speex':
|
||||
fseek($fd, $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length'], SEEK_CUR);
|
||||
getid3_ogg::ParseVorbisCommentsFilepointer($fd, $ThisFileInfo);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Last Page - Number of Samples
|
||||
|
||||
if (!getid3_lib::intValueSupported($ThisFileInfo['avdataend'])) {
|
||||
|
||||
$ThisFileInfo['warning'][] = 'Unable to parse Ogg end chunk file (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)';
|
||||
|
||||
} else {
|
||||
|
||||
fseek($fd, max($ThisFileInfo['avdataend'] - GETID3_FREAD_BUFFER_SIZE, 0), SEEK_SET);
|
||||
$LastChunkOfOgg = strrev(fread($fd, GETID3_FREAD_BUFFER_SIZE));
|
||||
if ($LastOggSpostion = strpos($LastChunkOfOgg, 'SggO')) {
|
||||
fseek($fd, $ThisFileInfo['avdataend'] - ($LastOggSpostion + strlen('SggO')), SEEK_SET);
|
||||
$ThisFileInfo['avdataend'] = ftell($fd);
|
||||
$ThisFileInfo['ogg']['pageheader']['eos'] = getid3_ogg::ParseOggPageHeader($fd);
|
||||
$ThisFileInfo['ogg']['samples'] = $ThisFileInfo['ogg']['pageheader']['eos']['pcm_abs_position'];
|
||||
if ($ThisFileInfo['ogg']['samples'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'Corrupt Ogg file: eos.number of samples == zero';
|
||||
return false;
|
||||
}
|
||||
$ThisFileInfo['ogg']['bitrate_average'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / ($ThisFileInfo['ogg']['samples'] / $ThisFileInfo['audio']['sample_rate']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!empty($ThisFileInfo['ogg']['bitrate_average'])) {
|
||||
$ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['ogg']['bitrate_average'];
|
||||
} elseif (!empty($ThisFileInfo['ogg']['bitrate_nominal'])) {
|
||||
$ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['ogg']['bitrate_nominal'];
|
||||
} elseif (!empty($ThisFileInfo['ogg']['bitrate_min']) && !empty($ThisFileInfo['ogg']['bitrate_max'])) {
|
||||
$ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['ogg']['bitrate_min'] + $ThisFileInfo['ogg']['bitrate_max']) / 2;
|
||||
}
|
||||
if (isset($ThisFileInfo['audio']['bitrate']) && !isset($ThisFileInfo['playtime_seconds'])) {
|
||||
if ($ThisFileInfo['audio']['bitrate'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'Corrupt Ogg file: bitrate_audio == zero';
|
||||
return false;
|
||||
}
|
||||
$ThisFileInfo['playtime_seconds'] = (float) ((($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['audio']['bitrate']);
|
||||
}
|
||||
|
||||
if (isset($ThisFileInfo['ogg']['vendor'])) {
|
||||
$ThisFileInfo['audio']['encoder'] = preg_replace('/^Encoded with /', '', $ThisFileInfo['ogg']['vendor']);
|
||||
|
||||
// Vorbis only
|
||||
if ($ThisFileInfo['audio']['dataformat'] == 'vorbis') {
|
||||
|
||||
// Vorbis 1.0 starts with Xiph.Org
|
||||
if (preg_match('/^Xiph.Org/', $ThisFileInfo['audio']['encoder'])) {
|
||||
|
||||
if ($ThisFileInfo['audio']['bitrate_mode'] == 'abr') {
|
||||
|
||||
// Set -b 128 on abr files
|
||||
$ThisFileInfo['audio']['encoder_options'] = '-b '.round($ThisFileInfo['ogg']['bitrate_nominal'] / 1000);
|
||||
|
||||
} elseif (($ThisFileInfo['audio']['bitrate_mode'] == 'vbr') && ($ThisFileInfo['audio']['channels'] == 2) && ($ThisFileInfo['audio']['sample_rate'] >= 44100) && ($ThisFileInfo['audio']['sample_rate'] <= 48000)) {
|
||||
// Set -q N on vbr files
|
||||
$ThisFileInfo['audio']['encoder_options'] = '-q '.$this->get_quality_from_nominal_bitrate($ThisFileInfo['ogg']['bitrate_nominal']);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($ThisFileInfo['audio']['encoder_options']) && !empty($ThisFileInfo['ogg']['bitrate_nominal'])) {
|
||||
$ThisFileInfo['audio']['encoder_options'] = 'Nominal bitrate: '.intval(round($ThisFileInfo['ogg']['bitrate_nominal'] / 1000)).'kbps';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static function ParseVorbisPageHeader(&$filedata, &$filedataoffset, &$ThisFileInfo, &$oggpageinfo) {
|
||||
$ThisFileInfo['audio']['dataformat'] = 'vorbis';
|
||||
$ThisFileInfo['audio']['lossless'] = false;
|
||||
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
|
||||
$filedataoffset += 1;
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, $filedataoffset, 6); // hard-coded to 'vorbis'
|
||||
$filedataoffset += 6;
|
||||
$ThisFileInfo['ogg']['bitstreamversion'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$ThisFileInfo['ogg']['numberofchannels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
|
||||
$filedataoffset += 1;
|
||||
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['ogg']['numberofchannels'];
|
||||
$ThisFileInfo['ogg']['samplerate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
if ($ThisFileInfo['ogg']['samplerate'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'Corrupt Ogg file: sample rate == zero';
|
||||
return false;
|
||||
}
|
||||
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['ogg']['samplerate'];
|
||||
$ThisFileInfo['ogg']['samples'] = 0; // filled in later
|
||||
$ThisFileInfo['ogg']['bitrate_average'] = 0; // filled in later
|
||||
$ThisFileInfo['ogg']['bitrate_max'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$ThisFileInfo['ogg']['bitrate_nominal'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$ThisFileInfo['ogg']['bitrate_min'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$ThisFileInfo['ogg']['blocksize_small'] = pow(2, getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0x0F);
|
||||
$ThisFileInfo['ogg']['blocksize_large'] = pow(2, (getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0xF0) >> 4);
|
||||
$ThisFileInfo['ogg']['stop_bit'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); // must be 1, marks end of packet
|
||||
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr'; // overridden if actually abr
|
||||
if ($ThisFileInfo['ogg']['bitrate_max'] == 0xFFFFFFFF) {
|
||||
unset($ThisFileInfo['ogg']['bitrate_max']);
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'abr';
|
||||
}
|
||||
if ($ThisFileInfo['ogg']['bitrate_nominal'] == 0xFFFFFFFF) {
|
||||
unset($ThisFileInfo['ogg']['bitrate_nominal']);
|
||||
}
|
||||
if ($ThisFileInfo['ogg']['bitrate_min'] == 0xFFFFFFFF) {
|
||||
unset($ThisFileInfo['ogg']['bitrate_min']);
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'abr';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static function ParseOggPageHeader(&$fd) {
|
||||
// http://xiph.org/ogg/vorbis/doc/framing.html
|
||||
$oggheader['page_start_offset'] = ftell($fd); // where we started from in the file
|
||||
|
||||
$filedata = fread($fd, GETID3_FREAD_BUFFER_SIZE);
|
||||
$filedataoffset = 0;
|
||||
while ((substr($filedata, $filedataoffset++, 4) != 'OggS')) {
|
||||
if ((ftell($fd) - $oggheader['page_start_offset']) >= GETID3_FREAD_BUFFER_SIZE) {
|
||||
// should be found before here
|
||||
return false;
|
||||
}
|
||||
if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) {
|
||||
if (feof($fd) || (($filedata .= fread($fd, GETID3_FREAD_BUFFER_SIZE)) === false)) {
|
||||
// get some more data, unless eof, in which case fail
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
$filedataoffset += strlen('OggS') - 1; // page, delimited by 'OggS'
|
||||
|
||||
$oggheader['stream_structver'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
|
||||
$filedataoffset += 1;
|
||||
$oggheader['flags_raw'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
|
||||
$filedataoffset += 1;
|
||||
$oggheader['flags']['fresh'] = (bool) ($oggheader['flags_raw'] & 0x01); // fresh packet
|
||||
$oggheader['flags']['bos'] = (bool) ($oggheader['flags_raw'] & 0x02); // first page of logical bitstream (bos)
|
||||
$oggheader['flags']['eos'] = (bool) ($oggheader['flags_raw'] & 0x04); // last page of logical bitstream (eos)
|
||||
|
||||
$oggheader['pcm_abs_position'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
|
||||
$filedataoffset += 8;
|
||||
$oggheader['stream_serialno'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$oggheader['page_seqno'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$oggheader['page_checksum'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$oggheader['page_segments'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
|
||||
$filedataoffset += 1;
|
||||
$oggheader['page_length'] = 0;
|
||||
for ($i = 0; $i < $oggheader['page_segments']; $i++) {
|
||||
$oggheader['segment_table'][$i] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
|
||||
$filedataoffset += 1;
|
||||
$oggheader['page_length'] += $oggheader['segment_table'][$i];
|
||||
}
|
||||
$oggheader['header_end_offset'] = $oggheader['page_start_offset'] + $filedataoffset;
|
||||
$oggheader['page_end_offset'] = $oggheader['header_end_offset'] + $oggheader['page_length'];
|
||||
fseek($fd, $oggheader['header_end_offset'], SEEK_SET);
|
||||
|
||||
return $oggheader;
|
||||
}
|
||||
|
||||
|
||||
static function ParseVorbisCommentsFilepointer(&$fd, &$ThisFileInfo) {
|
||||
|
||||
$OriginalOffset = ftell($fd);
|
||||
$CommentStartOffset = $OriginalOffset;
|
||||
$commentdataoffset = 0;
|
||||
$VorbisCommentPage = 1;
|
||||
|
||||
switch ($ThisFileInfo['audio']['dataformat']) {
|
||||
case 'vorbis':
|
||||
$CommentStartOffset = $ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset']; // Second Ogg page, after header block
|
||||
fseek($fd, $CommentStartOffset, SEEK_SET);
|
||||
$commentdataoffset = 27 + $ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage]['page_segments'];
|
||||
$commentdata = fread($fd, getid3_ogg::OggPageSegmentLength($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset);
|
||||
|
||||
$commentdataoffset += (strlen('vorbis') + 1);
|
||||
break;
|
||||
|
||||
case 'flac':
|
||||
fseek($fd, $ThisFileInfo['flac']['VORBIS_COMMENT']['raw']['offset'] + 4, SEEK_SET);
|
||||
$commentdata = fread($fd, $ThisFileInfo['flac']['VORBIS_COMMENT']['raw']['block_length']);
|
||||
break;
|
||||
|
||||
case 'speex':
|
||||
$CommentStartOffset = $ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset']; // Second Ogg page, after header block
|
||||
fseek($fd, $CommentStartOffset, SEEK_SET);
|
||||
$commentdataoffset = 27 + $ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage]['page_segments'];
|
||||
$commentdata = fread($fd, getid3_ogg::OggPageSegmentLength($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
$VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
|
||||
$commentdataoffset += 4;
|
||||
|
||||
$ThisFileInfo['ogg']['vendor'] = substr($commentdata, $commentdataoffset, $VendorSize);
|
||||
$commentdataoffset += $VendorSize;
|
||||
|
||||
$CommentsCount = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
|
||||
$commentdataoffset += 4;
|
||||
$ThisFileInfo['avdataoffset'] = $CommentStartOffset + $commentdataoffset;
|
||||
|
||||
$basicfields = array('TITLE', 'ARTIST', 'ALBUM', 'TRACKNUMBER', 'GENRE', 'DATE', 'DESCRIPTION', 'COMMENT');
|
||||
$ThisFileInfo_ogg_comments_raw = &$ThisFileInfo['ogg']['comments_raw'];
|
||||
for ($i = 0; $i < $CommentsCount; $i++) {
|
||||
|
||||
$ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] = $CommentStartOffset + $commentdataoffset;
|
||||
|
||||
if (ftell($fd) < ($ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + 4)) {
|
||||
$VorbisCommentPage++;
|
||||
|
||||
$oggpageinfo = getid3_ogg::ParseOggPageHeader($fd);
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
|
||||
|
||||
// First, save what we haven't read yet
|
||||
$AsYetUnusedData = substr($commentdata, $commentdataoffset);
|
||||
|
||||
// Then take that data off the end
|
||||
$commentdata = substr($commentdata, 0, $commentdataoffset);
|
||||
|
||||
// Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
|
||||
$commentdata .= str_repeat("\x00", 27 + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
|
||||
$commentdataoffset += (27 + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
|
||||
|
||||
// Finally, stick the unused data back on the end
|
||||
$commentdata .= $AsYetUnusedData;
|
||||
|
||||
//$commentdata .= fread($fd, $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
|
||||
$commentdata .= fread($fd, getid3_ogg::OggPageSegmentLength($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage], 1));
|
||||
|
||||
}
|
||||
$ThisFileInfo_ogg_comments_raw[$i]['size'] = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
|
||||
|
||||
// replace avdataoffset with position just after the last vorbiscomment
|
||||
$ThisFileInfo['avdataoffset'] = $ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + $ThisFileInfo_ogg_comments_raw[$i]['size'] + 4;
|
||||
|
||||
$commentdataoffset += 4;
|
||||
while ((strlen($commentdata) - $commentdataoffset) < $ThisFileInfo_ogg_comments_raw[$i]['size']) {
|
||||
if (($ThisFileInfo_ogg_comments_raw[$i]['size'] > $ThisFileInfo['avdataend']) || ($ThisFileInfo_ogg_comments_raw[$i]['size'] < 0)) {
|
||||
$ThisFileInfo['warning'][] = 'Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($ThisFileInfo_ogg_comments_raw[$i]['size']).' bytes) - aborting reading comments';
|
||||
break 2;
|
||||
}
|
||||
|
||||
$VorbisCommentPage++;
|
||||
|
||||
$oggpageinfo = getid3_ogg::ParseOggPageHeader($fd);
|
||||
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
|
||||
|
||||
// First, save what we haven't read yet
|
||||
$AsYetUnusedData = substr($commentdata, $commentdataoffset);
|
||||
|
||||
// Then take that data off the end
|
||||
$commentdata = substr($commentdata, 0, $commentdataoffset);
|
||||
|
||||
// Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
|
||||
$commentdata .= str_repeat("\x00", 27 + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
|
||||
$commentdataoffset += (27 + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
|
||||
|
||||
// Finally, stick the unused data back on the end
|
||||
$commentdata .= $AsYetUnusedData;
|
||||
|
||||
//$commentdata .= fread($fd, $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
|
||||
if (!isset($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage])) {
|
||||
$ThisFileInfo['warning'][] = 'undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.ftell($fd);
|
||||
break;
|
||||
}
|
||||
$readlength = getid3_ogg::OggPageSegmentLength($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage], 1);
|
||||
if ($readlength <= 0) {
|
||||
$ThisFileInfo['warning'][] = 'invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.ftell($fd);
|
||||
break;
|
||||
}
|
||||
$commentdata .= fread($fd, $readlength);
|
||||
|
||||
//$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];
|
||||
}
|
||||
$commentstring = substr($commentdata, $commentdataoffset, $ThisFileInfo_ogg_comments_raw[$i]['size']);
|
||||
$commentdataoffset += $ThisFileInfo_ogg_comments_raw[$i]['size'];
|
||||
|
||||
if (!$commentstring) {
|
||||
|
||||
// no comment?
|
||||
$ThisFileInfo['warning'][] = 'Blank Ogg comment ['.$i.']';
|
||||
|
||||
} elseif (strstr($commentstring, '=')) {
|
||||
|
||||
$commentexploded = explode('=', $commentstring, 2);
|
||||
$ThisFileInfo_ogg_comments_raw[$i]['key'] = strtoupper($commentexploded[0]);
|
||||
$ThisFileInfo_ogg_comments_raw[$i]['value'] = (isset($commentexploded[1]) ? $commentexploded[1] : '');
|
||||
$ThisFileInfo_ogg_comments_raw[$i]['data'] = base64_decode($ThisFileInfo_ogg_comments_raw[$i]['value']);
|
||||
|
||||
if (preg_match('#^(BM|GIF|\xFF\xD8\xFF|\x89\x50\x4E\x47\x0D\x0A\x1A\x0A|II\x2A\x00|MM\x00\x2A)#s', $ThisFileInfo_ogg_comments_raw[$i]['data'])) {
|
||||
$imageinfo = array();
|
||||
$imagechunkcheck = getid3_lib::GetDataImageSize($ThisFileInfo_ogg_comments_raw[$i]['data'], $imageinfo);
|
||||
unset($imageinfo);
|
||||
if (!empty($imagechunkcheck)) {
|
||||
$ThisFileInfo_ogg_comments_raw[$i]['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
|
||||
if ($ThisFileInfo_ogg_comments_raw[$i]['image_mime'] && ($ThisFileInfo_ogg_comments_raw[$i]['image_mime'] != 'application/octet-stream')) {
|
||||
unset($ThisFileInfo_ogg_comments_raw[$i]['value']);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($ThisFileInfo_ogg_comments_raw[$i]['value'])) {
|
||||
unset($ThisFileInfo_ogg_comments_raw[$i]['data']);
|
||||
$ThisFileInfo['ogg']['comments'][strtolower($ThisFileInfo_ogg_comments_raw[$i]['key'])][] = $ThisFileInfo_ogg_comments_raw[$i]['value'];
|
||||
} else {
|
||||
$ThisFileInfo['ogg']['comments']['picture'][] = array('data'=>$ThisFileInfo_ogg_comments_raw[$i]['data'], 'image_mime'=>$ThisFileInfo_ogg_comments_raw[$i]['image_mime']);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$ThisFileInfo['warning'][] = '[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Replay Gain Adjustment
|
||||
// http://privatewww.essex.ac.uk/~djmrob/replaygain/
|
||||
if (isset($ThisFileInfo['ogg']['comments']) && is_array($ThisFileInfo['ogg']['comments'])) {
|
||||
foreach ($ThisFileInfo['ogg']['comments'] as $index => $commentvalue) {
|
||||
switch ($index) {
|
||||
case 'rg_audiophile':
|
||||
case 'replaygain_album_gain':
|
||||
$ThisFileInfo['replay_gain']['album']['adjustment'] = (double) $commentvalue[0];
|
||||
unset($ThisFileInfo['ogg']['comments'][$index]);
|
||||
break;
|
||||
|
||||
case 'rg_radio':
|
||||
case 'replaygain_track_gain':
|
||||
$ThisFileInfo['replay_gain']['track']['adjustment'] = (double) $commentvalue[0];
|
||||
unset($ThisFileInfo['ogg']['comments'][$index]);
|
||||
break;
|
||||
|
||||
case 'replaygain_album_peak':
|
||||
$ThisFileInfo['replay_gain']['album']['peak'] = (double) $commentvalue[0];
|
||||
unset($ThisFileInfo['ogg']['comments'][$index]);
|
||||
break;
|
||||
|
||||
case 'rg_peak':
|
||||
case 'replaygain_track_peak':
|
||||
$ThisFileInfo['replay_gain']['track']['peak'] = (double) $commentvalue[0];
|
||||
unset($ThisFileInfo['ogg']['comments'][$index]);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fseek($fd, $OriginalOffset, SEEK_SET);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static function SpeexBandModeLookup($mode) {
|
||||
static $SpeexBandModeLookup = array();
|
||||
if (empty($SpeexBandModeLookup)) {
|
||||
$SpeexBandModeLookup[0] = 'narrow';
|
||||
$SpeexBandModeLookup[1] = 'wide';
|
||||
$SpeexBandModeLookup[2] = 'ultra-wide';
|
||||
}
|
||||
return (isset($SpeexBandModeLookup[$mode]) ? $SpeexBandModeLookup[$mode] : null);
|
||||
}
|
||||
|
||||
|
||||
static function OggPageSegmentLength($OggInfoArray, $SegmentNumber=1) {
|
||||
for ($i = 0; $i < $SegmentNumber; $i++) {
|
||||
$segmentlength = 0;
|
||||
foreach ($OggInfoArray['segment_table'] as $key => $value) {
|
||||
$segmentlength += $value;
|
||||
if ($value < 255) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $segmentlength;
|
||||
}
|
||||
|
||||
|
||||
static function get_quality_from_nominal_bitrate($nominal_bitrate) {
|
||||
|
||||
// decrease precision
|
||||
$nominal_bitrate = $nominal_bitrate / 1000;
|
||||
|
||||
if ($nominal_bitrate < 128) {
|
||||
// q-1 to q4
|
||||
$qval = ($nominal_bitrate - 64) / 16;
|
||||
} elseif ($nominal_bitrate < 256) {
|
||||
// q4 to q8
|
||||
$qval = $nominal_bitrate / 32;
|
||||
} elseif ($nominal_bitrate < 320) {
|
||||
// q8 to q9
|
||||
$qval = ($nominal_bitrate + 256) / 64;
|
||||
} else {
|
||||
// q9 to q10
|
||||
$qval = ($nominal_bitrate + 1300) / 180;
|
||||
}
|
||||
//return $qval; // 5.031324
|
||||
//return intval($qval); // 5
|
||||
return round($qval, 1); // 5 or 4.9
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,92 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.shorten.php //
|
||||
// module for analyzing Shorten Audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_rkau
|
||||
{
|
||||
|
||||
function getid3_rkau(&$fd, &$ThisFileInfo) {
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$RKAUHeader = fread($fd, 20);
|
||||
if (substr($RKAUHeader, 0, 3) != 'RKA') {
|
||||
$ThisFileInfo['error'][] = 'Expecting "RKA" at offset '.$ThisFileInfo['avdataoffset'].', found "'.substr($RKAUHeader, 0, 3).'"';
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'rkau';
|
||||
$ThisFileInfo['audio']['dataformat'] = 'rkau';
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
|
||||
|
||||
$ThisFileInfo['rkau']['raw']['version'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 3, 1));
|
||||
$ThisFileInfo['rkau']['version'] = '1.'.str_pad($ThisFileInfo['rkau']['raw']['version'] & 0x0F, 2, '0', STR_PAD_LEFT);
|
||||
if (($ThisFileInfo['rkau']['version'] > 1.07) || ($ThisFileInfo['rkau']['version'] < 1.06)) {
|
||||
$ThisFileInfo['error'][] = 'This version of getID3() can only parse RKAU files v1.06 and 1.07 (this file is v'.$ThisFileInfo['rkau']['version'].')';
|
||||
unset($ThisFileInfo['rkau']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['rkau']['source_bytes'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 4, 4));
|
||||
$ThisFileInfo['rkau']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 8, 4));
|
||||
$ThisFileInfo['rkau']['channels'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 12, 1));
|
||||
$ThisFileInfo['rkau']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 13, 1));
|
||||
|
||||
$ThisFileInfo['rkau']['raw']['quality'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 14, 1));
|
||||
$this->RKAUqualityLookup($ThisFileInfo['rkau']);
|
||||
|
||||
$ThisFileInfo['rkau']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 15, 1));
|
||||
$ThisFileInfo['rkau']['flags']['joint_stereo'] = (bool) (!($ThisFileInfo['rkau']['raw']['flags'] & 0x01));
|
||||
$ThisFileInfo['rkau']['flags']['streaming'] = (bool) ($ThisFileInfo['rkau']['raw']['flags'] & 0x02);
|
||||
$ThisFileInfo['rkau']['flags']['vrq_lossy_mode'] = (bool) ($ThisFileInfo['rkau']['raw']['flags'] & 0x04);
|
||||
|
||||
if ($ThisFileInfo['rkau']['flags']['streaming']) {
|
||||
$ThisFileInfo['avdataoffset'] += 20;
|
||||
$ThisFileInfo['rkau']['compressed_bytes'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 16, 4));
|
||||
} else {
|
||||
$ThisFileInfo['avdataoffset'] += 16;
|
||||
$ThisFileInfo['rkau']['compressed_bytes'] = $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'] - 1;
|
||||
}
|
||||
// Note: compressed_bytes does not always equal what appears to be the actual number of compressed bytes,
|
||||
// sometimes it's more, sometimes less. No idea why(?)
|
||||
|
||||
$ThisFileInfo['audio']['lossless'] = $ThisFileInfo['rkau']['lossless'];
|
||||
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['rkau']['channels'];
|
||||
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['rkau']['bits_per_sample'];
|
||||
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['rkau']['sample_rate'];
|
||||
|
||||
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['rkau']['source_bytes'] / ($ThisFileInfo['rkau']['sample_rate'] * $ThisFileInfo['rkau']['channels'] * ($ThisFileInfo['rkau']['bits_per_sample'] / 8));
|
||||
$ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['rkau']['compressed_bytes'] * 8) / $ThisFileInfo['playtime_seconds'];
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function RKAUqualityLookup(&$RKAUdata) {
|
||||
$level = ($RKAUdata['raw']['quality'] & 0xF0) >> 4;
|
||||
$quality = $RKAUdata['raw']['quality'] & 0x0F;
|
||||
|
||||
$RKAUdata['lossless'] = (($quality == 0) ? true : false);
|
||||
$RKAUdata['compression_level'] = $level + 1;
|
||||
if (!$RKAUdata['lossless']) {
|
||||
$RKAUdata['quality_setting'] = $quality;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,107 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.tta.php //
|
||||
// module for analyzing TTA Audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_tta
|
||||
{
|
||||
|
||||
function getid3_tta(&$fd, &$ThisFileInfo) {
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'tta';
|
||||
$ThisFileInfo['audio']['dataformat'] = 'tta';
|
||||
$ThisFileInfo['audio']['lossless'] = true;
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$ttaheader = fread($fd, 26);
|
||||
|
||||
$ThisFileInfo['tta']['magic'] = substr($ttaheader, 0, 3);
|
||||
if ($ThisFileInfo['tta']['magic'] != 'TTA') {
|
||||
$ThisFileInfo['error'][] = 'Expecting "TTA" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$ThisFileInfo['tta']['magic'].'"';
|
||||
unset($ThisFileInfo['fileformat']);
|
||||
unset($ThisFileInfo['audio']);
|
||||
unset($ThisFileInfo['tta']);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ($ttaheader{3}) {
|
||||
case "\x01": // TTA v1.x
|
||||
case "\x02": // TTA v1.x
|
||||
case "\x03": // TTA v1.x
|
||||
// "It was the demo-version of the TTA encoder. There is no released format with such header. TTA encoder v1 is not supported about a year."
|
||||
$ThisFileInfo['tta']['major_version'] = 1;
|
||||
$ThisFileInfo['avdataoffset'] += 16;
|
||||
|
||||
$ThisFileInfo['tta']['compression_level'] = ord($ttaheader{3});
|
||||
$ThisFileInfo['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2));
|
||||
$ThisFileInfo['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2));
|
||||
$ThisFileInfo['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 4));
|
||||
$ThisFileInfo['tta']['samples_per_channel'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 12, 4));
|
||||
|
||||
$ThisFileInfo['audio']['encoder_options'] = '-e'.$ThisFileInfo['tta']['compression_level'];
|
||||
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['tta']['samples_per_channel'] / $ThisFileInfo['tta']['sample_rate'];
|
||||
break;
|
||||
|
||||
case '2': // TTA v2.x
|
||||
// "I have hurried to release the TTA 2.0 encoder. Format documentation is removed from our site. This format still in development. Please wait the TTA2 format, encoder v4."
|
||||
$ThisFileInfo['tta']['major_version'] = 2;
|
||||
$ThisFileInfo['avdataoffset'] += 20;
|
||||
|
||||
$ThisFileInfo['tta']['compression_level'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2));
|
||||
$ThisFileInfo['tta']['audio_format'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2));
|
||||
$ThisFileInfo['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 2));
|
||||
$ThisFileInfo['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 10, 2));
|
||||
$ThisFileInfo['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 12, 4));
|
||||
$ThisFileInfo['tta']['data_length'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 16, 4));
|
||||
|
||||
$ThisFileInfo['audio']['encoder_options'] = '-e'.$ThisFileInfo['tta']['compression_level'];
|
||||
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['tta']['data_length'] / $ThisFileInfo['tta']['sample_rate'];
|
||||
break;
|
||||
|
||||
case '1': // TTA v3.x
|
||||
// "This is a first stable release of the TTA format. It will be supported by the encoders v3 or higher."
|
||||
$ThisFileInfo['tta']['major_version'] = 3;
|
||||
$ThisFileInfo['avdataoffset'] += 26;
|
||||
|
||||
$ThisFileInfo['tta']['audio_format'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2)); // getid3_riff::RIFFwFormatTagLookup()
|
||||
$ThisFileInfo['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2));
|
||||
$ThisFileInfo['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 2));
|
||||
$ThisFileInfo['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 10, 4));
|
||||
$ThisFileInfo['tta']['data_length'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 14, 4));
|
||||
$ThisFileInfo['tta']['crc32_footer'] = substr($ttaheader, 18, 4);
|
||||
$ThisFileInfo['tta']['seek_point'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 22, 4));
|
||||
|
||||
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['tta']['data_length'] / $ThisFileInfo['tta']['sample_rate'];
|
||||
break;
|
||||
|
||||
default:
|
||||
$ThisFileInfo['error'][] = 'This version of getID3() only knows how to handle TTA v1 and v2 - it may not work correctly with this file which appears to be TTA v'.$ttaheader{3};
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
$ThisFileInfo['audio']['encoder'] = 'TTA v'.$ThisFileInfo['tta']['major_version'];
|
||||
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['tta']['bits_per_sample'];
|
||||
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['tta']['sample_rate'];
|
||||
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['tta']['channels'];
|
||||
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,159 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.vqf.php //
|
||||
// module for analyzing VQF audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_vqf
|
||||
{
|
||||
function getid3_vqf(&$fd, &$ThisFileInfo) {
|
||||
// based loosely on code from TTwinVQ by Jurgen Faul <jfaulØgmx*de>
|
||||
// http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'vqf';
|
||||
$ThisFileInfo['audio']['dataformat'] = 'vqf';
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
|
||||
$ThisFileInfo['audio']['lossless'] = false;
|
||||
|
||||
// shortcut
|
||||
$ThisFileInfo['vqf']['raw'] = array();
|
||||
$thisfile_vqf = &$ThisFileInfo['vqf'];
|
||||
$thisfile_vqf_raw = &$thisfile_vqf['raw'];
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$VQFheaderData = fread($fd, 16);
|
||||
|
||||
$offset = 0;
|
||||
$thisfile_vqf_raw['header_tag'] = substr($VQFheaderData, $offset, 4);
|
||||
if ($thisfile_vqf_raw['header_tag'] != 'TWIN') {
|
||||
$ThisFileInfo['error'][] = 'Expecting "TWIN" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$thisfile_vqf_raw['header_tag'].'"';
|
||||
unset($ThisFileInfo['vqf']);
|
||||
unset($ThisFileInfo['fileformat']);
|
||||
return false;
|
||||
}
|
||||
$offset += 4;
|
||||
$thisfile_vqf_raw['version'] = substr($VQFheaderData, $offset, 8);
|
||||
$offset += 8;
|
||||
$thisfile_vqf_raw['size'] = getid3_lib::BigEndian2Int(substr($VQFheaderData, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
while (ftell($fd) < $ThisFileInfo['avdataend']) {
|
||||
|
||||
$ChunkBaseOffset = ftell($fd);
|
||||
$chunkoffset = 0;
|
||||
$ChunkData = fread($fd, 8);
|
||||
$ChunkName = substr($ChunkData, $chunkoffset, 4);
|
||||
if ($ChunkName == 'DATA') {
|
||||
$ThisFileInfo['avdataoffset'] = $ChunkBaseOffset;
|
||||
break;
|
||||
}
|
||||
$chunkoffset += 4;
|
||||
$ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
|
||||
$chunkoffset += 4;
|
||||
if ($ChunkSize > ($ThisFileInfo['avdataend'] - ftell($fd))) {
|
||||
$ThisFileInfo['error'][] = 'Invalid chunk size ('.$ChunkSize.') for chunk "'.$ChunkName.'" at offset '.$ChunkBaseOffset;
|
||||
break;
|
||||
}
|
||||
if ($ChunkSize > 0) {
|
||||
$ChunkData .= fread($fd, $ChunkSize);
|
||||
}
|
||||
|
||||
switch ($ChunkName) {
|
||||
case 'COMM':
|
||||
// shortcut
|
||||
$thisfile_vqf['COMM'] = array();
|
||||
$thisfile_vqf_COMM = &$thisfile_vqf['COMM'];
|
||||
|
||||
$thisfile_vqf_COMM['channel_mode'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
|
||||
$chunkoffset += 4;
|
||||
$thisfile_vqf_COMM['bitrate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
|
||||
$chunkoffset += 4;
|
||||
$thisfile_vqf_COMM['sample_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
|
||||
$chunkoffset += 4;
|
||||
$thisfile_vqf_COMM['security_level'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
|
||||
$chunkoffset += 4;
|
||||
|
||||
$ThisFileInfo['audio']['channels'] = $thisfile_vqf_COMM['channel_mode'] + 1;
|
||||
$ThisFileInfo['audio']['sample_rate'] = $this->VQFchannelFrequencyLookup($thisfile_vqf_COMM['sample_rate']);
|
||||
$ThisFileInfo['audio']['bitrate'] = $thisfile_vqf_COMM['bitrate'] * 1000;
|
||||
$ThisFileInfo['audio']['encoder_options'] = 'CBR' . ceil($ThisFileInfo['audio']['bitrate']/1000);
|
||||
|
||||
if ($ThisFileInfo['audio']['bitrate'] == 0) {
|
||||
$ThisFileInfo['error'][] = 'Corrupt VQF file: bitrate_audio == zero';
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NAME':
|
||||
case 'AUTH':
|
||||
case '(c) ':
|
||||
case 'FILE':
|
||||
case 'COMT':
|
||||
case 'ALBM':
|
||||
$thisfile_vqf['comments'][$this->VQFcommentNiceNameLookup($ChunkName)][] = trim(substr($ChunkData, 8));
|
||||
break;
|
||||
|
||||
case 'DSIZ':
|
||||
$thisfile_vqf['DSIZ'] = getid3_lib::BigEndian2Int(substr($ChunkData, 8, 4));
|
||||
break;
|
||||
|
||||
default:
|
||||
$ThisFileInfo['warning'][] = 'Unhandled chunk type "'.$ChunkName.'" at offset '.$ChunkBaseOffset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$ThisFileInfo['playtime_seconds'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['audio']['bitrate'];
|
||||
|
||||
if (isset($thisfile_vqf['DSIZ']) && (($thisfile_vqf['DSIZ'] != ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'] - strlen('DATA'))))) {
|
||||
switch ($thisfile_vqf['DSIZ']) {
|
||||
case 0:
|
||||
case 1:
|
||||
$ThisFileInfo['warning'][] = 'Invalid DSIZ value "'.$thisfile_vqf['DSIZ'].'". This is known to happen with VQF files encoded by Ahead Nero, and seems to be its way of saying this is TwinVQF v'.($thisfile_vqf['DSIZ'] + 1).'.0';
|
||||
$ThisFileInfo['audio']['encoder'] = 'Ahead Nero';
|
||||
break;
|
||||
|
||||
default:
|
||||
$ThisFileInfo['warning'][] = 'Probable corrupted file - should be '.$thisfile_vqf['DSIZ'].' bytes, actually '.($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'] - strlen('DATA'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function VQFchannelFrequencyLookup($frequencyid) {
|
||||
static $VQFchannelFrequencyLookup = array(
|
||||
11 => 11025,
|
||||
22 => 22050,
|
||||
44 => 44100
|
||||
);
|
||||
return (isset($VQFchannelFrequencyLookup[$frequencyid]) ? $VQFchannelFrequencyLookup[$frequencyid] : $frequencyid * 1000);
|
||||
}
|
||||
|
||||
function VQFcommentNiceNameLookup($shortname) {
|
||||
static $VQFcommentNiceNameLookup = array(
|
||||
'NAME' => 'title',
|
||||
'AUTH' => 'artist',
|
||||
'(c) ' => 'copyright',
|
||||
'FILE' => 'filename',
|
||||
'COMT' => 'comment',
|
||||
'ALBM' => 'album'
|
||||
);
|
||||
return (isset($VQFcommentNiceNameLookup[$shortname]) ? $VQFcommentNiceNameLookup[$shortname] : $shortname);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,391 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.wavpack.php //
|
||||
// module for analyzing WavPack v4.0+ Audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_wavpack
|
||||
{
|
||||
|
||||
function getid3_wavpack(&$fd, &$ThisFileInfo) {
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
|
||||
while (true) {
|
||||
|
||||
$wavpackheader = fread($fd, 32);
|
||||
|
||||
if (ftell($fd) >= $ThisFileInfo['avdataend']) {
|
||||
break;
|
||||
} elseif (feof($fd)) {
|
||||
break;
|
||||
} elseif (
|
||||
isset($ThisFileInfo['wavpack']['blockheader']['total_samples']) &&
|
||||
isset($ThisFileInfo['wavpack']['blockheader']['block_samples']) &&
|
||||
($ThisFileInfo['wavpack']['blockheader']['total_samples'] > 0) &&
|
||||
($ThisFileInfo['wavpack']['blockheader']['block_samples'] > 0) &&
|
||||
(!isset($ThisFileInfo['wavpack']['riff_trailer_size']) || ($ThisFileInfo['wavpack']['riff_trailer_size'] <= 0)) &&
|
||||
((isset($ThisFileInfo['wavpack']['config_flags']['md5_checksum']) && ($ThisFileInfo['wavpack']['config_flags']['md5_checksum'] === false)) || !empty($ThisFileInfo['md5_data_source']))) {
|
||||
break;
|
||||
}
|
||||
|
||||
$blockheader_offset = ftell($fd) - 32;
|
||||
$blockheader_magic = substr($wavpackheader, 0, 4);
|
||||
$blockheader_size = getid3_lib::LittleEndian2Int(substr($wavpackheader, 4, 4));
|
||||
|
||||
if ($blockheader_magic != 'wvpk') {
|
||||
$ThisFileInfo['error'][] = 'Expecting "wvpk" at offset '.$blockheader_offset.', found "'.$blockheader_magic.'"';
|
||||
switch (isset($ThisFileInfo['audio']['dataformat']) ? $ThisFileInfo['audio']['dataformat'] : '') {
|
||||
case 'wavpack':
|
||||
case 'wvc':
|
||||
break;
|
||||
default:
|
||||
unset($ThisFileInfo['fileformat']);
|
||||
unset($ThisFileInfo['audio']);
|
||||
unset($ThisFileInfo['wavpack']);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (empty($ThisFileInfo['wavpack']['blockheader']['block_samples']) ||
|
||||
empty($ThisFileInfo['wavpack']['blockheader']['total_samples']) ||
|
||||
($ThisFileInfo['wavpack']['blockheader']['block_samples'] <= 0) ||
|
||||
($ThisFileInfo['wavpack']['blockheader']['total_samples'] <= 0)) {
|
||||
// Also, it is possible that the first block might not have
|
||||
// any samples (block_samples == 0) and in this case you should skip blocks
|
||||
// until you find one with samples because the other information (like
|
||||
// total_samples) are not guaranteed to be correct until (block_samples > 0)
|
||||
|
||||
// Finally, I have defined a format for files in which the length is not known
|
||||
// (for example when raw files are created using pipes). In these cases
|
||||
// total_samples will be -1 and you must seek to the final block to determine
|
||||
// the total number of samples.
|
||||
|
||||
|
||||
$ThisFileInfo['audio']['dataformat'] = 'wavpack';
|
||||
$ThisFileInfo['fileformat'] = 'wavpack';
|
||||
$ThisFileInfo['audio']['lossless'] = true;
|
||||
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
|
||||
|
||||
$ThisFileInfo['wavpack']['blockheader']['offset'] = $blockheader_offset;
|
||||
$ThisFileInfo['wavpack']['blockheader']['magic'] = $blockheader_magic;
|
||||
$ThisFileInfo['wavpack']['blockheader']['size'] = $blockheader_size;
|
||||
|
||||
if ($ThisFileInfo['wavpack']['blockheader']['size'] >= 0x100000) {
|
||||
$ThisFileInfo['error'][] = 'Expecting WavPack block size less than "0x100000", found "'.$ThisFileInfo['wavpack']['blockheader']['size'].'" at offset '.$ThisFileInfo['wavpack']['blockheader']['offset'];
|
||||
switch (isset($ThisFileInfo['audio']['dataformat']) ? $ThisFileInfo['audio']['dataformat'] : '') {
|
||||
case 'wavpack':
|
||||
case 'wvc':
|
||||
break;
|
||||
default:
|
||||
unset($ThisFileInfo['fileformat']);
|
||||
unset($ThisFileInfo['audio']);
|
||||
unset($ThisFileInfo['wavpack']);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['wavpack']['blockheader']['minor_version'] = ord($wavpackheader{8});
|
||||
$ThisFileInfo['wavpack']['blockheader']['major_version'] = ord($wavpackheader{9});
|
||||
|
||||
if (($ThisFileInfo['wavpack']['blockheader']['major_version'] != 4) ||
|
||||
(($ThisFileInfo['wavpack']['blockheader']['minor_version'] < 4) &&
|
||||
($ThisFileInfo['wavpack']['blockheader']['minor_version'] > 16))) {
|
||||
$ThisFileInfo['error'][] = 'Expecting WavPack version between "4.2" and "4.16", found version "'.$ThisFileInfo['wavpack']['blockheader']['major_version'].'.'.$ThisFileInfo['wavpack']['blockheader']['minor_version'].'" at offset '.$ThisFileInfo['wavpack']['blockheader']['offset'];
|
||||
switch (isset($ThisFileInfo['audio']['dataformat']) ? $ThisFileInfo['audio']['dataformat'] : '') {
|
||||
case 'wavpack':
|
||||
case 'wvc':
|
||||
break;
|
||||
default:
|
||||
unset($ThisFileInfo['fileformat']);
|
||||
unset($ThisFileInfo['audio']);
|
||||
unset($ThisFileInfo['wavpack']);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['wavpack']['blockheader']['track_number'] = ord($wavpackheader{10}); // unused
|
||||
$ThisFileInfo['wavpack']['blockheader']['index_number'] = ord($wavpackheader{11}); // unused
|
||||
$ThisFileInfo['wavpack']['blockheader']['total_samples'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 12, 4));
|
||||
$ThisFileInfo['wavpack']['blockheader']['block_index'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 16, 4));
|
||||
$ThisFileInfo['wavpack']['blockheader']['block_samples'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 20, 4));
|
||||
$ThisFileInfo['wavpack']['blockheader']['flags_raw'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 24, 4));
|
||||
$ThisFileInfo['wavpack']['blockheader']['crc'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 28, 4));
|
||||
|
||||
$ThisFileInfo['wavpack']['blockheader']['flags']['bytes_per_sample'] = 1 + ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000003);
|
||||
$ThisFileInfo['wavpack']['blockheader']['flags']['mono'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000004);
|
||||
$ThisFileInfo['wavpack']['blockheader']['flags']['hybrid'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000008);
|
||||
$ThisFileInfo['wavpack']['blockheader']['flags']['joint_stereo'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000010);
|
||||
$ThisFileInfo['wavpack']['blockheader']['flags']['cross_decorrelation'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000020);
|
||||
$ThisFileInfo['wavpack']['blockheader']['flags']['hybrid_noiseshape'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000040);
|
||||
$ThisFileInfo['wavpack']['blockheader']['flags']['ieee_32bit_float'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000080);
|
||||
$ThisFileInfo['wavpack']['blockheader']['flags']['int_32bit'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000100);
|
||||
$ThisFileInfo['wavpack']['blockheader']['flags']['hybrid_bitrate_noise'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000200);
|
||||
$ThisFileInfo['wavpack']['blockheader']['flags']['hybrid_balance_noise'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000400);
|
||||
$ThisFileInfo['wavpack']['blockheader']['flags']['multichannel_initial'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000800);
|
||||
$ThisFileInfo['wavpack']['blockheader']['flags']['multichannel_final'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00001000);
|
||||
|
||||
$ThisFileInfo['audio']['lossless'] = !$ThisFileInfo['wavpack']['blockheader']['flags']['hybrid'];
|
||||
}
|
||||
|
||||
while (!feof($fd) && (ftell($fd) < ($blockheader_offset + $blockheader_size + 8))) {
|
||||
|
||||
$metablock = array('offset'=>ftell($fd));
|
||||
$metablockheader = fread($fd, 2);
|
||||
if (feof($fd)) {
|
||||
break;
|
||||
}
|
||||
$metablock['id'] = ord($metablockheader{0});
|
||||
$metablock['function_id'] = ($metablock['id'] & 0x3F);
|
||||
$metablock['function_name'] = $this->WavPackMetablockNameLookup($metablock['function_id']);
|
||||
|
||||
// The 0x20 bit in the id of the meta subblocks (which is defined as
|
||||
// ID_OPTIONAL_DATA) is a permanent part of the id. The idea is that
|
||||
// if a decoder encounters an id that it does not know about, it uses
|
||||
// that "ID_OPTIONAL_DATA" flag to determine what to do. If it is set
|
||||
// then the decoder simply ignores the metadata, but if it is zero
|
||||
// then the decoder should quit because it means that an understanding
|
||||
// of the metadata is required to correctly decode the audio.
|
||||
$metablock['non_decoder'] = (bool) ($metablock['id'] & 0x20);
|
||||
|
||||
$metablock['padded_data'] = (bool) ($metablock['id'] & 0x40);
|
||||
$metablock['large_block'] = (bool) ($metablock['id'] & 0x80);
|
||||
if ($metablock['large_block']) {
|
||||
$metablockheader .= fread($fd, 2);
|
||||
}
|
||||
$metablock['size'] = getid3_lib::LittleEndian2Int(substr($metablockheader, 1)) * 2; // size is stored in words
|
||||
$metablock['data'] = null;
|
||||
|
||||
if ($metablock['size'] > 0) {
|
||||
|
||||
switch ($metablock['function_id']) {
|
||||
case 0x21: // ID_RIFF_HEADER
|
||||
case 0x22: // ID_RIFF_TRAILER
|
||||
case 0x23: // ID_REPLAY_GAIN
|
||||
case 0x24: // ID_CUESHEET
|
||||
case 0x25: // ID_CONFIG_BLOCK
|
||||
case 0x26: // ID_MD5_CHECKSUM
|
||||
$metablock['data'] = fread($fd, $metablock['size']);
|
||||
|
||||
if ($metablock['padded_data']) {
|
||||
// padded to the nearest even byte
|
||||
$metablock['size']--;
|
||||
$metablock['data'] = substr($metablock['data'], 0, -1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x00: // ID_DUMMY
|
||||
case 0x01: // ID_ENCODER_INFO
|
||||
case 0x02: // ID_DECORR_TERMS
|
||||
case 0x03: // ID_DECORR_WEIGHTS
|
||||
case 0x04: // ID_DECORR_SAMPLES
|
||||
case 0x05: // ID_ENTROPY_VARS
|
||||
case 0x06: // ID_HYBRID_PROFILE
|
||||
case 0x07: // ID_SHAPING_WEIGHTS
|
||||
case 0x08: // ID_FLOAT_INFO
|
||||
case 0x09: // ID_INT32_INFO
|
||||
case 0x0A: // ID_WV_BITSTREAM
|
||||
case 0x0B: // ID_WVC_BITSTREAM
|
||||
case 0x0C: // ID_WVX_BITSTREAM
|
||||
case 0x0D: // ID_CHANNEL_INFO
|
||||
fseek($fd, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET);
|
||||
break;
|
||||
|
||||
default:
|
||||
$ThisFileInfo['warning'][] = 'Unexpected metablock type "0x'.str_pad(dechex($metablock['function_id']), 2, '0', STR_PAD_LEFT).'" at offset '.$metablock['offset'];
|
||||
fseek($fd, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET);
|
||||
break;
|
||||
}
|
||||
|
||||
switch ($metablock['function_id']) {
|
||||
case 0x21: // ID_RIFF_HEADER
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
|
||||
$original_wav_filesize = getid3_lib::LittleEndian2Int(substr($metablock['data'], 4, 4));
|
||||
getid3_riff::ParseRIFFdata($metablock['data'], $ParsedRIFFheader);
|
||||
$metablock['riff'] = $ParsedRIFFheader['riff'];
|
||||
$metablock['riff']['original_filesize'] = $original_wav_filesize;
|
||||
$ThisFileInfo['wavpack']['riff_trailer_size'] = $original_wav_filesize - $metablock['riff']['WAVE']['data'][0]['size'] - $metablock['riff']['header_size'];
|
||||
|
||||
$ThisFileInfo['audio']['sample_rate'] = $ParsedRIFFheader['riff']['raw']['fmt ']['nSamplesPerSec'];
|
||||
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['wavpack']['blockheader']['total_samples'] / $ThisFileInfo['audio']['sample_rate'];
|
||||
|
||||
// Safe RIFF header in case there's a RIFF footer later
|
||||
$metablockRIFFheader = $metablock['data'];
|
||||
break;
|
||||
|
||||
|
||||
case 0x22: // ID_RIFF_TRAILER
|
||||
$metablockRIFFfooter = $metablockRIFFheader.$metablock['data'];
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
|
||||
|
||||
$ftell_old = ftell($fd);
|
||||
$startoffset = $metablock['offset'] + ($metablock['large_block'] ? 4 : 2);
|
||||
$ParsedRIFFfooter = array('avdataend'=>$ThisFileInfo['avdataend'], 'fileformat'=>'riff', 'error'=>array(), 'warning'=>array());
|
||||
$metablock['riff'] = getid3_riff::ParseRIFF($fd, $startoffset, $startoffset + $metablock['size'], $ParsedRIFFfooter);
|
||||
fseek($fd, $ftell_old, SEEK_SET);
|
||||
|
||||
if (!empty($metablock['riff']['INFO'])) {
|
||||
getid3_riff::RIFFcommentsParse($metablock['riff']['INFO'], $metablock['comments']);
|
||||
$ThisFileInfo['tags']['riff'] = $metablock['comments'];
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0x23: // ID_REPLAY_GAIN
|
||||
$ThisFileInfo['warning'][] = 'WavPack "Replay Gain" contents not yet handled by getID3() in metablock at offset '.$metablock['offset'];
|
||||
break;
|
||||
|
||||
|
||||
case 0x24: // ID_CUESHEET
|
||||
$ThisFileInfo['warning'][] = 'WavPack "Cuesheet" contents not yet handled by getID3() in metablock at offset '.$metablock['offset'];
|
||||
break;
|
||||
|
||||
|
||||
case 0x25: // ID_CONFIG_BLOCK
|
||||
$metablock['flags_raw'] = getid3_lib::LittleEndian2Int(substr($metablock['data'], 0, 3));
|
||||
|
||||
$metablock['flags']['adobe_mode'] = (bool) ($metablock['flags_raw'] & 0x000001); // "adobe" mode for 32-bit floats
|
||||
$metablock['flags']['fast_flag'] = (bool) ($metablock['flags_raw'] & 0x000002); // fast mode
|
||||
$metablock['flags']['very_fast_flag'] = (bool) ($metablock['flags_raw'] & 0x000004); // double fast
|
||||
$metablock['flags']['high_flag'] = (bool) ($metablock['flags_raw'] & 0x000008); // high quality mode
|
||||
$metablock['flags']['very_high_flag'] = (bool) ($metablock['flags_raw'] & 0x000010); // double high (not used yet)
|
||||
$metablock['flags']['bitrate_kbps'] = (bool) ($metablock['flags_raw'] & 0x000020); // bitrate is kbps, not bits / sample
|
||||
$metablock['flags']['auto_shaping'] = (bool) ($metablock['flags_raw'] & 0x000040); // automatic noise shaping
|
||||
$metablock['flags']['shape_override'] = (bool) ($metablock['flags_raw'] & 0x000080); // shaping mode specified
|
||||
$metablock['flags']['joint_override'] = (bool) ($metablock['flags_raw'] & 0x000100); // joint-stereo mode specified
|
||||
$metablock['flags']['copy_time'] = (bool) ($metablock['flags_raw'] & 0x000200); // copy file-time from source
|
||||
$metablock['flags']['create_exe'] = (bool) ($metablock['flags_raw'] & 0x000400); // create executable
|
||||
$metablock['flags']['create_wvc'] = (bool) ($metablock['flags_raw'] & 0x000800); // create correction file
|
||||
$metablock['flags']['optimize_wvc'] = (bool) ($metablock['flags_raw'] & 0x001000); // maximize bybrid compression
|
||||
$metablock['flags']['quality_mode'] = (bool) ($metablock['flags_raw'] & 0x002000); // psychoacoustic quality mode
|
||||
$metablock['flags']['raw_flag'] = (bool) ($metablock['flags_raw'] & 0x004000); // raw mode (not implemented yet)
|
||||
$metablock['flags']['calc_noise'] = (bool) ($metablock['flags_raw'] & 0x008000); // calc noise in hybrid mode
|
||||
$metablock['flags']['lossy_mode'] = (bool) ($metablock['flags_raw'] & 0x010000); // obsolete (for information)
|
||||
$metablock['flags']['extra_mode'] = (bool) ($metablock['flags_raw'] & 0x020000); // extra processing mode
|
||||
$metablock['flags']['skip_wvx'] = (bool) ($metablock['flags_raw'] & 0x040000); // no wvx stream w/ floats & big ints
|
||||
$metablock['flags']['md5_checksum'] = (bool) ($metablock['flags_raw'] & 0x080000); // compute & store MD5 signature
|
||||
$metablock['flags']['quiet_mode'] = (bool) ($metablock['flags_raw'] & 0x100000); // don't report progress %
|
||||
|
||||
$ThisFileInfo['wavpack']['config_flags'] = $metablock['flags'];
|
||||
|
||||
|
||||
$ThisFileInfo['audio']['encoder_options'] = '';
|
||||
if ($ThisFileInfo['wavpack']['blockheader']['flags']['hybrid']) {
|
||||
$ThisFileInfo['audio']['encoder_options'] .= ' -b???';
|
||||
}
|
||||
$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['adobe_mode'] ? ' -a' : '');
|
||||
$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['optimize_wvc'] ? ' -cc' : '');
|
||||
$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['create_exe'] ? ' -e' : '');
|
||||
$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['fast_flag'] ? ' -f' : '');
|
||||
$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['joint_override'] ? ' -j?' : '');
|
||||
$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['high_flag'] ? ' -h' : '');
|
||||
$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['md5_checksum'] ? ' -m' : '');
|
||||
$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['calc_noise'] ? ' -n' : '');
|
||||
$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['shape_override'] ? ' -s?' : '');
|
||||
$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['extra_mode'] ? ' -x?' : '');
|
||||
if (!empty($ThisFileInfo['audio']['encoder_options'])) {
|
||||
$ThisFileInfo['audio']['encoder_options'] = trim($ThisFileInfo['audio']['encoder_options']);
|
||||
} elseif (isset($ThisFileInfo['audio']['encoder_options'])) {
|
||||
unset($ThisFileInfo['audio']['encoder_options']);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0x26: // ID_MD5_CHECKSUM
|
||||
if (strlen($metablock['data']) == 16) {
|
||||
$ThisFileInfo['md5_data_source'] = strtolower(getid3_lib::PrintHexBytes($metablock['data'], true, false, false));
|
||||
} else {
|
||||
$ThisFileInfo['warning'][] = 'Expecting 16 bytes of WavPack "MD5 Checksum" in metablock at offset '.$metablock['offset'].', but found '.strlen($metablock['data']).' bytes';
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0x00: // ID_DUMMY
|
||||
case 0x01: // ID_ENCODER_INFO
|
||||
case 0x02: // ID_DECORR_TERMS
|
||||
case 0x03: // ID_DECORR_WEIGHTS
|
||||
case 0x04: // ID_DECORR_SAMPLES
|
||||
case 0x05: // ID_ENTROPY_VARS
|
||||
case 0x06: // ID_HYBRID_PROFILE
|
||||
case 0x07: // ID_SHAPING_WEIGHTS
|
||||
case 0x08: // ID_FLOAT_INFO
|
||||
case 0x09: // ID_INT32_INFO
|
||||
case 0x0A: // ID_WV_BITSTREAM
|
||||
case 0x0B: // ID_WVC_BITSTREAM
|
||||
case 0x0C: // ID_WVX_BITSTREAM
|
||||
case 0x0D: // ID_CHANNEL_INFO
|
||||
unset($metablock);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (!empty($metablock)) {
|
||||
$ThisFileInfo['wavpack']['metablocks'][] = $metablock;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$ThisFileInfo['audio']['encoder'] = 'WavPack v'.$ThisFileInfo['wavpack']['blockheader']['major_version'].'.'.str_pad($ThisFileInfo['wavpack']['blockheader']['minor_version'], 2, '0', STR_PAD_LEFT);
|
||||
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['wavpack']['blockheader']['flags']['bytes_per_sample'] * 8;
|
||||
$ThisFileInfo['audio']['channels'] = ($ThisFileInfo['wavpack']['blockheader']['flags']['mono'] ? 1 : 2);
|
||||
|
||||
if (!empty($ThisFileInfo['playtime_seconds'])) {
|
||||
|
||||
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
|
||||
|
||||
} else {
|
||||
|
||||
$ThisFileInfo['audio']['dataformat'] = 'wvc';
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function WavPackMetablockNameLookup(&$id) {
|
||||
static $WavPackMetablockNameLookup = array(
|
||||
0x00 => 'Dummy',
|
||||
0x01 => 'Encoder Info',
|
||||
0x02 => 'Decorrelation Terms',
|
||||
0x03 => 'Decorrelation Weights',
|
||||
0x04 => 'Decorrelation Samples',
|
||||
0x05 => 'Entropy Variables',
|
||||
0x06 => 'Hybrid Profile',
|
||||
0x07 => 'Shaping Weights',
|
||||
0x08 => 'Float Info',
|
||||
0x09 => 'Int32 Info',
|
||||
0x0A => 'WV Bitstream',
|
||||
0x0B => 'WVC Bitstream',
|
||||
0x0C => 'WVX Bitstream',
|
||||
0x0D => 'Channel Info',
|
||||
0x21 => 'RIFF header',
|
||||
0x22 => 'RIFF trailer',
|
||||
0x23 => 'Replay Gain',
|
||||
0x24 => 'Cuesheet',
|
||||
0x25 => 'Config Block',
|
||||
0x26 => 'MD5 Checksum',
|
||||
);
|
||||
return (isset($WavPackMetablockNameLookup[$id]) ? $WavPackMetablockNameLookup[$id] : '');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,183 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.graphic.gif.php //
|
||||
// module for analyzing GIF Image files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_gif
|
||||
{
|
||||
|
||||
function getid3_gif(&$fd, &$ThisFileInfo) {
|
||||
$ThisFileInfo['fileformat'] = 'gif';
|
||||
$ThisFileInfo['video']['dataformat'] = 'gif';
|
||||
$ThisFileInfo['video']['lossless'] = true;
|
||||
$ThisFileInfo['video']['pixel_aspect_ratio'] = (float) 1;
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$GIFheader = fread($fd, 13);
|
||||
$offset = 0;
|
||||
|
||||
$ThisFileInfo['gif']['header']['raw']['identifier'] = substr($GIFheader, $offset, 3);
|
||||
$offset += 3;
|
||||
|
||||
if ($ThisFileInfo['gif']['header']['raw']['identifier'] != 'GIF') {
|
||||
$ThisFileInfo['error'][] = 'Expecting "GIF" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$ThisFileInfo['gif']['header']['raw']['identifier'].'"';
|
||||
unset($ThisFileInfo['fileformat']);
|
||||
unset($ThisFileInfo['gif']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['gif']['header']['raw']['version'] = substr($GIFheader, $offset, 3);
|
||||
$offset += 3;
|
||||
$ThisFileInfo['gif']['header']['raw']['width'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$ThisFileInfo['gif']['header']['raw']['height'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$ThisFileInfo['gif']['header']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1));
|
||||
$offset += 1;
|
||||
$ThisFileInfo['gif']['header']['raw']['bg_color_index'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1));
|
||||
$offset += 1;
|
||||
$ThisFileInfo['gif']['header']['raw']['aspect_ratio'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1));
|
||||
$offset += 1;
|
||||
|
||||
$ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['gif']['header']['raw']['width'];
|
||||
$ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['gif']['header']['raw']['height'];
|
||||
$ThisFileInfo['gif']['version'] = $ThisFileInfo['gif']['header']['raw']['version'];
|
||||
$ThisFileInfo['gif']['header']['flags']['global_color_table'] = (bool) ($ThisFileInfo['gif']['header']['raw']['flags'] & 0x80);
|
||||
if ($ThisFileInfo['gif']['header']['raw']['flags'] & 0x80) {
|
||||
// Number of bits per primary color available to the original image, minus 1
|
||||
$ThisFileInfo['gif']['header']['bits_per_pixel'] = 3 * ((($ThisFileInfo['gif']['header']['raw']['flags'] & 0x70) >> 4) + 1);
|
||||
} else {
|
||||
$ThisFileInfo['gif']['header']['bits_per_pixel'] = 0;
|
||||
}
|
||||
$ThisFileInfo['gif']['header']['flags']['global_color_sorted'] = (bool) ($ThisFileInfo['gif']['header']['raw']['flags'] & 0x40);
|
||||
if ($ThisFileInfo['gif']['header']['flags']['global_color_table']) {
|
||||
// the number of bytes contained in the Global Color Table. To determine that
|
||||
// actual size of the color table, raise 2 to [the value of the field + 1]
|
||||
$ThisFileInfo['gif']['header']['global_color_size'] = pow(2, ($ThisFileInfo['gif']['header']['raw']['flags'] & 0x07) + 1);
|
||||
$ThisFileInfo['video']['bits_per_sample'] = ($ThisFileInfo['gif']['header']['raw']['flags'] & 0x07) + 1;
|
||||
} else {
|
||||
$ThisFileInfo['gif']['header']['global_color_size'] = 0;
|
||||
}
|
||||
if ($ThisFileInfo['gif']['header']['raw']['aspect_ratio'] != 0) {
|
||||
// Aspect Ratio = (Pixel Aspect Ratio + 15) / 64
|
||||
$ThisFileInfo['gif']['header']['aspect_ratio'] = ($ThisFileInfo['gif']['header']['raw']['aspect_ratio'] + 15) / 64;
|
||||
}
|
||||
|
||||
// if ($ThisFileInfo['gif']['header']['flags']['global_color_table']) {
|
||||
// $GIFcolorTable = fread($fd, 3 * $ThisFileInfo['gif']['header']['global_color_size']);
|
||||
// $offset = 0;
|
||||
// for ($i = 0; $i < $ThisFileInfo['gif']['header']['global_color_size']; $i++) {
|
||||
// $red = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
|
||||
// $green = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
|
||||
// $blue = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
|
||||
// $ThisFileInfo['gif']['global_color_table'][$i] = (($red << 16) | ($green << 8) | ($blue));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Image Descriptor
|
||||
// while (!feof($fd)) {
|
||||
// $NextBlockTest = fread($fd, 1);
|
||||
// switch ($NextBlockTest) {
|
||||
//
|
||||
// case ',': // ',' - Image separator character
|
||||
//
|
||||
// $ImageDescriptorData = $NextBlockTest.fread($fd, 9);
|
||||
// $ImageDescriptor = array();
|
||||
// $ImageDescriptor['image_left'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 1, 2));
|
||||
// $ImageDescriptor['image_top'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 3, 2));
|
||||
// $ImageDescriptor['image_width'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 5, 2));
|
||||
// $ImageDescriptor['image_height'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 7, 2));
|
||||
// $ImageDescriptor['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 9, 1));
|
||||
// $ImageDescriptor['flags']['use_local_color_map'] = (bool) ($ImageDescriptor['flags_raw'] & 0x80);
|
||||
// $ImageDescriptor['flags']['image_interlaced'] = (bool) ($ImageDescriptor['flags_raw'] & 0x40);
|
||||
// $ThisFileInfo['gif']['image_descriptor'][] = $ImageDescriptor;
|
||||
//
|
||||
// if ($ImageDescriptor['flags']['use_local_color_map']) {
|
||||
//
|
||||
// $ThisFileInfo['warning'][] = 'This version of getID3() cannot parse local color maps for GIFs';
|
||||
// return true;
|
||||
//
|
||||
// }
|
||||
//echo 'Start of raster data: '.ftell($fd).'<BR>';
|
||||
// $RasterData = array();
|
||||
// $RasterData['code_size'] = getid3_lib::LittleEndian2Int(fread($fd, 1));
|
||||
// $RasterData['block_byte_count'] = getid3_lib::LittleEndian2Int(fread($fd, 1));
|
||||
// $ThisFileInfo['gif']['raster_data'][count($ThisFileInfo['gif']['image_descriptor']) - 1] = $RasterData;
|
||||
//
|
||||
// $CurrentCodeSize = $RasterData['code_size'] + 1;
|
||||
// for ($i = 0; $i < pow(2, $RasterData['code_size']); $i++) {
|
||||
// $DefaultDataLookupTable[$i] = chr($i);
|
||||
// }
|
||||
// $DefaultDataLookupTable[pow(2, $RasterData['code_size']) + 0] = ''; // Clear Code
|
||||
// $DefaultDataLookupTable[pow(2, $RasterData['code_size']) + 1] = ''; // End Of Image Code
|
||||
//
|
||||
//
|
||||
// $NextValue = $this->GetLSBits($fd, $CurrentCodeSize);
|
||||
// echo 'Clear Code: '.$NextValue.'<BR>';
|
||||
//
|
||||
// $NextValue = $this->GetLSBits($fd, $CurrentCodeSize);
|
||||
// echo 'First Color: '.$NextValue.'<BR>';
|
||||
//
|
||||
// $Prefix = $NextValue;
|
||||
//$i = 0;
|
||||
// while ($i++ < 20) {
|
||||
// $NextValue = $this->GetLSBits($fd, $CurrentCodeSize);
|
||||
// echo $NextValue.'<BR>';
|
||||
// }
|
||||
//return true;
|
||||
// break;
|
||||
//
|
||||
// case '!':
|
||||
// // GIF Extension Block
|
||||
// $ExtensionBlockData = $NextBlockTest.fread($fd, 2);
|
||||
// $ExtensionBlock = array();
|
||||
// $ExtensionBlock['function_code'] = getid3_lib::LittleEndian2Int(substr($ExtensionBlockData, 1, 1));
|
||||
// $ExtensionBlock['byte_length'] = getid3_lib::LittleEndian2Int(substr($ExtensionBlockData, 2, 1));
|
||||
// $ExtensionBlock['data'] = fread($fd, $ExtensionBlock['byte_length']);
|
||||
// $ThisFileInfo['gif']['extension_blocks'][] = $ExtensionBlock;
|
||||
// break;
|
||||
//
|
||||
// case ';':
|
||||
// $ThisFileInfo['gif']['terminator_offset'] = ftell($fd) - 1;
|
||||
// // GIF Terminator
|
||||
// break;
|
||||
//
|
||||
// default:
|
||||
// break;
|
||||
//
|
||||
//
|
||||
// }
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function GetLSBits($fd, $bits) {
|
||||
static $bitbuffer = '';
|
||||
while (strlen($bitbuffer) < $bits) {
|
||||
//echo 'Read another byte: '.ftell($fd).'<BR>';
|
||||
$bitbuffer = str_pad(decbin(ord(fread($fd, 1))), 8, '0', STR_PAD_LEFT).$bitbuffer;
|
||||
}
|
||||
|
||||
$value = bindec(substr($bitbuffer, 0 - $bits));
|
||||
$bitbuffer = substr($bitbuffer, 0, 0 - $bits);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,102 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.graphic.svg.php //
|
||||
// module for analyzing SVG Image files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_svg
|
||||
{
|
||||
|
||||
|
||||
function getid3_svg(&$fd, &$ThisFileInfo) {
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
|
||||
$SVGheader = fread($fd, 4096);
|
||||
if (preg_match('#\<\?xml([^\>]+)\?\>#i', $SVGheader, $matches)) {
|
||||
$ThisFileInfo['svg']['xml']['raw'] = $matches;
|
||||
}
|
||||
if (preg_match('#\<\!DOCTYPE([^\>]+)\>#i', $SVGheader, $matches)) {
|
||||
$ThisFileInfo['svg']['doctype']['raw'] = $matches;
|
||||
}
|
||||
if (preg_match('#\<svg([^\>]+)\>#i', $SVGheader, $matches)) {
|
||||
$ThisFileInfo['svg']['svg']['raw'] = $matches;
|
||||
}
|
||||
if (isset($ThisFileInfo['svg']['svg']['raw'])) {
|
||||
|
||||
$sections_to_fix = array('xml', 'doctype', 'svg');
|
||||
foreach ($sections_to_fix as $section_to_fix) {
|
||||
if (!isset($ThisFileInfo['svg'][$section_to_fix])) {
|
||||
continue;
|
||||
}
|
||||
$section_data = array();
|
||||
while (preg_match('/ "([^"]+)"/', $ThisFileInfo['svg'][$section_to_fix]['raw'][1], $matches)) {
|
||||
$section_data[] = $matches[1];
|
||||
$ThisFileInfo['svg'][$section_to_fix]['raw'][1] = str_replace($matches[0], '', $ThisFileInfo['svg'][$section_to_fix]['raw'][1]);
|
||||
}
|
||||
while (preg_match('/([^\s]+)="([^"]+)"/', $ThisFileInfo['svg'][$section_to_fix]['raw'][1], $matches)) {
|
||||
$section_data[] = $matches[0];
|
||||
$ThisFileInfo['svg'][$section_to_fix]['raw'][1] = str_replace($matches[0], '', $ThisFileInfo['svg'][$section_to_fix]['raw'][1]);
|
||||
}
|
||||
$section_data = array_merge($section_data, preg_split('/[\s,]+/', $ThisFileInfo['svg'][$section_to_fix]['raw'][1]));
|
||||
foreach ($section_data as $keyvaluepair) {
|
||||
$keyvaluepair = trim($keyvaluepair);
|
||||
if ($keyvaluepair) {
|
||||
$keyvalueexploded = explode('=', $keyvaluepair);
|
||||
$key = (isset($keyvalueexploded[0]) ? $keyvalueexploded[0] : '');
|
||||
$value = (isset($keyvalueexploded[1]) ? $keyvalueexploded[1] : '');
|
||||
$ThisFileInfo['svg'][$section_to_fix]['sections'][$key] = trim($value, '"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'svg';
|
||||
$ThisFileInfo['video']['dataformat'] = 'svg';
|
||||
$ThisFileInfo['video']['lossless'] = true;
|
||||
//$ThisFileInfo['video']['bits_per_sample'] = 24;
|
||||
$ThisFileInfo['video']['pixel_aspect_ratio'] = (float) 1;
|
||||
|
||||
if (!empty($ThisFileInfo['svg']['svg']['sections']['width'])) {
|
||||
$ThisFileInfo['svg']['width'] = intval($ThisFileInfo['svg']['svg']['sections']['width']);
|
||||
}
|
||||
if (!empty($ThisFileInfo['svg']['svg']['sections']['height'])) {
|
||||
$ThisFileInfo['svg']['height'] = intval($ThisFileInfo['svg']['svg']['sections']['height']);
|
||||
}
|
||||
if (!empty($ThisFileInfo['svg']['svg']['sections']['version'])) {
|
||||
$ThisFileInfo['svg']['version'] = $ThisFileInfo['svg']['svg']['sections']['version'];
|
||||
}
|
||||
if (!isset($ThisFileInfo['svg']['version']) && isset($ThisFileInfo['svg']['doctype']['sections'])) {
|
||||
foreach ($ThisFileInfo['svg']['doctype']['sections'] as $key => $value) {
|
||||
if (preg_match('#//W3C//DTD SVG ([0-9\.]+)//#i', $key, $matches)) {
|
||||
$ThisFileInfo['svg']['version'] = $matches[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($ThisFileInfo['svg']['width'])) {
|
||||
$ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['svg']['width'];
|
||||
}
|
||||
if (!empty($ThisFileInfo['svg']['height'])) {
|
||||
$ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['svg']['height'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
$ThisFileInfo['error'][] = 'Did not find expected <svg> tag';
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,226 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.archive.tiff.php //
|
||||
// module for analyzing TIFF files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_tiff
|
||||
{
|
||||
|
||||
function getid3_tiff(&$fd, &$ThisFileInfo) {
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$TIFFheader = fread($fd, 4);
|
||||
|
||||
switch (substr($TIFFheader, 0, 2)) {
|
||||
case 'II':
|
||||
$ThisFileInfo['tiff']['byte_order'] = 'Intel';
|
||||
break;
|
||||
case 'MM':
|
||||
$ThisFileInfo['tiff']['byte_order'] = 'Motorola';
|
||||
break;
|
||||
default:
|
||||
$ThisFileInfo['error'][] = 'Invalid TIFF byte order identifier ('.substr($TIFFheader, 0, 2).') at offset '.$ThisFileInfo['avdataoffset'];
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'tiff';
|
||||
$ThisFileInfo['video']['dataformat'] = 'tiff';
|
||||
$ThisFileInfo['video']['lossless'] = true;
|
||||
$ThisFileInfo['tiff']['ifd'] = array();
|
||||
$CurrentIFD = array();
|
||||
|
||||
$FieldTypeByteLength = array(1=>1, 2=>1, 3=>2, 4=>4, 5=>8);
|
||||
|
||||
$nextIFDoffset = $this->TIFFendian2Int(fread($fd, 4), $ThisFileInfo['tiff']['byte_order']);
|
||||
|
||||
while ($nextIFDoffset > 0) {
|
||||
|
||||
$CurrentIFD['offset'] = $nextIFDoffset;
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'] + $nextIFDoffset, SEEK_SET);
|
||||
$CurrentIFD['fieldcount'] = $this->TIFFendian2Int(fread($fd, 2), $ThisFileInfo['tiff']['byte_order']);
|
||||
|
||||
for ($i = 0; $i < $CurrentIFD['fieldcount']; $i++) {
|
||||
$CurrentIFD['fields'][$i]['raw']['tag'] = $this->TIFFendian2Int(fread($fd, 2), $ThisFileInfo['tiff']['byte_order']);
|
||||
$CurrentIFD['fields'][$i]['raw']['type'] = $this->TIFFendian2Int(fread($fd, 2), $ThisFileInfo['tiff']['byte_order']);
|
||||
$CurrentIFD['fields'][$i]['raw']['length'] = $this->TIFFendian2Int(fread($fd, 4), $ThisFileInfo['tiff']['byte_order']);
|
||||
$CurrentIFD['fields'][$i]['raw']['offset'] = fread($fd, 4);
|
||||
|
||||
switch ($CurrentIFD['fields'][$i]['raw']['type']) {
|
||||
case 1: // BYTE An 8-bit unsigned integer.
|
||||
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
|
||||
$CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 1), $ThisFileInfo['tiff']['byte_order']);
|
||||
} else {
|
||||
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $ThisFileInfo['tiff']['byte_order']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // ASCII 8-bit bytes that store ASCII codes; the last byte must be null.
|
||||
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
|
||||
$CurrentIFD['fields'][$i]['value'] = substr($CurrentIFD['fields'][$i]['raw']['offset'], 3);
|
||||
} else {
|
||||
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $ThisFileInfo['tiff']['byte_order']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // SHORT A 16-bit (2-byte) unsigned integer.
|
||||
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 2) {
|
||||
$CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 2), $ThisFileInfo['tiff']['byte_order']);
|
||||
} else {
|
||||
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $ThisFileInfo['tiff']['byte_order']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // LONG A 32-bit (4-byte) unsigned integer.
|
||||
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 1) {
|
||||
$CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $ThisFileInfo['tiff']['byte_order']);
|
||||
} else {
|
||||
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $ThisFileInfo['tiff']['byte_order']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 5: // RATIONAL Two LONG_s: the first represents the numerator of a fraction, the second the denominator.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$ThisFileInfo['tiff']['ifd'][] = $CurrentIFD;
|
||||
$CurrentIFD = array();
|
||||
$nextIFDoffset = $this->TIFFendian2Int(fread($fd, 4), $ThisFileInfo['tiff']['byte_order']);
|
||||
|
||||
}
|
||||
|
||||
foreach ($ThisFileInfo['tiff']['ifd'] as $IFDid => $IFDarray) {
|
||||
foreach ($IFDarray['fields'] as $key => $fieldarray) {
|
||||
switch ($fieldarray['raw']['tag']) {
|
||||
case 256: // ImageWidth
|
||||
case 257: // ImageLength
|
||||
case 258: // BitsPerSample
|
||||
case 259: // Compression
|
||||
if (!isset($fieldarray['value'])) {
|
||||
fseek($fd, $fieldarray['offset'], SEEK_SET);
|
||||
$ThisFileInfo['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = fread($fd, $fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case 270: // ImageDescription
|
||||
case 271: // Make
|
||||
case 272: // Model
|
||||
case 305: // Software
|
||||
case 306: // DateTime
|
||||
case 315: // Artist
|
||||
case 316: // HostComputer
|
||||
if (isset($fieldarray['value'])) {
|
||||
$ThisFileInfo['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $fieldarray['value'];
|
||||
} else {
|
||||
fseek($fd, $fieldarray['offset'], SEEK_SET);
|
||||
$ThisFileInfo['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = fread($fd, $fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch ($fieldarray['raw']['tag']) {
|
||||
case 256: // ImageWidth
|
||||
$ThisFileInfo['video']['resolution_x'] = $fieldarray['value'];
|
||||
break;
|
||||
|
||||
case 257: // ImageLength
|
||||
$ThisFileInfo['video']['resolution_y'] = $fieldarray['value'];
|
||||
break;
|
||||
|
||||
case 258: // BitsPerSample
|
||||
if (isset($fieldarray['value'])) {
|
||||
$ThisFileInfo['video']['bits_per_sample'] = $fieldarray['value'];
|
||||
} else {
|
||||
$ThisFileInfo['video']['bits_per_sample'] = 0;
|
||||
for ($i = 0; $i < $fieldarray['raw']['length']; $i++) {
|
||||
$ThisFileInfo['video']['bits_per_sample'] += $this->TIFFendian2Int(substr($ThisFileInfo['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'], $i * $FieldTypeByteLength[$fieldarray['raw']['type']], $FieldTypeByteLength[$fieldarray['raw']['type']]), $ThisFileInfo['tiff']['byte_order']);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 259: // Compression
|
||||
$ThisFileInfo['video']['codec'] = $this->TIFFcompressionMethod($fieldarray['value']);
|
||||
break;
|
||||
|
||||
case 270: // ImageDescription
|
||||
case 271: // Make
|
||||
case 272: // Model
|
||||
case 305: // Software
|
||||
case 306: // DateTime
|
||||
case 315: // Artist
|
||||
case 316: // HostComputer
|
||||
$TIFFcommentName = $this->TIFFcommentName($fieldarray['raw']['tag']);
|
||||
if (isset($ThisFileInfo['tiff']['comments'][$TIFFcommentName])) {
|
||||
$ThisFileInfo['tiff']['comments'][$TIFFcommentName][] = $ThisFileInfo['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'];
|
||||
} else {
|
||||
$ThisFileInfo['tiff']['comments'][$TIFFcommentName] = array($ThisFileInfo['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data']);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function TIFFendian2Int($bytestring, $byteorder) {
|
||||
if ($byteorder == 'Intel') {
|
||||
return getid3_lib::LittleEndian2Int($bytestring);
|
||||
} elseif ($byteorder == 'Motorola') {
|
||||
return getid3_lib::BigEndian2Int($bytestring);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function TIFFcompressionMethod($id) {
|
||||
static $TIFFcompressionMethod = array();
|
||||
if (empty($TIFFcompressionMethod)) {
|
||||
$TIFFcompressionMethod = array(
|
||||
1 => 'Uncompressed',
|
||||
2 => 'Huffman',
|
||||
3 => 'Fax - CCITT 3',
|
||||
5 => 'LZW',
|
||||
32773 => 'PackBits',
|
||||
);
|
||||
}
|
||||
return (isset($TIFFcompressionMethod[$id]) ? $TIFFcompressionMethod[$id] : 'unknown/invalid ('.$id.')');
|
||||
}
|
||||
|
||||
function TIFFcommentName($id) {
|
||||
static $TIFFcommentName = array();
|
||||
if (empty($TIFFcommentName)) {
|
||||
$TIFFcommentName = array(
|
||||
270 => 'imagedescription',
|
||||
271 => 'make',
|
||||
272 => 'model',
|
||||
305 => 'software',
|
||||
306 => 'datetime',
|
||||
315 => 'artist',
|
||||
316 => 'hostcomputer',
|
||||
);
|
||||
}
|
||||
return (isset($TIFFcommentName[$id]) ? $TIFFcommentName[$id] : 'unknown/invalid ('.$id.')');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.archive.doc.php //
|
||||
// module for analyzing MS Office (.doc, .xls, etc) files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_doc
|
||||
{
|
||||
|
||||
function getid3_doc(&$fd, &$ThisFileInfo) {
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'doc';
|
||||
|
||||
$ThisFileInfo['error'][] = 'MS Office (.doc, .xls, etc) parsing not enabled in this version of getID3()';
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,59 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.misc.exe.php //
|
||||
// module for analyzing EXE files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_exe
|
||||
{
|
||||
|
||||
function getid3_exe(&$fd, &$ThisFileInfo) {
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$EXEheader = fread($fd, 28);
|
||||
|
||||
if (substr($EXEheader, 0, 2) != 'MZ') {
|
||||
$ThisFileInfo['error'][] = 'Expecting "MZ" at offset '.$ThisFileInfo['avdataoffset'].', found "'.substr($EXEheader, 0, 2).'" instead.';
|
||||
return false;
|
||||
}
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'exe';
|
||||
$ThisFileInfo['exe']['mz']['magic'] = 'MZ';
|
||||
|
||||
$ThisFileInfo['exe']['mz']['raw']['last_page_size'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 2, 2));
|
||||
$ThisFileInfo['exe']['mz']['raw']['page_count'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 4, 2));
|
||||
$ThisFileInfo['exe']['mz']['raw']['relocation_count'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 6, 2));
|
||||
$ThisFileInfo['exe']['mz']['raw']['header_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 8, 2));
|
||||
$ThisFileInfo['exe']['mz']['raw']['min_memory_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 10, 2));
|
||||
$ThisFileInfo['exe']['mz']['raw']['max_memory_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 12, 2));
|
||||
$ThisFileInfo['exe']['mz']['raw']['initial_ss'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 14, 2));
|
||||
$ThisFileInfo['exe']['mz']['raw']['initial_sp'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 16, 2));
|
||||
$ThisFileInfo['exe']['mz']['raw']['checksum'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 18, 2));
|
||||
$ThisFileInfo['exe']['mz']['raw']['cs_ip'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 20, 4));
|
||||
$ThisFileInfo['exe']['mz']['raw']['relocation_table_offset'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 24, 2));
|
||||
$ThisFileInfo['exe']['mz']['raw']['overlay_number'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 26, 2));
|
||||
|
||||
$ThisFileInfo['exe']['mz']['byte_size'] = (($ThisFileInfo['exe']['mz']['raw']['page_count'] - 1)) * 512 + $ThisFileInfo['exe']['mz']['raw']['last_page_size'];
|
||||
$ThisFileInfo['exe']['mz']['header_size'] = $ThisFileInfo['exe']['mz']['raw']['header_paragraphs'] * 16;
|
||||
$ThisFileInfo['exe']['mz']['memory_minimum'] = $ThisFileInfo['exe']['mz']['raw']['min_memory_paragraphs'] * 16;
|
||||
$ThisFileInfo['exe']['mz']['memory_recommended'] = $ThisFileInfo['exe']['mz']['raw']['max_memory_paragraphs'] * 16;
|
||||
|
||||
$ThisFileInfo['error'][] = 'EXE parsing not enabled in this version of getID3()';
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.archive.doc.php //
|
||||
// module for analyzing MS Office (.doc, .xls, etc) files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_msoffice
|
||||
{
|
||||
|
||||
function getid3_msoffice(&$fd, &$ThisFileInfo) {
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$DOCFILEheader = fread($fd, 8);
|
||||
$magic = "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1";
|
||||
if (substr($DOCFILEheader, 0, 8) != $magic) {
|
||||
$ThisFileInfo['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$ThisFileInfo['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($DOCFILEheader, 0, 8)).' instead.';
|
||||
return false;
|
||||
}
|
||||
$ThisFileInfo['fileformat'] = 'msoffice';
|
||||
|
||||
$ThisFileInfo['error'][] = 'MS Office (.doc, .xls, etc) parsing not enabled in this version of getID3() [v'.GETID3_VERSION.']';
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.misc.pdf.php //
|
||||
// module for analyzing PDF files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_pdf
|
||||
{
|
||||
|
||||
function getid3_pdf(&$fd, &$ThisFileInfo) {
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'pdf';
|
||||
|
||||
$ThisFileInfo['error'][] = 'PDF parsing not enabled in this version of getID3()';
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,332 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.tag.apetag.php //
|
||||
// module for analyzing APE tags //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
class getid3_apetag
|
||||
{
|
||||
|
||||
function getid3_apetag(&$fd, &$ThisFileInfo, $overrideendoffset=0) {
|
||||
|
||||
if (!getid3_lib::intValueSupported($ThisFileInfo['filesize'])) {
|
||||
$ThisFileInfo['warning'][] = 'Unable to check for APEtags because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
|
||||
return false;
|
||||
}
|
||||
|
||||
$id3v1tagsize = 128;
|
||||
$apetagheadersize = 32;
|
||||
$lyrics3tagsize = 10;
|
||||
|
||||
if ($overrideendoffset == 0) {
|
||||
|
||||
fseek($fd, 0 - $id3v1tagsize - $apetagheadersize - $lyrics3tagsize, SEEK_END);
|
||||
$APEfooterID3v1 = fread($fd, $id3v1tagsize + $apetagheadersize + $lyrics3tagsize);
|
||||
|
||||
//if (preg_match('/APETAGEX.{24}TAG.{125}$/i', $APEfooterID3v1)) {
|
||||
if (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $id3v1tagsize - $apetagheadersize, 8) == 'APETAGEX') {
|
||||
|
||||
// APE tag found before ID3v1
|
||||
$ThisFileInfo['ape']['tag_offset_end'] = $ThisFileInfo['filesize'] - $id3v1tagsize;
|
||||
|
||||
//} elseif (preg_match('/APETAGEX.{24}$/i', $APEfooterID3v1)) {
|
||||
} elseif (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $apetagheadersize, 8) == 'APETAGEX') {
|
||||
|
||||
// APE tag found, no ID3v1
|
||||
$ThisFileInfo['ape']['tag_offset_end'] = $ThisFileInfo['filesize'];
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
fseek($fd, $overrideendoffset - $apetagheadersize, SEEK_SET);
|
||||
if (fread($fd, 8) == 'APETAGEX') {
|
||||
$ThisFileInfo['ape']['tag_offset_end'] = $overrideendoffset;
|
||||
}
|
||||
|
||||
}
|
||||
if (!isset($ThisFileInfo['ape']['tag_offset_end'])) {
|
||||
|
||||
// APE tag not found
|
||||
unset($ThisFileInfo['ape']);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// shortcut
|
||||
$thisfile_ape = &$ThisFileInfo['ape'];
|
||||
|
||||
fseek($fd, $thisfile_ape['tag_offset_end'] - $apetagheadersize, SEEK_SET);
|
||||
$APEfooterData = fread($fd, 32);
|
||||
if (!($thisfile_ape['footer'] = $this->parseAPEheaderFooter($APEfooterData))) {
|
||||
$ThisFileInfo['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($fd, $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'] - $apetagheadersize, SEEK_SET);
|
||||
$thisfile_ape['tag_offset_start'] = ftell($fd);
|
||||
$APEtagData = fread($fd, $thisfile_ape['footer']['raw']['tagsize'] + $apetagheadersize);
|
||||
} else {
|
||||
$thisfile_ape['tag_offset_start'] = $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'];
|
||||
fseek($fd, $thisfile_ape['tag_offset_start'], SEEK_SET);
|
||||
$APEtagData = fread($fd, $thisfile_ape['footer']['raw']['tagsize']);
|
||||
}
|
||||
$ThisFileInfo['avdataend'] = $thisfile_ape['tag_offset_start'];
|
||||
|
||||
if (isset($ThisFileInfo['id3v1']['tag_offset_start']) && ($ThisFileInfo['id3v1']['tag_offset_start'] < $thisfile_ape['tag_offset_end'])) {
|
||||
$ThisFileInfo['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in APEtag data';
|
||||
unset($ThisFileInfo['id3v1']);
|
||||
foreach ($ThisFileInfo['warning'] as $key => $value) {
|
||||
if ($value == 'Some ID3v1 fields do not use NULL characters for padding') {
|
||||
unset($ThisFileInfo['warning'][$key]);
|
||||
sort($ThisFileInfo['warning']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$offset = 0;
|
||||
if (isset($thisfile_ape['footer']['flags']['header']) && $thisfile_ape['footer']['flags']['header']) {
|
||||
if ($thisfile_ape['header'] = $this->parseAPEheaderFooter(substr($APEtagData, 0, $apetagheadersize))) {
|
||||
$offset += $apetagheadersize;
|
||||
} else {
|
||||
$ThisFileInfo['error'][] = 'Error parsing APE header at offset '.$thisfile_ape['tag_offset_start'];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// shortcut
|
||||
$ThisFileInfo['replay_gain'] = array();
|
||||
$thisfile_replaygain = &$ThisFileInfo['replay_gain'];
|
||||
|
||||
for ($i = 0; $i < $thisfile_ape['footer']['raw']['tag_items']; $i++) {
|
||||
$value_size = getid3_lib::LittleEndian2Int(substr($APEtagData, $offset, 4));
|
||||
$offset += 4;
|
||||
$item_flags = getid3_lib::LittleEndian2Int(substr($APEtagData, $offset, 4));
|
||||
$offset += 4;
|
||||
if (strstr(substr($APEtagData, $offset), "\x00") === false) {
|
||||
$ThisFileInfo['error'][] = 'Cannot find null-byte (0x00) seperator between ItemKey #'.$i.' and value. ItemKey starts '.$offset.' bytes into the APE tag, at file offset '.($thisfile_ape['tag_offset_start'] + $offset);
|
||||
return false;
|
||||
}
|
||||
$ItemKeyLength = strpos($APEtagData, "\x00", $offset) - $offset;
|
||||
$item_key = strtolower(substr($APEtagData, $offset, $ItemKeyLength));
|
||||
|
||||
// shortcut
|
||||
$thisfile_ape['items'][$item_key] = array();
|
||||
$thisfile_ape_items_current = &$thisfile_ape['items'][$item_key];
|
||||
|
||||
$thisfile_ape_items_current['offset'] = $thisfile_ape['tag_offset_start'] + $offset;
|
||||
|
||||
$offset += ($ItemKeyLength + 1); // skip 0x00 terminator
|
||||
$thisfile_ape_items_current['data'] = substr($APEtagData, $offset, $value_size);
|
||||
$offset += $value_size;
|
||||
|
||||
$thisfile_ape_items_current['flags'] = $this->parseAPEtagFlags($item_flags);
|
||||
switch ($thisfile_ape_items_current['flags']['item_contents_raw']) {
|
||||
case 0: // UTF-8
|
||||
case 3: // Locator (URL, filename, etc), UTF-8 encoded
|
||||
$thisfile_ape_items_current['data'] = explode("\x00", trim($thisfile_ape_items_current['data']));
|
||||
break;
|
||||
|
||||
default: // binary data
|
||||
break;
|
||||
}
|
||||
|
||||
switch (strtolower($item_key)) {
|
||||
case 'replaygain_track_gain':
|
||||
$thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
|
||||
$thisfile_replaygain['track']['originator'] = 'unspecified';
|
||||
break;
|
||||
|
||||
case 'replaygain_track_peak':
|
||||
$thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
|
||||
$thisfile_replaygain['track']['originator'] = 'unspecified';
|
||||
if ($thisfile_replaygain['track']['peak'] <= 0) {
|
||||
$ThisFileInfo['warning'][] = 'ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'replaygain_album_gain':
|
||||
$thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
|
||||
$thisfile_replaygain['album']['originator'] = 'unspecified';
|
||||
break;
|
||||
|
||||
case 'replaygain_album_peak':
|
||||
$thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
|
||||
$thisfile_replaygain['album']['originator'] = 'unspecified';
|
||||
if ($thisfile_replaygain['album']['peak'] <= 0) {
|
||||
$ThisFileInfo['warning'][] = 'ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'mp3gain_undo':
|
||||
list($mp3gain_undo_left, $mp3gain_undo_right, $mp3gain_undo_wrap) = explode(',', $thisfile_ape_items_current['data'][0]);
|
||||
$thisfile_replaygain['mp3gain']['undo_left'] = intval($mp3gain_undo_left);
|
||||
$thisfile_replaygain['mp3gain']['undo_right'] = intval($mp3gain_undo_right);
|
||||
$thisfile_replaygain['mp3gain']['undo_wrap'] = (($mp3gain_undo_wrap == 'Y') ? true : false);
|
||||
break;
|
||||
|
||||
case 'mp3gain_minmax':
|
||||
list($mp3gain_globalgain_min, $mp3gain_globalgain_max) = explode(',', $thisfile_ape_items_current['data'][0]);
|
||||
$thisfile_replaygain['mp3gain']['globalgain_track_min'] = intval($mp3gain_globalgain_min);
|
||||
$thisfile_replaygain['mp3gain']['globalgain_track_max'] = intval($mp3gain_globalgain_max);
|
||||
break;
|
||||
|
||||
case 'mp3gain_album_minmax':
|
||||
list($mp3gain_globalgain_album_min, $mp3gain_globalgain_album_max) = explode(',', $thisfile_ape_items_current['data'][0]);
|
||||
$thisfile_replaygain['mp3gain']['globalgain_album_min'] = intval($mp3gain_globalgain_album_min);
|
||||
$thisfile_replaygain['mp3gain']['globalgain_album_max'] = intval($mp3gain_globalgain_album_max);
|
||||
break;
|
||||
|
||||
case 'tracknumber':
|
||||
if (is_array($thisfile_ape_items_current['data'])) {
|
||||
foreach ($thisfile_ape_items_current['data'] as $comment) {
|
||||
$thisfile_ape['comments']['track'][] = $comment;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'cover art (artist)':
|
||||
case 'cover art (back)':
|
||||
case 'cover art (band logo)':
|
||||
case 'cover art (band)':
|
||||
case 'cover art (colored fish)':
|
||||
case 'cover art (composer)':
|
||||
case 'cover art (conductor)':
|
||||
case 'cover art (front)':
|
||||
case 'cover art (icon)':
|
||||
case 'cover art (illustration)':
|
||||
case 'cover art (lead)':
|
||||
case 'cover art (leaflet)':
|
||||
case 'cover art (lyricist)':
|
||||
case 'cover art (media)':
|
||||
case 'cover art (movie scene)':
|
||||
case 'cover art (other icon)':
|
||||
case 'cover art (other)':
|
||||
case 'cover art (performance)':
|
||||
case 'cover art (publisher logo)':
|
||||
case 'cover art (recording)':
|
||||
case 'cover art (studio)':
|
||||
// list of possible cover arts from http://taglib-sharp.sourcearchive.com/documentation/2.0.3.0-2/Ape_2Tag_8cs-source.html
|
||||
list($thisfile_ape_items_current['filename'], $thisfile_ape_items_current['data']) = explode("\x00", $thisfile_ape_items_current['data'], 2);
|
||||
$thisfile_ape_items_current['dataoffset'] = $thisfile_ape_items_current['offset'] + strlen($thisfile_ape_items_current['filename']."\x00");
|
||||
|
||||
$thisfile_ape_items_current['image_mime'] = '';
|
||||
$imageinfo = array();
|
||||
$imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_ape_items_current['data'], $imageinfo);
|
||||
$thisfile_ape_items_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
|
||||
|
||||
if (!isset($ThisFileInfo['ape']['comments']['picture'])) {
|
||||
$ThisFileInfo['ape']['comments']['picture'] = array();
|
||||
}
|
||||
$ThisFileInfo['ape']['comments']['picture'][] = array('data'=>$thisfile_ape_items_current['data'], 'image_mime'=>$thisfile_ape_items_current['image_mime']);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (is_array($thisfile_ape_items_current['data'])) {
|
||||
foreach ($thisfile_ape_items_current['data'] as $comment) {
|
||||
$thisfile_ape['comments'][strtolower($item_key)][] = $comment;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (empty($thisfile_replaygain)) {
|
||||
unset($ThisFileInfo['replay_gain']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function parseAPEheaderFooter($APEheaderFooterData) {
|
||||
// http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html
|
||||
|
||||
// shortcut
|
||||
$headerfooterinfo['raw'] = array();
|
||||
$headerfooterinfo_raw = &$headerfooterinfo['raw'];
|
||||
|
||||
$headerfooterinfo_raw['footer_tag'] = substr($APEheaderFooterData, 0, 8);
|
||||
if ($headerfooterinfo_raw['footer_tag'] != 'APETAGEX') {
|
||||
return false;
|
||||
}
|
||||
$headerfooterinfo_raw['version'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 8, 4));
|
||||
$headerfooterinfo_raw['tagsize'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 12, 4));
|
||||
$headerfooterinfo_raw['tag_items'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 16, 4));
|
||||
$headerfooterinfo_raw['global_flags'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 20, 4));
|
||||
$headerfooterinfo_raw['reserved'] = substr($APEheaderFooterData, 24, 8);
|
||||
|
||||
$headerfooterinfo['tag_version'] = $headerfooterinfo_raw['version'] / 1000;
|
||||
if ($headerfooterinfo['tag_version'] >= 2) {
|
||||
$headerfooterinfo['flags'] = $this->parseAPEtagFlags($headerfooterinfo_raw['global_flags']);
|
||||
}
|
||||
return $headerfooterinfo;
|
||||
}
|
||||
|
||||
function parseAPEtagFlags($rawflagint) {
|
||||
// "Note: APE Tags 1.0 do not use any of the APE Tag flags.
|
||||
// All are set to zero on creation and ignored on reading."
|
||||
// http://www.uni-jena.de/~pfk/mpp/sv8/apetagflags.html
|
||||
$flags['header'] = (bool) ($rawflagint & 0x80000000);
|
||||
$flags['footer'] = (bool) ($rawflagint & 0x40000000);
|
||||
$flags['this_is_header'] = (bool) ($rawflagint & 0x20000000);
|
||||
$flags['item_contents_raw'] = ($rawflagint & 0x00000006) >> 1;
|
||||
$flags['read_only'] = (bool) ($rawflagint & 0x00000001);
|
||||
|
||||
$flags['item_contents'] = $this->APEcontentTypeFlagLookup($flags['item_contents_raw']);
|
||||
|
||||
return $flags;
|
||||
}
|
||||
|
||||
function APEcontentTypeFlagLookup($contenttypeid) {
|
||||
static $APEcontentTypeFlagLookup = array(
|
||||
0 => 'utf-8',
|
||||
1 => 'binary',
|
||||
2 => 'external',
|
||||
3 => 'reserved'
|
||||
);
|
||||
return (isset($APEcontentTypeFlagLookup[$contenttypeid]) ? $APEcontentTypeFlagLookup[$contenttypeid] : 'invalid');
|
||||
}
|
||||
|
||||
function APEtagItemIsUTF8Lookup($itemkey) {
|
||||
static $APEtagItemIsUTF8Lookup = array(
|
||||
'title',
|
||||
'subtitle',
|
||||
'artist',
|
||||
'album',
|
||||
'debut album',
|
||||
'publisher',
|
||||
'conductor',
|
||||
'track',
|
||||
'composer',
|
||||
'comment',
|
||||
'copyright',
|
||||
'publicationright',
|
||||
'file',
|
||||
'year',
|
||||
'record date',
|
||||
'record location',
|
||||
'genre',
|
||||
'media',
|
||||
'related',
|
||||
'isrc',
|
||||
'abstract',
|
||||
'language',
|
||||
'bibliography'
|
||||
);
|
||||
return in_array(strtolower($itemkey), $APEtagItemIsUTF8Lookup);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,303 +0,0 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// write.real.php //
|
||||
// module for writing RealAudio/RealVideo tags //
|
||||
// dependencies: module.tag.real.php //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
class getid3_write_real
|
||||
{
|
||||
var $filename;
|
||||
var $tag_data = array();
|
||||
var $warnings = array(); // any non-critical errors will be stored here
|
||||
var $errors = array(); // any critical errors will be stored here
|
||||
var $paddedlength = 512; // minimum length of CONT tag in bytes
|
||||
|
||||
function getid3_write_real() {
|
||||
return true;
|
||||
}
|
||||
|
||||
function WriteReal() {
|
||||
// File MUST be writeable - CHMOD(646) at least
|
||||
if (is_writeable($this->filename)) {
|
||||
ob_start();
|
||||
if ($fp_source = fopen($this->filename, 'r+b')) {
|
||||
|
||||
ob_end_clean();
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$OldThisFileInfo = $getID3->analyze($this->filename);
|
||||
if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) {
|
||||
$this->errors[] = 'Cannot write Real tags on old-style file format';
|
||||
fclose($fp_source);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($OldThisFileInfo['real']['chunks'])) {
|
||||
$this->errors[] = 'Cannot write Real tags because cannot find DATA chunk in file';
|
||||
fclose($fp_source);
|
||||
return false;
|
||||
}
|
||||
foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) {
|
||||
$oldChunkInfo[$chunkarray['name']] = $chunkarray;
|
||||
}
|
||||
if (!empty($oldChunkInfo['CONT']['length'])) {
|
||||
$this->paddedlength = max($oldChunkInfo['CONT']['length'], $this->paddedlength);
|
||||
}
|
||||
|
||||
$new_CONT_tag_data = $this->GenerateCONTchunk();
|
||||
$new_PROP_tag_data = $this->GeneratePROPchunk($OldThisFileInfo['real']['chunks'], $new_CONT_tag_data);
|
||||
$new__RMF_tag_data = $this->GenerateRMFchunk($OldThisFileInfo['real']['chunks']);
|
||||
|
||||
if (isset($oldChunkInfo['.RMF']['length']) && ($oldChunkInfo['.RMF']['length'] == strlen($new__RMF_tag_data))) {
|
||||
fseek($fp_source, $oldChunkInfo['.RMF']['offset'], SEEK_SET);
|
||||
fwrite($fp_source, $new__RMF_tag_data);
|
||||
} else {
|
||||
$this->errors[] = 'new .RMF tag ('.strlen($new__RMF_tag_data).' bytes) different length than old .RMF tag ('.$oldChunkInfo['.RMF']['length'].' bytes)';
|
||||
fclose($fp_source);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($oldChunkInfo['PROP']['length']) && ($oldChunkInfo['PROP']['length'] == strlen($new_PROP_tag_data))) {
|
||||
fseek($fp_source, $oldChunkInfo['PROP']['offset'], SEEK_SET);
|
||||
fwrite($fp_source, $new_PROP_tag_data);
|
||||
} else {
|
||||
$this->errors[] = 'new PROP tag ('.strlen($new_PROP_tag_data).' bytes) different length than old PROP tag ('.$oldChunkInfo['PROP']['length'].' bytes)';
|
||||
fclose($fp_source);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($oldChunkInfo['CONT']['length']) && ($oldChunkInfo['CONT']['length'] == strlen($new_CONT_tag_data))) {
|
||||
|
||||
// new data length is same as old data length - just overwrite
|
||||
fseek($fp_source, $oldChunkInfo['CONT']['offset'], SEEK_SET);
|
||||
fwrite($fp_source, $new_CONT_tag_data);
|
||||
fclose($fp_source);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
if (empty($oldChunkInfo['CONT'])) {
|
||||
// no existing CONT chunk
|
||||
$BeforeOffset = $oldChunkInfo['DATA']['offset'];
|
||||
$AfterOffset = $oldChunkInfo['DATA']['offset'];
|
||||
} else {
|
||||
// new data is longer than old data
|
||||
$BeforeOffset = $oldChunkInfo['CONT']['offset'];
|
||||
$AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length'];
|
||||
}
|
||||
if ($tempfilename = tempnam(GETID3_TEMP_DIR, 'getID3')) {
|
||||
ob_start();
|
||||
if ($fp_temp = fopen($tempfilename, 'wb')) {
|
||||
|
||||
rewind($fp_source);
|
||||
fwrite($fp_temp, fread($fp_source, $BeforeOffset));
|
||||
fwrite($fp_temp, $new_CONT_tag_data);
|
||||
fseek($fp_source, $AfterOffset, SEEK_SET);
|
||||
while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) {
|
||||
fwrite($fp_temp, $buffer, strlen($buffer));
|
||||
}
|
||||
fclose($fp_temp);
|
||||
|
||||
if (copy($tempfilename, $this->filename)) {
|
||||
unlink($tempfilename);
|
||||
fclose($fp_source);
|
||||
return true;
|
||||
}
|
||||
unlink($tempfilename);
|
||||
$this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.') - '.strip_tags(ob_get_contents());
|
||||
|
||||
} else {
|
||||
|
||||
$this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents());
|
||||
|
||||
}
|
||||
ob_end_clean();
|
||||
}
|
||||
fclose($fp_source);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
$errormessage = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$this->errors[] = 'File is not writeable: '.$this->filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
function GenerateRMFchunk(&$chunks) {
|
||||
$oldCONTexists = false;
|
||||
foreach ($chunks as $key => $chunk) {
|
||||
$chunkNameKeys[$chunk['name']] = $key;
|
||||
if ($chunk['name'] == 'CONT') {
|
||||
$oldCONTexists = true;
|
||||
}
|
||||
}
|
||||
$newHeadersCount = $chunks[$chunkNameKeys['.RMF']]['headers_count'] + ($oldCONTexists ? 0 : 1);
|
||||
|
||||
$RMFchunk = "\x00\x00"; // object version
|
||||
$RMFchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['.RMF']]['file_version'], 4);
|
||||
$RMFchunk .= getid3_lib::BigEndian2String($newHeadersCount, 4);
|
||||
|
||||
$RMFchunk = '.RMF'.getid3_lib::BigEndian2String(strlen($RMFchunk) + 8, 4).$RMFchunk; // .RMF chunk identifier + chunk length
|
||||
return $RMFchunk;
|
||||
}
|
||||
|
||||
function GeneratePROPchunk(&$chunks, &$new_CONT_tag_data) {
|
||||
$old_CONT_length = 0;
|
||||
$old_DATA_offset = 0;
|
||||
$old_INDX_offset = 0;
|
||||
foreach ($chunks as $key => $chunk) {
|
||||
$chunkNameKeys[$chunk['name']] = $key;
|
||||
if ($chunk['name'] == 'CONT') {
|
||||
$old_CONT_length = $chunk['length'];
|
||||
} elseif ($chunk['name'] == 'DATA') {
|
||||
if (!$old_DATA_offset) {
|
||||
$old_DATA_offset = $chunk['offset'];
|
||||
}
|
||||
} elseif ($chunk['name'] == 'INDX') {
|
||||
if (!$old_INDX_offset) {
|
||||
$old_INDX_offset = $chunk['offset'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$CONTdelta = strlen($new_CONT_tag_data) - $old_CONT_length;
|
||||
|
||||
$PROPchunk = "\x00\x00"; // object version
|
||||
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_bit_rate'], 4);
|
||||
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_bit_rate'], 4);
|
||||
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_packet_size'], 4);
|
||||
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_packet_size'], 4);
|
||||
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_packets'], 4);
|
||||
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['duration'], 4);
|
||||
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['preroll'], 4);
|
||||
$PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_INDX_offset + $CONTdelta), 4);
|
||||
$PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_DATA_offset + $CONTdelta), 4);
|
||||
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_streams'], 2);
|
||||
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['flags_raw'], 2);
|
||||
|
||||
$PROPchunk = 'PROP'.getid3_lib::BigEndian2String(strlen($PROPchunk) + 8, 4).$PROPchunk; // PROP chunk identifier + chunk length
|
||||
return $PROPchunk;
|
||||
}
|
||||
|
||||
function GenerateCONTchunk() {
|
||||
foreach ($this->tag_data as $key => $value) {
|
||||
// limit each value to 0xFFFF bytes
|
||||
$this->tag_data[$key] = substr($value, 0, 65535);
|
||||
}
|
||||
|
||||
$CONTchunk = "\x00\x00"; // object version
|
||||
|
||||
$CONTchunk .= getid3_lib::BigEndian2String((!empty($this->tag_data['title']) ? strlen($this->tag_data['title']) : 0), 2);
|
||||
$CONTchunk .= (!empty($this->tag_data['title']) ? strlen($this->tag_data['title']) : '');
|
||||
|
||||
$CONTchunk .= getid3_lib::BigEndian2String((!empty($this->tag_data['artist']) ? strlen($this->tag_data['artist']) : 0), 2);
|
||||
$CONTchunk .= (!empty($this->tag_data['artist']) ? strlen($this->tag_data['artist']) : '');
|
||||
|
||||
$CONTchunk .= getid3_lib::BigEndian2String((!empty($this->tag_data['copyright']) ? strlen($this->tag_data['copyright']) : 0), 2);
|
||||
$CONTchunk .= (!empty($this->tag_data['copyright']) ? strlen($this->tag_data['copyright']) : '');
|
||||
|
||||
$CONTchunk .= getid3_lib::BigEndian2String((!empty($this->tag_data['comment']) ? strlen($this->tag_data['comment']) : 0), 2);
|
||||
$CONTchunk .= (!empty($this->tag_data['comment']) ? strlen($this->tag_data['comment']) : '');
|
||||
|
||||
if ($this->paddedlength > (strlen($CONTchunk) + 8)) {
|
||||
$CONTchunk .= str_repeat("\x00", $this->paddedlength - strlen($CONTchunk) - 8);
|
||||
}
|
||||
|
||||
$CONTchunk = 'CONT'.getid3_lib::BigEndian2String(strlen($CONTchunk) + 8, 4).$CONTchunk; // CONT chunk identifier + chunk length
|
||||
|
||||
return $CONTchunk;
|
||||
}
|
||||
|
||||
function RemoveReal() {
|
||||
// File MUST be writeable - CHMOD(646) at least
|
||||
if (is_writeable($this->filename)) {
|
||||
ob_start();
|
||||
if ($fp_source = fopen($this->filename, 'r+b')) {
|
||||
|
||||
ob_end_clean();
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$OldThisFileInfo = $getID3->analyze($this->filename);
|
||||
if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) {
|
||||
$this->errors[] = 'Cannot remove Real tags from old-style file format';
|
||||
fclose($fp_source);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($OldThisFileInfo['real']['chunks'])) {
|
||||
$this->errors[] = 'Cannot remove Real tags because cannot find DATA chunk in file';
|
||||
fclose($fp_source);
|
||||
return false;
|
||||
}
|
||||
foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) {
|
||||
$oldChunkInfo[$chunkarray['name']] = $chunkarray;
|
||||
}
|
||||
|
||||
if (empty($oldChunkInfo['CONT'])) {
|
||||
// no existing CONT chunk
|
||||
fclose($fp_source);
|
||||
return true;
|
||||
}
|
||||
|
||||
$BeforeOffset = $oldChunkInfo['CONT']['offset'];
|
||||
$AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length'];
|
||||
if ($tempfilename = tempnam(GETID3_TEMP_DIR, 'getID3')) {
|
||||
ob_start();
|
||||
if ($fp_temp = fopen($tempfilename, 'wb')) {
|
||||
|
||||
rewind($fp_source);
|
||||
fwrite($fp_temp, fread($fp_source, $BeforeOffset));
|
||||
fseek($fp_source, $AfterOffset, SEEK_SET);
|
||||
while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) {
|
||||
fwrite($fp_temp, $buffer, strlen($buffer));
|
||||
}
|
||||
fclose($fp_temp);
|
||||
|
||||
if (copy($tempfilename, $this->filename)) {
|
||||
unlink($tempfilename);
|
||||
fclose($fp_source);
|
||||
return true;
|
||||
}
|
||||
unlink($tempfilename);
|
||||
$this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.') - '.strip_tags(ob_get_contents());
|
||||
|
||||
} else {
|
||||
|
||||
$this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents());
|
||||
|
||||
}
|
||||
ob_end_clean();
|
||||
}
|
||||
fclose($fp_source);
|
||||
return false;
|
||||
|
||||
|
||||
} else {
|
||||
$errormessage = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$this->errors[] = 'File is not writeable: '.$this->filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
617
serendipity_event_podcast/player/james-heinrich/getid3/README.md
Normal file
617
serendipity_event_podcast/player/james-heinrich/getid3/README.md
Normal file
|
@ -0,0 +1,617 @@
|
|||
getID3() by James Heinrich (<info@getid3.org>)
|
||||
===
|
||||
**Available at <http://getid3.sourceforge.net> or <https://www.getid3.org>**
|
||||
|
||||
getID3() is released under multiple licenses. You may choose from the following licenses, and use getID3 according to the terms of the license most suitable to your project.
|
||||
|
||||
**GNU GPL:**
|
||||
|
||||
* [v3](https://gnu.org/licenses/gpl.html)
|
||||
|
||||
* [v2](https://gnu.org/licenses/old-licenses/gpl-2.0.html)
|
||||
|
||||
* [v1](https://gnu.org/licenses/old-licenses/gpl-1.0.html)
|
||||
|
||||
**GNU LGPL:**
|
||||
|
||||
* [v3](https://gnu.org/licenses/lgpl.html)
|
||||
|
||||
**Mozilla MPL:**
|
||||
|
||||
* [v2](https://www.mozilla.org/MPL/2.0/)
|
||||
|
||||
**getID3 Commercial License:**
|
||||
|
||||
* [gCL](https://www.getid3.org/#gCL) (payment required)
|
||||
|
||||
* * *
|
||||
Copies of each of the above licenses are included in the `licenses/`
|
||||
directory of the getID3 distribution.
|
||||
|
||||
If you want to donate, there is a link on <https://www.getid3.org> for PayPal donations.
|
||||
|
||||
|
||||
|
||||
Quick Start
|
||||
===
|
||||
|
||||
**Q:** How can I check that getID3() works on my server/files?
|
||||
|
||||
**A:** Unzip getID3() to a directory, then access `/demos/demo.browse.php`
|
||||
|
||||
|
||||
|
||||
Support
|
||||
===
|
||||
|
||||
**Q:** I have a question, or I found a bug. What do I do?
|
||||
|
||||
**A:** The preferred method of support requests and/or bug reports is the forum at <http://support.getid3.org/>
|
||||
|
||||
|
||||
|
||||
Sourceforge Notification
|
||||
===
|
||||
|
||||
It's highly recommended that you sign up for notification from
|
||||
Sourceforge for when new versions are released. Please visit:
|
||||
<http://sourceforge.net/project/showfiles.php?group_id=55859>
|
||||
and click the little "monitor package" icon/link. If you're
|
||||
previously signed up for the mailing list, be aware that it has
|
||||
been discontinued, only the automated Sourceforge notification
|
||||
will be used from now on.
|
||||
|
||||
|
||||
|
||||
What does getID3() do?
|
||||
===
|
||||
|
||||
Reads & parses (to varying degrees):
|
||||
|
||||
+ tags:
|
||||
* APE (v1 and v2)
|
||||
* ID3v1 (& ID3v1.1)
|
||||
* ID3v2 (v2.4, v2.3, v2.2)
|
||||
* Lyrics3 (v1 & v2)
|
||||
|
||||
+ audio-lossy:
|
||||
* MP3/MP2/MP1
|
||||
* MPC / Musepack
|
||||
* Ogg (Vorbis, OggFLAC, Speex, Opus)
|
||||
* AAC / MP4
|
||||
* AC3
|
||||
* DTS
|
||||
* RealAudio
|
||||
* Speex
|
||||
* DSS
|
||||
* VQF
|
||||
|
||||
+ audio-lossless:
|
||||
* AIFF
|
||||
* AU
|
||||
* Bonk
|
||||
* CD-audio (*.cda)
|
||||
* FLAC
|
||||
* LA (Lossless Audio)
|
||||
* LiteWave
|
||||
* LPAC
|
||||
* MIDI
|
||||
* Monkey's Audio
|
||||
* OptimFROG
|
||||
* RKAU
|
||||
* Shorten
|
||||
* Tom's lossless Audio Kompressor (TAK)
|
||||
* TTA
|
||||
* VOC
|
||||
* WAV (RIFF)
|
||||
* WavPack
|
||||
|
||||
+ audio-video:
|
||||
* ASF: ASF, Windows Media Audio (WMA), Windows Media Video (WMV)
|
||||
* AVI (RIFF)
|
||||
* Flash
|
||||
* Matroska (MKV)
|
||||
* MPEG-1 / MPEG-2
|
||||
* NSV (Nullsoft Streaming Video)
|
||||
* Quicktime (including MP4)
|
||||
* RealVideo
|
||||
|
||||
+ still image:
|
||||
* BMP
|
||||
* GIF
|
||||
* JPEG
|
||||
* PNG
|
||||
* TIFF
|
||||
* SWF (Flash)
|
||||
* PhotoCD
|
||||
|
||||
+ data:
|
||||
* ISO-9660 CD-ROM image (directory structure)
|
||||
* SZIP (limited support)
|
||||
* ZIP (directory structure)
|
||||
* TAR
|
||||
* CUE
|
||||
|
||||
|
||||
+ Writes:
|
||||
* ID3v1 (& ID3v1.1)
|
||||
* ID3v2 (v2.3 & v2.4)
|
||||
* VorbisComment on OggVorbis
|
||||
* VorbisComment on FLAC (not OggFLAC)
|
||||
* APE v2
|
||||
* Lyrics3 (delete only)
|
||||
|
||||
|
||||
|
||||
Requirements
|
||||
===
|
||||
|
||||
* PHP 4.2.0 up to 5.2.x for getID3() 1.7.x (and earlier)
|
||||
* PHP 5.0.5 (or higher) for getID3() 1.8.x (and up)
|
||||
* PHP 5.0.5 (or higher) for getID3() 2.0.x (and up)
|
||||
* at least 4MB memory for PHP. 8MB or more is highly recommended.
|
||||
12MB is required with all modules loaded.
|
||||
|
||||
Installation
|
||||
===
|
||||
The preferred method is via [composer](https://getcomposer.org/). Follow the installation [instructions](https://getcomposer.org/doc/00-intro.md) if you do not already have composer installed.
|
||||
|
||||
Once composer is installed, execute the following command in your project root to install this library:
|
||||
|
||||
```
|
||||
composer require james-heinrich/getid3
|
||||
```
|
||||
|
||||
Usage
|
||||
===
|
||||
|
||||
See /demos/demo.basic.php for a very basic use of getID3() with no
|
||||
fancy output, just scanning one file.
|
||||
|
||||
See structure.txt for the returned data structure.
|
||||
|
||||
**For an example of a complete directory-browsing, file-scanning implementation of getID3(), please run /demos/demo.browse.php**
|
||||
|
||||
See /demos/demo.mysql.php for a sample recursive scanning code that
|
||||
scans every file in a given directory, and all sub-directories, stores
|
||||
the results in a database and allows various analysis / maintenance
|
||||
operations
|
||||
|
||||
To analyze remote files over HTTP or FTP you need to copy the file
|
||||
locally first before running getID3(). Your code would look something
|
||||
like this:
|
||||
|
||||
``` php
|
||||
<?php
|
||||
|
||||
// Copy remote file locally to scan with getID3()
|
||||
$remotefilename = 'http://www.example.com/filename.mp3';
|
||||
if ($fp_remote = fopen($remotefilename, 'rb')) {
|
||||
$localtempfilename = tempnam('/tmp', 'getID3');
|
||||
if ($fp_local = fopen($localtempfilename, 'wb')) {
|
||||
while ($buffer = fread($fp_remote, 8192)) {
|
||||
fwrite($fp_local, $buffer);
|
||||
}
|
||||
fclose($fp_local);
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$ThisFileInfo = $getID3->analyze($localtempfilename);
|
||||
// Delete temporary file
|
||||
unlink($localtempfilename);
|
||||
}
|
||||
fclose($fp_remote);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**See /demos/demo.write.php for how to write tags.**
|
||||
|
||||
What does the returned data structure look like?
|
||||
===
|
||||
|
||||
See structure.txt
|
||||
|
||||
It is recommended that you look at the output of
|
||||
/demos/demo.browse.php scanning the file(s) you're interested in to
|
||||
confirm what data is actually returned for any particular filetype in
|
||||
general, and your files in particular, as the actual data returned
|
||||
may vary considerably depending on what information is available in
|
||||
the file itself.
|
||||
|
||||
|
||||
|
||||
Notes
|
||||
===
|
||||
|
||||
getID3() 1.x:
|
||||
---
|
||||
If the format parser encounters a critical problem, it will return
|
||||
something in `$fileinfo['error']`, describing the encountered error. If
|
||||
a less critical error or notice is generated it will appear in
|
||||
`$fileinfo['warning']`. Both keys may contain more than one warning or
|
||||
error. If something is returned in ['error'] then the file was not
|
||||
correctly parsed and returned data may or may not be correct and/or
|
||||
complete. If something is returned in `['warning']` (and not `['error']`)
|
||||
then the data that is returned is OK - usually getID3() is reporting
|
||||
errors in the file that have been worked around due to known bugs in
|
||||
other programs. Some warnings may indicate that the data that is
|
||||
returned is OK but that some data could not be extracted due to
|
||||
errors in the file.
|
||||
|
||||
getID3() 2.x:
|
||||
---
|
||||
See above except errors are thrown (so you will only get one error).
|
||||
|
||||
Disclaimer
|
||||
===
|
||||
|
||||
getID3() has been tested on many systems, on many types of files,
|
||||
under many operating systems, and is generally believe to be stable
|
||||
and safe. That being said, there is still the chance there is an
|
||||
undiscovered and/or unfixed bug that may potentially corrupt your
|
||||
file, especially within the writing functions. By using getID3() you
|
||||
agree that it's not my fault if any of your files are corrupted.
|
||||
In fact, I'm not liable for anything :)
|
||||
|
||||
License
|
||||
===
|
||||
|
||||
GNU General Public License - see license.txt
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
FAQ:
|
||||
---
|
||||
**Q:** Can I use getID3() in my program? Do I need a commercial license?
|
||||
|
||||
**A:** You're generally free to use getID3 however you see fit. The only
|
||||
case in which you would require a commercial license is if you're
|
||||
selling your closed-source program that integrates getID3. If you
|
||||
sell your program including a copy of getID3, that's fine as long
|
||||
as you include a copy of the sourcecode when you sell it. Or you
|
||||
can distribute your code without getID3 and say "download it from
|
||||
getid3.sourceforge.net"
|
||||
|
||||
|
||||
|
||||
Why is it called "getID3()" if it does so much more than just that?
|
||||
===
|
||||
|
||||
v0.1 did in fact just do that. I don't have a copy of code that old, but I
|
||||
could essentially write it today with a one-line function:
|
||||
|
||||
``` php
|
||||
function getID3($filename) { return unpack('a3TAG/a30title/a30artist/a30album/a4year/a28comment/c1track/c1genreid', substr(file_get_contents($filename), -128)); }
|
||||
|
||||
```
|
||||
|
||||
|
||||
Future Plans
|
||||
===
|
||||
<https://www.getid3.org/phpBB3/viewforum.php?f=7>
|
||||
|
||||
* Better support for MP4 container format
|
||||
* Scan for appended ID3v2 tag at end of file per ID3v2.4 specs (Section 5.0)
|
||||
* Support for JPEG-2000 (http://www.morgan-multimedia.com/jpeg2000_overview.htm)
|
||||
* Support for MOD (mod/stm/s3m/it/xm/mtm/ult/669)
|
||||
* Support for ACE (thanks Vince)
|
||||
* Support for Ogg other than Vorbis, Speex and OggFlac (ie. Ogg+Xvid)
|
||||
* Ability to create Xing/LAME VBR header for VBR MP3s that are missing VBR header
|
||||
* Ability to "clean" ID3v2 padding (replace invalid padding with valid padding)
|
||||
* Warn if MP3s change version mid-stream (in full-scan mode)
|
||||
* check for corrupt/broken mid-file MP3 streams in histogram scan
|
||||
* Support for lossless-compression formats
|
||||
(http://www.firstpr.com.au/audiocomp/lossless/#Links)
|
||||
(http://compression.ca/act-sound.html)
|
||||
(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>)
|
||||
* http://abcavi.narod.ru/sof/abcavi/infotags.htm
|
||||
(thanks Kibi)
|
||||
* Better support for Bink video
|
||||
* http://www.hr/josip/DSP/AudioFile2.html
|
||||
* http://www.pcisys.net/~melanson/codecs/
|
||||
* Detect mp3PRO
|
||||
* Support for PSD
|
||||
* Support for JPC
|
||||
* Support for JP2
|
||||
* Support for JPX
|
||||
* Support for JB2
|
||||
* Support for IFF
|
||||
* Support for ICO
|
||||
* Support for ANI
|
||||
* 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)
|
||||
* More complete support for SWF - parsing encapsulated MP3 and/or JPEG content
|
||||
(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)
|
||||
* Support for DSS (https://www.getid3.org/phpBB3/viewtopic.php?t=171)
|
||||
* Support for SMAF (http://smaf-yamaha.com/what/demo.html)
|
||||
https://www.getid3.org/phpBB3/viewtopic.php?t=182
|
||||
* Support for AMR (https://www.getid3.org/phpBB3/viewtopic.php?t=195)
|
||||
* Support for 3gpp (https://www.getid3.org/phpBB3/viewtopic.php?t=195)
|
||||
* Support for ID4 (http://www.wackysoft.cjb.net grizlyY2KØhotmail*com)
|
||||
* Parse XML data returned in Ogg comments
|
||||
* Parse XML data from Quicktime SMIL metafiles (klausrathØmac*com)
|
||||
* ID3v2 genre string creator function
|
||||
* More complete parsing of JPG
|
||||
* Support for all old-style ASF packets
|
||||
* ASF/WMA/WMV tag writing
|
||||
* Parse declared T??? ID3v2 text information frames, where appropriate
|
||||
(thanks Christian Fritz for the idea)
|
||||
* Recognize encoder:
|
||||
http://www.guerillasoft.com/EncSpot2/index.html
|
||||
http://ff123.net/identify.html
|
||||
http://www.hydrogenaudio.org/?act=ST&f=16&t=9414
|
||||
http://www.hydrogenaudio.org/?showtopic=11785
|
||||
* Support for other OS/2 bitmap structures: Bitmap Array('BA'),
|
||||
Color Icon('CI'), Color Pointer('CP'), Icon('IC'), Pointer ('PT')
|
||||
http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm
|
||||
* Support for WavPack RAW mode
|
||||
* ASF/WMA/WMV data packet parsing
|
||||
* ID3v2FrameFlagsLookupTagAlter()
|
||||
* ID3v2FrameFlagsLookupFileAlter()
|
||||
* obey ID3v2 tag alter/preserve/discard rules
|
||||
* http://www.geocities.com/SiliconValley/Sector/9654/Softdoc/Illyrium/Aolyr.htm
|
||||
* proper checking for LINK/LNK frame validity in ID3v2 writing
|
||||
* proper checking for ASPI-TLEN frame validity in ID3v2 writing
|
||||
* proper checking for COMR frame validity in ID3v2 writing
|
||||
* http://www.geocities.co.jp/SiliconValley-Oakland/3664/index.html
|
||||
* decode GEOB ID3v2 structure as encoded by RealJukebox,
|
||||
decode NCON ID3v2 structure as encoded by MusicMatch
|
||||
(probably won't happen - the formats are proprietary)
|
||||
|
||||
|
||||
|
||||
Known Bugs/Issues in getID3() that may be fixed eventually
|
||||
===
|
||||
<https://www.getid3.org/phpBB3/viewtopic.php?t=25>
|
||||
|
||||
* Cannot determine bitrate for MPEG video with VBR video data
|
||||
(need documentation)
|
||||
* Interlace/progressive cannot be determined for MPEG video
|
||||
(need documentation)
|
||||
* MIDI playtime is sometimes inaccurate
|
||||
* AAC-RAW mode files cannot be identified
|
||||
* WavPack-RAW mode files cannot be identified
|
||||
* mp4 files report lots of "Unknown QuickTime atom type"
|
||||
(need documentation)
|
||||
* Encrypted ASF/WMA/WMV files warn about "unhandled GUID
|
||||
ASF_Content_Encryption_Object"
|
||||
* Bitrate split between audio and video cannot be calculated for
|
||||
NSV, only the total bitrate. (need documentation)
|
||||
* All Ogg formats (Vorbis, OggFLAC, Speex) are affected by the
|
||||
problem of large VorbisComments spanning multiple Ogg pages, but
|
||||
but only OggVorbis files can be processed with vorbiscomment.
|
||||
* The version of "head" supplied with Mac OS 10.2.8 (maybe other
|
||||
versions too) does only understands a single option (-n) and
|
||||
therefore fails. getID3 ignores this and returns wrong md5_data.
|
||||
|
||||
|
||||
|
||||
Known Bugs/Issues in getID3() that cannot be fixed
|
||||
---
|
||||
<https://www.getid3.org/phpBB3/viewtopic.php?t=25>
|
||||
|
||||
* 32-bit PHP installations only:
|
||||
Files larger than 2GB cannot always be parsed fully by getID3()
|
||||
due to limitations in the 32-bit PHP filesystem functions.
|
||||
NOTE: Since v1.7.8b3 there is partial support for larger-than-
|
||||
2GB files, most of which will parse OK, as long as no critical
|
||||
data is located beyond the 2GB offset.
|
||||
Known will-work:
|
||||
* all file formats on 64-bit PHP
|
||||
* ZIP (format doesn't support files >2GB)
|
||||
* FLAC (current encoders don't support files >2GB)
|
||||
Known will-not-work:
|
||||
* ID3v1 tags (always located at end-of-file)
|
||||
* Lyrics3 tags (always located at end-of-file)
|
||||
* APE tags (always located at end-of-file)
|
||||
Maybe-will-work:
|
||||
* Quicktime (will work if needed metadata is before 2GB offset,
|
||||
that is if the file has been hinted/optimized for streaming)
|
||||
* RIFF.WAV (should work fine, but gives warnings about not being
|
||||
able to parse all chunks)
|
||||
* RIFF.AVI (playtime will probably be wrong, is only based on
|
||||
"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)
|
||||
|
||||
|
||||
|
||||
Known Bugs/Issues in other programs
|
||||
---
|
||||
<https://www.getid3.org/phpBB3/viewtopic.php?t=25>
|
||||
|
||||
* Windows Media Player (up to v11) and iTunes (up to v10+) do
|
||||
not correctly handle ID3v2.3 tags with UTF-16BE+BOM
|
||||
encoding (they assume the data is UTF-16LE+BOM and either
|
||||
crash (WMP) or output Asian character set (iTunes)
|
||||
* Winamp (up to v2.80 at least) does not support ID3v2.4 tags,
|
||||
only ID3v2.3
|
||||
see: http://forums.winamp.com/showthread.php?postid=387524
|
||||
* Some versions of Helium2 (www.helium2.com) do not write
|
||||
ID3v2.4-compliant Frame Sizes, even though the tag is marked
|
||||
as ID3v2.4) (detected by getID3())
|
||||
* MP3ext V3.3.17 places a non-compliant padding string at the end
|
||||
of the ID3v2 header. This is supposedly fixed in v3.4b21 but
|
||||
only if you manually add a registry key. This fix is not yet
|
||||
confirmed. (detected by getID3())
|
||||
* CDex v1.40 (fixed by v1.50b7) writes non-compliant Ogg comment
|
||||
strings, supposed to be in the format "NAME=value" but actually
|
||||
written just "value" (detected by getID3())
|
||||
* Oggenc 0.9-rc3 flags the encoded file as ABR whether it's
|
||||
actually ABR or VBR.
|
||||
* iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably
|
||||
other versions are too) writes ID3v2.3 comment tags using a
|
||||
frame name 'COM ' which is not valid for ID3v2.3+ (it's an
|
||||
ID3v2.2-style frame name) (detected by getID3())
|
||||
* MP2enc does not encode mono CBR MP2 files properly (half speed
|
||||
sound and double playtime)
|
||||
* MP2enc does not encode mono VBR MP2 files properly (actually
|
||||
encoded as stereo)
|
||||
* tooLAME does not encode mono VBR MP2 files properly (actually
|
||||
encoded as stereo)
|
||||
* AACenc encodes files in VBR mode (actually ABR) even if CBR is
|
||||
specified
|
||||
* AAC/ADIF - bitrate_mode = cbr for vbr files
|
||||
* LAME 3.90-3.92 prepends one frame of null data (space for the
|
||||
LAME/VBR header, but it never gets written) when encoding in CBR
|
||||
mode with the DLL
|
||||
* Ahead Nero encodes TwinVQF with a DSIZ value (which is supposed
|
||||
to be the filesize in bytes) of "0" for TwinVQF v1.0 and "1" for
|
||||
TwinVQF v2.0 (detected by getID3())
|
||||
* Ahead Nero encodes TwinVQF files 1 second shorter than they
|
||||
should be
|
||||
* AAC-ADTS files are always actually encoded VBR, even if CBR mode
|
||||
is specified (the CBR-mode switches on the encoder enable ABR
|
||||
mode, not CBR as such, but it's not possible to tell the
|
||||
difference between such ABR files and true VBR)
|
||||
* STREAMINFO.audio_signature in OggFLAC is always null. "The reason
|
||||
it's like that is because there is no seeking support in
|
||||
libOggFLAC yet, so it has no way to go back and write the
|
||||
computed sum after encoding. Seeking support in Ogg FLAC is the
|
||||
#1 item for the next release." - Josh Coalson (FLAC developer)
|
||||
NOTE: getID3() will calculate md5_data in a method similar to
|
||||
other file formats, but that value cannot be compared to the
|
||||
md5_data value from FLAC data in a FLAC file format.
|
||||
* STREAMINFO.audio_signature is not calculated in FLAC v0.3.0 &
|
||||
v0.4.0 - getID3() will calculate md5_data in a method similar to
|
||||
other file formats, but that value cannot be compared to the
|
||||
md5_data value from FLAC v0.5.0+
|
||||
* RioPort (various versions including 2.0 and 3.11) tags ID3v2 with
|
||||
a WCOM frame that has no data portion
|
||||
* Earlier versions of Coolplayer adds illegal ID3 tags to Ogg Vorbis
|
||||
files, thus making them corrupt.
|
||||
* Meracl ID3 Tag Writer v1.3.4 (and older) incorrectly truncates the
|
||||
last byte of data from an MP3 file when appending a new ID3v1 tag.
|
||||
(detected by getID3())
|
||||
* Lossless-Audio files encoded with and without the -noseek switch
|
||||
do actually differ internally and therefore cannot match md5_data
|
||||
* iTunes has been known to append a new ID3v1 tag on the end of an
|
||||
existing ID3v1 tag when ID3v2 tag is also present
|
||||
(detected by getID3())
|
||||
* MediaMonkey may write a blank RGAD ID3v2 frame but put actual
|
||||
replay gain adjustments in a series of user-defined TXXX frames
|
||||
(detected and handled by getID3() since v1.9.2)
|
||||
|
||||
|
||||
|
||||
|
||||
Reference material:
|
||||
===
|
||||
|
||||
[www.id3.org](http://www.id3.org) material now mirrored at <http://id3lib.sourceforge.net/id3/>
|
||||
|
||||
* http://www.id3.org/id3v2.4.0-structure.txt
|
||||
* http://www.id3.org/id3v2.4.0-frames.txt
|
||||
* http://www.id3.org/id3v2.4.0-changes.txt
|
||||
* http://www.id3.org/id3v2.3.0.txt
|
||||
* http://www.id3.org/id3v2-00.txt
|
||||
* http://www.id3.org/mp3frame.html
|
||||
* http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html <mathewhendry@hotmail.com>
|
||||
* http://www.dv.co.yu/mpgscript/mpeghdr.htm
|
||||
* http://www.mp3-tech.org/programmer/frame_header.html
|
||||
* http://users.belgacom.net/gc247244/extra/tag.html
|
||||
* http://gabriel.mp3-tech.org/mp3infotag.html
|
||||
* http://www.id3.org/iso4217.html
|
||||
* http://www.unicode.org/Public/MAPPINGS/ISO8859/8859-1.TXT
|
||||
* http://www.xiph.org/ogg/vorbis/doc/framing.html
|
||||
* http://www.xiph.org/ogg/vorbis/doc/v-comment.html
|
||||
* http://leknor.com/code/php/class.ogg.php.txt
|
||||
* http://www.id3.org/iso639-2.html
|
||||
* http://www.id3.org/lyrics3.html
|
||||
* http://www.id3.org/lyrics3200.html
|
||||
* http://www.psc.edu/general/software/packages/ieee/ieee.html
|
||||
* http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
|
||||
* http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
|
||||
* http://www.jmcgowan.com/avi.html
|
||||
* http://www.wotsit.org/
|
||||
* http://www.herdsoft.com/ti/davincie/davp3xo2.htm
|
||||
* http://www.mathdogs.com/vorbis-illuminated/bitstream-appendix.html
|
||||
* "Standard MIDI File Format" by Dustin Caldwell (from www.wotsit.org)
|
||||
* http://midistudio.com/Help/GMSpecs_Patches.htm
|
||||
* http://www.xiph.org/archives/vorbis/200109/0459.html
|
||||
* http://www.replaygain.org/
|
||||
* http://www.lossless-audio.com/
|
||||
* http://download.microsoft.com/download/winmediatech40/Doc/1.0/WIN98MeXP/EN-US/ASF_Specification_v.1.0.exe
|
||||
* http://mediaxw.sourceforge.net/files/doc/Active%20Streaming%20Format%20(ASF)%201.0%20Specification.pdf
|
||||
* http://www.uni-jena.de/~pfk/mpp/sv8/ (archived at http://www.hydrogenaudio.org/musepack/klemm/www.personal.uni-jena.de/~pfk/mpp/sv8/)
|
||||
* http://jfaul.de/atl/
|
||||
* http://www.uni-jena.de/~pfk/mpp/ (archived at http://www.hydrogenaudio.org/musepack/klemm/www.personal.uni-jena.de/~pfk/mpp/)
|
||||
* http://www.libpng.org/pub/png/spec/png-1.2-pdg.html
|
||||
* http://www.real.com/devzone/library/creating/rmsdk/doc/rmff.htm
|
||||
* http://www.fastgraph.com/help/bmp_os2_header_format.html
|
||||
* http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm
|
||||
* http://flac.sourceforge.net/format.html
|
||||
* http://www.research.att.com/projects/mpegaudio/mpeg2.html
|
||||
* http://www.audiocoding.com/wiki/index.php?page=AAC
|
||||
* http://libmpeg.org/mpeg4/doc/w2203tfs.pdf
|
||||
* http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
|
||||
* http://developer.apple.com/techpubs/quicktime/qtdevdocs/RM/frameset.htm
|
||||
* http://www.nullsoft.com/nsv/
|
||||
* http://www.wotsit.org/download.asp?f=iso9660
|
||||
* http://sandbox.mc.edu/~bennet/cs110/tc/tctod.html
|
||||
* http://www.cdroller.com/htm/readdata.html
|
||||
* http://www.speex.org/manual/node10.html
|
||||
* http://www.harmony-central.com/Computer/Programming/aiff-file-format.doc
|
||||
* http://www.faqs.org/rfcs/rfc2361.html
|
||||
* http://ghido.shelter.ro/
|
||||
* http://www.ebu.ch/tech_t3285.pdf
|
||||
* http://www.sr.se/utveckling/tu/bwf
|
||||
* http://ftp.aessc.org/pub/aes46-2002.pdf
|
||||
* http://cartchunk.org:8080/
|
||||
* http://www.broadcastpapers.com/radio/cartchunk01.htm
|
||||
* http://www.hr/josip/DSP/AudioFile2.html
|
||||
* http://home.attbi.com/~chris.bagwell/AudioFormats-11.html
|
||||
* http://www.pure-mac.com/extkey.html
|
||||
* http://cesnet.dl.sourceforge.net/sourceforge/bonkenc/bonk-binary-format-0.9.txt
|
||||
* http://www.headbands.com/gspot/
|
||||
* http://www.openswf.org/spec/SWFfileformat.html
|
||||
* http://j-faul.virtualave.net/
|
||||
* http://www.btinternet.com/~AnthonyJ/Atari/programming/avr_format.html
|
||||
* http://cui.unige.ch/OSG/info/AudioFormats/ap11.html
|
||||
* http://sswf.sourceforge.net/SWFalexref.html
|
||||
* http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
|
||||
* http://www-lehre.informatik.uni-osnabrueck.de/~fbstark/diplom/docs/swf/Flash_Uncovered.htm
|
||||
* http://developer.apple.com/quicktime/icefloe/dispatch012.html
|
||||
* http://www.csdn.net/Dev/Format/graphics/PCD.htm
|
||||
* http://tta.iszf.irk.ru/
|
||||
* http://www.atsc.org/standards/a_52a.pdf
|
||||
* http://www.alanwood.net/unicode/
|
||||
* http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html
|
||||
* http://www.its.msstate.edu/net/real/reports/config/tags.stats
|
||||
* http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt
|
||||
* http://brennan.young.net/Comp/LiveStage/things.html
|
||||
* http://www.multiweb.cz/twoinches/MP3inside.htm
|
||||
* http://www.geocities.co.jp/SiliconValley-Oakland/3664/alittle.html#GenreExtended
|
||||
* http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/
|
||||
* http://www.unicode.org/unicode/faq/utf_bom.html
|
||||
* http://tta.corecodec.org/?menu=format
|
||||
* http://www.scvi.net/nsvformat.htm
|
||||
* http://pda.etsi.org/pda/queryform.asp
|
||||
* http://cpansearch.perl.org/src/RGIBSON/Audio-DSS-0.02/lib/Audio/DSS.pm
|
||||
* http://trac.musepack.net/trac/wiki/SV8Specification
|
||||
* http://wyday.com/cuesharp/specification.php
|
||||
* http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
|
||||
* http://wiki.hydrogenaud.io/index.php?title=TAK
|
3034
serendipity_event_podcast/player/james-heinrich/getid3/changelog.txt
Normal file
3034
serendipity_event_podcast/player/james-heinrich/getid3/changelog.txt
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,316 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// /demo/demo.audioinfo.class.php - part of getID3() //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP version 4.1.0 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Placed in public domain by Allan Hansen, 2002. Share and enjoy! |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | /demo/demo.audioinfo.class.php |
|
||||
// | |
|
||||
// | Example wrapper class to extract information from audio files |
|
||||
// | through getID3(). |
|
||||
// | |
|
||||
// | getID3() returns a lot of information. Much of this information is |
|
||||
// | not needed for the end-application. It is also possible that some |
|
||||
// | users want to extract specific info. Modifying getID3() files is a |
|
||||
// | bad idea, as modifications needs to be done to future versions of |
|
||||
// | getID3(). |
|
||||
// | |
|
||||
// | Modify this wrapper class instead. This example extracts certain |
|
||||
// | fields only and adds a new root value - encoder_options if possible. |
|
||||
// | It also checks for mp3 files with wave headers. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Example code: |
|
||||
// | $au = new AudioInfo(); |
|
||||
// | print_r($au->Info('file.flac'); |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Authors: Allan Hansen <ahØartemis*dk> |
|
||||
// +----------------------------------------------------------------------+
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* getID3() settings
|
||||
*/
|
||||
|
||||
require_once('../getid3/getid3.php');
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for extracting information from audio files with getID3().
|
||||
*/
|
||||
|
||||
class AudioInfo {
|
||||
|
||||
/**
|
||||
* Private variables
|
||||
*/
|
||||
private $result;
|
||||
private $info;
|
||||
private $getID3;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
||||
function __construct() {
|
||||
|
||||
// Initialize getID3 engine
|
||||
$this->getID3 = new getID3;
|
||||
$this->getID3->option_md5_data = true;
|
||||
$this->getID3->option_md5_data_source = true;
|
||||
$this->getID3->encoding = 'UTF-8';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Extract information - only public function
|
||||
*
|
||||
* @param string $file Audio file to extract info from.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
||||
public function Info($file) {
|
||||
|
||||
// Analyze file
|
||||
$this->info = $this->getID3->analyze($file);
|
||||
|
||||
// Exit here on error
|
||||
if (isset($this->info['error'])) {
|
||||
return array ('error' => $this->info['error']);
|
||||
}
|
||||
|
||||
// Init wrapper object
|
||||
$this->result = array();
|
||||
$this->result['format_name'] = (isset($this->info['fileformat']) ? $this->info['fileformat'] : '').'/'.(isset($this->info['audio']['dataformat']) ? $this->info['audio']['dataformat'] : '').(isset($this->info['video']['dataformat']) ? '/'.$this->info['video']['dataformat'] : '');
|
||||
$this->result['encoder_version'] = (isset($this->info['audio']['encoder']) ? $this->info['audio']['encoder'] : '');
|
||||
$this->result['encoder_options'] = (isset($this->info['audio']['encoder_options']) ? $this->info['audio']['encoder_options'] : '');
|
||||
$this->result['bitrate_mode'] = (isset($this->info['audio']['bitrate_mode']) ? $this->info['audio']['bitrate_mode'] : '');
|
||||
$this->result['channels'] = (isset($this->info['audio']['channels']) ? $this->info['audio']['channels'] : '');
|
||||
$this->result['sample_rate'] = (isset($this->info['audio']['sample_rate']) ? $this->info['audio']['sample_rate'] : '');
|
||||
$this->result['bits_per_sample'] = (isset($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : '');
|
||||
$this->result['playing_time'] = (isset($this->info['playtime_seconds']) ? $this->info['playtime_seconds'] : '');
|
||||
$this->result['avg_bit_rate'] = (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : '');
|
||||
$this->result['tags'] = (isset($this->info['tags']) ? $this->info['tags'] : '');
|
||||
$this->result['comments'] = (isset($this->info['comments']) ? $this->info['comments'] : '');
|
||||
$this->result['warning'] = (isset($this->info['warning']) ? $this->info['warning'] : '');
|
||||
$this->result['md5'] = (isset($this->info['md5_data']) ? $this->info['md5_data'] : '');
|
||||
|
||||
// Post getID3() data handling based on file format
|
||||
$method = (isset($this->info['fileformat']) ? $this->info['fileformat'] : '').'Info';
|
||||
if ($method && method_exists($this, $method)) {
|
||||
$this->$method();
|
||||
}
|
||||
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* post-getID3() data handling for AAC files.
|
||||
*
|
||||
*/
|
||||
|
||||
private function aacInfo() {
|
||||
$this->result['format_name'] = 'AAC';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* post-getID3() data handling for Wave files.
|
||||
*
|
||||
*/
|
||||
|
||||
private function riffInfo() {
|
||||
if ($this->info['audio']['dataformat'] == 'wav') {
|
||||
|
||||
$this->result['format_name'] = 'Wave';
|
||||
|
||||
} elseif (preg_match('#^mp[1-3]$#', $this->info['audio']['dataformat'])) {
|
||||
|
||||
$this->result['format_name'] = strtoupper($this->info['audio']['dataformat']);
|
||||
|
||||
} else {
|
||||
|
||||
$this->result['format_name'] = 'riff/'.$this->info['audio']['dataformat'];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* * post-getID3() data handling for FLAC files.
|
||||
*
|
||||
*/
|
||||
|
||||
private function flacInfo() {
|
||||
$this->result['format_name'] = 'FLAC';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* post-getID3() data handling for Monkey's Audio files.
|
||||
*
|
||||
*/
|
||||
|
||||
private function macInfo() {
|
||||
$this->result['format_name'] = 'Monkey\'s Audio';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* post-getID3() data handling for Lossless Audio files.
|
||||
*/
|
||||
private function laInfo() {
|
||||
$this->result['format_name'] = 'La';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* post-getID3() data handling for Ogg Vorbis files.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
|
||||
function oggInfo() {
|
||||
if ($this->info['audio']['dataformat'] == 'vorbis') {
|
||||
|
||||
$this->result['format_name'] = 'Ogg Vorbis';
|
||||
|
||||
} else if ($this->info['audio']['dataformat'] == 'flac') {
|
||||
|
||||
$this->result['format_name'] = 'Ogg FLAC';
|
||||
|
||||
} else if ($this->info['audio']['dataformat'] == 'speex') {
|
||||
|
||||
$this->result['format_name'] = 'Ogg Speex';
|
||||
|
||||
} else {
|
||||
|
||||
$this->result['format_name'] = 'Ogg '.$this->info['audio']['dataformat'];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* post-getID3() data handling for Musepack files.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
|
||||
function mpcInfo() {
|
||||
$this->result['format_name'] = 'Musepack';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* post-getID3() data handling for MPEG files.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
|
||||
function mp3Info() {
|
||||
$this->result['format_name'] = 'MP3';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* post-getID3() data handling for MPEG files.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
|
||||
function mp2Info() {
|
||||
$this->result['format_name'] = 'MP2';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* post-getID3() data handling for MPEG files.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
|
||||
function mp1Info() {
|
||||
$this->result['format_name'] = 'MP1';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* post-getID3() data handling for WMA files.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
|
||||
function asfInfo() {
|
||||
$this->result['format_name'] = strtoupper($this->info['audio']['dataformat']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* post-getID3() data handling for Real files.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
|
||||
function realInfo() {
|
||||
$this->result['format_name'] = 'Real';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* post-getID3() data handling for VQF files.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
|
||||
function vqfInfo() {
|
||||
$this->result['format_name'] = 'VQF';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// /demo/demo.basic.php - part of getID3() //
|
||||
// Sample script showing most basic use of getID3() //
|
||||
// see readme.txt for more details //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
die('For security reasons, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in demos/'.basename(__FILE__));
|
||||
|
||||
|
||||
// include getID3() library (can be in a different directory if full path is specified)
|
||||
require_once('../getid3/getid3.php');
|
||||
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
|
||||
// Analyze file and store returned data in $ThisFileInfo
|
||||
$ThisFileInfo = $getID3->analyze($filename);
|
||||
|
||||
/*
|
||||
Optional: copies data from all subarrays of [tags] into [comments] so
|
||||
metadata is all available in one location for all tag formats
|
||||
metainformation is always available under [tags] even if this is not called
|
||||
*/
|
||||
$getID3->CopyTagsToComments($ThisFileInfo);
|
||||
|
||||
/*
|
||||
Output desired information in whatever format you want
|
||||
Note: all entries in [comments] or [tags] are arrays of strings
|
||||
See structure.txt for information on what information is available where
|
||||
or check out the output of /demos/demo.browse.php for a particular file
|
||||
to see the full detail of what information is returned where in the array
|
||||
Note: all array keys may not always exist, you may want to check with isset()
|
||||
or empty() before deciding what to output
|
||||
*/
|
||||
|
||||
//echo $ThisFileInfo['comments_html']['artist'][0]; // artist from any/all available tag formats
|
||||
//echo $ThisFileInfo['tags']['id3v2']['title'][0]; // title from ID3v2
|
||||
//echo $ThisFileInfo['audio']['bitrate']; // audio bitrate
|
||||
//echo $ThisFileInfo['playtime_string']; // playtime in minutes:seconds, formatted string
|
||||
|
||||
/* if you want to see all the tag data (from all tag formats), uncomment this line: */
|
||||
//echo '<pre>'.htmlentities(print_r($ThisFileInfo['comments'], true), ENT_SUBSTITUTE).'</pre>';
|
||||
|
||||
/* if you want to see ALL the output, uncomment this line: */
|
||||
//echo '<pre>'.htmlentities(print_r($ThisFileInfo, true), ENT_SUBSTITUTE).'</pre>';
|
||||
|
||||
|
|
@ -0,0 +1,622 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// /demo/demo.browse.php - part of getID3() //
|
||||
// Sample script for browsing/scanning files and displaying //
|
||||
// information returned by getID3() //
|
||||
// see readme.txt for more details //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
die('For security reasons, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in demos/'.basename(__FILE__));
|
||||
|
||||
|
||||
define('GETID3_DEMO_BROWSE_ALLOW_EDIT_LINK', false); // if enabled, shows "edit" links (to /demos/demo.write.php) to allow ID3/APE/etc tag editing on applicable file types
|
||||
define('GETID3_DEMO_BROWSE_ALLOW_DELETE_LINK', false); // if enabled, shows "delete" links to delete files from the browse interface
|
||||
define('GETID3_DEMO_BROWSE_ALLOW_MD5_LINK', false); // if enabled, shows "enable" link for MD5 hashes for file/data/source
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// die if magic_quotes_runtime or magic_quotes_gpc are set
|
||||
if (version_compare(PHP_VERSION, '7.4.0', '<')) { // get_magic_quotes_runtime / get_magic_quotes_gpc functions give deprecation warnings in PHP v7.4
|
||||
if (function_exists('get_magic_quotes_runtime') && get_magic_quotes_runtime()) {
|
||||
die('magic_quotes_runtime is enabled, getID3 will not run.');
|
||||
}
|
||||
if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
|
||||
die('magic_quotes_gpc is enabled, getID3 will not run.');
|
||||
}
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
require_once('../getid3/getid3.php');
|
||||
|
||||
$PageEncoding = 'UTF-8';
|
||||
$FileSystemEncoding = ((GETID3_OS_ISWINDOWS && version_compare(PHP_VERSION, '7.1.0', '<')) ? 'Windows-1252' : 'UTF-8');
|
||||
$writescriptfilename = 'demo.write.php';
|
||||
|
||||
// Needed for windows only. Leave commented-out to auto-detect, only define here if auto-detection does not work properly
|
||||
//define('GETID3_HELPERAPPSDIR', 'C:\\helperapps\\');
|
||||
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$getID3->setOption(array(
|
||||
'encoding' => $PageEncoding,
|
||||
'options_audiovideo_quicktime_ReturnAtomData' => true,
|
||||
));
|
||||
|
||||
$getID3checkColor_Head = 'CCCCDD';
|
||||
$getID3checkColor_DirectoryLight = 'FFCCCC';
|
||||
$getID3checkColor_DirectoryDark = 'EEBBBB';
|
||||
$getID3checkColor_FileLight = 'EEEEEE';
|
||||
$getID3checkColor_FileDark = 'DDDDDD';
|
||||
$getID3checkColor_UnknownLight = 'CCCCFF';
|
||||
$getID3checkColor_UnknownDark = 'BBBBDD';
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
header('Content-Type: text/html; charset='.$PageEncoding);
|
||||
echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">';
|
||||
echo '<html><head>';
|
||||
echo '<title>getID3() - /demo/demo.browse.php (sample script)</title>';
|
||||
echo '<link rel="stylesheet" href="getid3.css" type="text/css">';
|
||||
echo '<meta http-equiv="Content-Type" content="text/html;charset='.$PageEncoding.'" />';
|
||||
echo '</head><body>';
|
||||
|
||||
if (isset($_REQUEST['deletefile']) && GETID3_DEMO_BROWSE_ALLOW_DELETE_LINK) {
|
||||
if (file_exists($_REQUEST['deletefile'])) {
|
||||
if (unlink($_REQUEST['deletefile'])) {
|
||||
$deletefilemessage = 'Successfully deleted '.$_REQUEST['deletefile'];
|
||||
} else {
|
||||
$deletefilemessage = 'FAILED to delete '.$_REQUEST['deletefile'].' - error deleting file';
|
||||
}
|
||||
} else {
|
||||
$deletefilemessage = 'FAILED to delete '.$_REQUEST['deletefile'].' - file does not exist';
|
||||
}
|
||||
if (isset($_REQUEST['noalert'])) {
|
||||
echo '<span style="font-weight: bold; color: #'.(($deletefilemessage[0] == 'F') ? 'FF0000' : '008000').';">'.htmlentities($deletefilemessage, ENT_QUOTES).'</span><hr>';
|
||||
} else {
|
||||
echo '<script type="text/javascript">alert("'.addslashes($deletefilemessage).'");</script>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isset($_REQUEST['filename'])) {
|
||||
|
||||
if (!file_exists($_REQUEST['filename']) || !is_file($_REQUEST['filename'])) {
|
||||
die(getid3_lib::iconv_fallback($FileSystemEncoding, $PageEncoding, $_REQUEST['filename'].' does not exist'));
|
||||
}
|
||||
$starttime = microtime(true);
|
||||
|
||||
//$getID3->setOption(array(
|
||||
// 'option_md5_data' => $AutoGetHashes,
|
||||
// 'option_sha1_data' => $AutoGetHashes,
|
||||
//));
|
||||
$ThisFileInfo = $getID3->analyze($_REQUEST['filename']);
|
||||
$AutoGetHashes = (bool) (isset($ThisFileInfo['filesize']) && ($ThisFileInfo['filesize'] > 0) && ($ThisFileInfo['filesize'] < (50 * 1048576))); // auto-get md5_data, md5_file, sha1_data, sha1_file if filesize < 50MB, and NOT zero (which may indicate a file>2GB)
|
||||
$AutoGetHashes = ($AutoGetHashes && GETID3_DEMO_BROWSE_ALLOW_MD5_LINK);
|
||||
if ($AutoGetHashes) {
|
||||
$ThisFileInfo['md5_file'] = md5_file($_REQUEST['filename']);
|
||||
$ThisFileInfo['sha1_file'] = sha1_file($_REQUEST['filename']);
|
||||
}
|
||||
|
||||
|
||||
$getID3->CopyTagsToComments($ThisFileInfo);
|
||||
|
||||
$listdirectory = dirname($_REQUEST['filename']);
|
||||
$listdirectory = realpath($listdirectory); // get rid of /../../ references
|
||||
|
||||
if (GETID3_OS_ISWINDOWS) {
|
||||
// this mostly just gives a consistant look to Windows and *nix filesystems
|
||||
// (windows uses \ as directory seperator, *nix uses /)
|
||||
$listdirectory = str_replace(DIRECTORY_SEPARATOR, '/', $listdirectory.'/');
|
||||
}
|
||||
|
||||
if (preg_match('#^(ht|f)tp://#', $_REQUEST['filename'])) {
|
||||
echo '<i>Cannot browse remote filesystems</i><br>';
|
||||
} else {
|
||||
echo 'Browse: <a href="'.htmlentities($_SERVER['PHP_SELF'].'?listdirectory='.urlencode($listdirectory), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">'.getid3_lib::iconv_fallback($FileSystemEncoding, $PageEncoding, $listdirectory).'</a><br>';
|
||||
}
|
||||
|
||||
getid3_lib::ksort_recursive($ThisFileInfo);
|
||||
echo table_var_dump($ThisFileInfo, false, $PageEncoding);
|
||||
$endtime = microtime(true);
|
||||
echo 'File parsed in '.number_format($endtime - $starttime, 3).' seconds.<br>';
|
||||
|
||||
} else {
|
||||
|
||||
$listdirectory = (isset($_REQUEST['listdirectory']) ? $_REQUEST['listdirectory'] : '.');
|
||||
$listdirectory = getid3_lib::truepath($listdirectory); // get rid of /../../ references
|
||||
$currentfulldir = str_replace(DIRECTORY_SEPARATOR, '/', $listdirectory).'/'; // this mostly just gives a consistant look to Windows and *nix filesystems: (Windows uses \ as directory seperator, *nix uses /)
|
||||
|
||||
ob_start();
|
||||
if ($handle = opendir($listdirectory)) {
|
||||
|
||||
ob_end_clean();
|
||||
echo str_repeat(' ', 300); // IE buffers the first 300 or so chars, making this progressive display useless - fill the buffer with spaces
|
||||
echo 'Processing';
|
||||
|
||||
$starttime = microtime(true);
|
||||
|
||||
$TotalScannedUnknownFiles = 0;
|
||||
$TotalScannedKnownFiles = 0;
|
||||
$TotalScannedPlaytimeFiles = 0;
|
||||
$TotalScannedBitrateFiles = 0;
|
||||
$TotalScannedFilesize = 0;
|
||||
$TotalScannedPlaytime = 0;
|
||||
$TotalScannedBitrate = 0;
|
||||
$FilesWithWarnings = 0;
|
||||
$FilesWithErrors = 0;
|
||||
|
||||
while ($file = readdir($handle)) {
|
||||
$currentfilename = $listdirectory.'/'.$file;
|
||||
set_time_limit(30); // allocate another 30 seconds to process this file - should go much quicker than this unless intense processing (like bitrate histogram analysis) is enabled
|
||||
echo ' <span title="'.htmlentities($file, ENT_QUOTES).'">.</span>'; // progress indicator dot
|
||||
flush(); // make sure the dot is shown, otherwise it's useless
|
||||
switch ($file) {
|
||||
case '..':
|
||||
$ParentDir = realpath($file.'/..').'/';
|
||||
if (GETID3_OS_ISWINDOWS) {
|
||||
$ParentDir = str_replace(DIRECTORY_SEPARATOR, '/', $ParentDir);
|
||||
}
|
||||
$DirectoryContents[$currentfulldir]['dir'][$file]['filename'] = $ParentDir;
|
||||
continue 2;
|
||||
break;
|
||||
|
||||
case '.':
|
||||
// ignore
|
||||
continue 2;
|
||||
break;
|
||||
}
|
||||
// symbolic-link-resolution enhancements by davidbullock״ech-center*com
|
||||
$TargetObject = realpath($currentfilename); // Find actual file path, resolve if it's a symbolic link
|
||||
$TargetObjectType = filetype($TargetObject); // Check file type without examining extension
|
||||
|
||||
if ($TargetObjectType == 'dir') {
|
||||
|
||||
$DirectoryContents[$currentfulldir]['dir'][$file]['filename'] = $file;
|
||||
|
||||
} elseif ($TargetObjectType == 'file') {
|
||||
|
||||
$getID3->setOption(array('option_md5_data' => (isset($_REQUEST['ShowMD5']) && GETID3_DEMO_BROWSE_ALLOW_MD5_LINK)));
|
||||
$fileinformation = $getID3->analyze($currentfilename);
|
||||
|
||||
$getID3->CopyTagsToComments($fileinformation);
|
||||
|
||||
$TotalScannedFilesize += (isset($fileinformation['filesize']) ? $fileinformation['filesize'] : 0);
|
||||
|
||||
if (isset($_REQUEST['ShowMD5']) && GETID3_DEMO_BROWSE_ALLOW_MD5_LINK) {
|
||||
$fileinformation['md5_file'] = md5_file($currentfilename);
|
||||
}
|
||||
|
||||
if (!empty($fileinformation['fileformat'])) {
|
||||
$DirectoryContents[$currentfulldir]['known'][$file] = $fileinformation;
|
||||
$TotalScannedPlaytime += (isset($fileinformation['playtime_seconds']) ? $fileinformation['playtime_seconds'] : 0);
|
||||
$TotalScannedBitrate += (isset($fileinformation['bitrate']) ? $fileinformation['bitrate'] : 0);
|
||||
$TotalScannedKnownFiles++;
|
||||
} else {
|
||||
$DirectoryContents[$currentfulldir]['other'][$file] = $fileinformation;
|
||||
$DirectoryContents[$currentfulldir]['other'][$file]['playtime_string'] = '-';
|
||||
$TotalScannedUnknownFiles++;
|
||||
}
|
||||
if (isset($fileinformation['playtime_seconds']) && ($fileinformation['playtime_seconds'] > 0)) {
|
||||
$TotalScannedPlaytimeFiles++;
|
||||
}
|
||||
if (isset($fileinformation['bitrate']) && ($fileinformation['bitrate'] > 0)) {
|
||||
$TotalScannedBitrateFiles++;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
echo '<div style="color: red;">Unknown filesystem entry: "'.htmlentities($currentfilename, ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'"</div>';
|
||||
|
||||
}
|
||||
}
|
||||
$endtime = microtime(true);
|
||||
closedir($handle);
|
||||
echo 'done<br>';
|
||||
echo 'Directory scanned in '.number_format($endtime - $starttime, 2).' seconds.<br>';
|
||||
flush();
|
||||
|
||||
$columnsintable = 14;
|
||||
echo '<table class="table" cellspacing="0" cellpadding="3">';
|
||||
|
||||
echo '<tr bgcolor="#'.$getID3checkColor_Head.'"><th colspan="'.$columnsintable.'">Files in '.getid3_lib::iconv_fallback($FileSystemEncoding, $PageEncoding, $currentfulldir).'</th></tr>';
|
||||
$rowcounter = 0;
|
||||
foreach ($DirectoryContents as $dirname => $val) {
|
||||
if (isset($DirectoryContents[$dirname]['dir']) && is_array($DirectoryContents[$dirname]['dir'])) {
|
||||
uksort($DirectoryContents[$dirname]['dir'], 'MoreNaturalSort');
|
||||
foreach ($DirectoryContents[$dirname]['dir'] as $filename => $fileinfo) {
|
||||
echo '<tr bgcolor="#'.(($rowcounter++ % 2) ? $getID3checkColor_DirectoryLight : $getID3checkColor_DirectoryDark).'">';
|
||||
if ($filename == '..') {
|
||||
echo '<td colspan="'.$columnsintable.'">';
|
||||
echo '<form action="'.htmlentities($_SERVER['PHP_SELF'], ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'" method="get">';
|
||||
echo 'Parent directory: ';
|
||||
echo '<input type="text" name="listdirectory" size="50" style="background-color: '.$getID3checkColor_DirectoryDark.';" value="';
|
||||
if (GETID3_OS_ISWINDOWS) {
|
||||
echo htmlentities(str_replace(DIRECTORY_SEPARATOR, '/', realpath($dirname.$filename)), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding);
|
||||
} else {
|
||||
echo htmlentities(realpath($dirname.$filename), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding);
|
||||
}
|
||||
echo '"> <input type="submit" value="Go">';
|
||||
echo '</form></td>';
|
||||
} else {
|
||||
$escaped_filename = htmlentities($filename, ENT_SUBSTITUTE, $FileSystemEncoding); // do filesystems always return filenames in ISO-8859-1?
|
||||
$escaped_filename = ($escaped_filename ? $escaped_filename : rawurlencode($filename));
|
||||
echo '<td colspan="'.$columnsintable.'"><a href="'.htmlentities($_SERVER['PHP_SELF'].'?listdirectory='.urlencode($dirname.$filename), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'"><b>'.$escaped_filename.'</b></a></td>';
|
||||
}
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '<tr bgcolor="#'.$getID3checkColor_Head.'">';
|
||||
echo '<th>Filename</th>';
|
||||
echo '<th>File Size</th>';
|
||||
echo '<th>Format</th>';
|
||||
echo '<th>Playtime</th>';
|
||||
echo '<th>Bitrate</th>';
|
||||
echo '<th>Artist</th>';
|
||||
echo '<th>Title</th>';
|
||||
if (isset($_REQUEST['ShowMD5']) && GETID3_DEMO_BROWSE_ALLOW_MD5_LINK) {
|
||||
echo '<th>MD5 File (File) (<a href="'.htmlentities($_SERVER['PHP_SELF'].'?listdirectory='.rawurlencode(isset($_REQUEST['listdirectory']) ? $_REQUEST['listdirectory'] : '.'), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">disable</a>)</th>';
|
||||
echo '<th>MD5 Data (File) (<a href="'.htmlentities($_SERVER['PHP_SELF'].'?listdirectory='.rawurlencode(isset($_REQUEST['listdirectory']) ? $_REQUEST['listdirectory'] : '.'), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">disable</a>)</th>';
|
||||
echo '<th>MD5 Data (Source) (<a href="'.htmlentities($_SERVER['PHP_SELF'].'?listdirectory='.rawurlencode(isset($_REQUEST['listdirectory']) ? $_REQUEST['listdirectory'] : '.'), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">disable</a>)</th>';
|
||||
} else {
|
||||
echo '<th colspan="3">MD5 Data'.(GETID3_DEMO_BROWSE_ALLOW_MD5_LINK ?' (<a href="'.htmlentities($_SERVER['PHP_SELF'].'?listdirectory='.rawurlencode(isset($_REQUEST['listdirectory']) ? $_REQUEST['listdirectory'] : '.').'&ShowMD5=1', ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">enable</a>)' : '').'</th>';
|
||||
}
|
||||
echo '<th>Tags</th>';
|
||||
echo '<th>Errors & Warnings</th>';
|
||||
echo (GETID3_DEMO_BROWSE_ALLOW_EDIT_LINK ? '<th>Edit</th>' : '');
|
||||
echo (GETID3_DEMO_BROWSE_ALLOW_DELETE_LINK ? '<th>Delete</th>' : '');
|
||||
echo '</tr>';
|
||||
|
||||
if (isset($DirectoryContents[$dirname]['known']) && is_array($DirectoryContents[$dirname]['known'])) {
|
||||
uksort($DirectoryContents[$dirname]['known'], 'MoreNaturalSort');
|
||||
foreach ($DirectoryContents[$dirname]['known'] as $filename => $fileinfo) {
|
||||
echo '<tr bgcolor="#'.(($rowcounter++ % 2) ? $getID3checkColor_FileDark : $getID3checkColor_FileLight).'">';
|
||||
$escaped_filename = htmlentities($filename, ENT_SUBSTITUTE, $FileSystemEncoding); // do filesystems always return filenames in ISO-8859-1?
|
||||
$escaped_filename = ($escaped_filename ? $escaped_filename : rawurlencode($filename));
|
||||
echo '<td><a href="'.htmlentities($_SERVER['PHP_SELF'].'?filename='.urlencode($dirname.$filename), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'" title="View detailed analysis">'.$escaped_filename.'</a></td>';
|
||||
echo '<td align="right"> '.number_format($fileinfo['filesize']).'</td>';
|
||||
echo '<td align="right"> '.NiceDisplayFiletypeFormat($fileinfo).'</td>';
|
||||
echo '<td align="right"> '.(isset($fileinfo['playtime_string']) ? $fileinfo['playtime_string'] : '-').'</td>';
|
||||
echo '<td align="right"> '.(isset($fileinfo['bitrate']) ? BitrateText($fileinfo['bitrate'] / 1000, 0, ((isset($fileinfo['audio']['bitrate_mode']) && ($fileinfo['audio']['bitrate_mode'] == 'vbr')) ? true : false)) : '-').'</td>';
|
||||
echo '<td align="left"> '.(isset($fileinfo['comments_html']['artist']) ? implode('<br>', $fileinfo['comments_html']['artist']) : ((isset($fileinfo['video']['resolution_x']) && isset($fileinfo['video']['resolution_y'])) ? $fileinfo['video']['resolution_x'].'x'.$fileinfo['video']['resolution_y'] : '')).'</td>';
|
||||
echo '<td align="left"> '.(isset($fileinfo['comments_html']['title']) ? implode('<br>', $fileinfo['comments_html']['title']) : (isset($fileinfo['video']['frame_rate']) ? number_format($fileinfo['video']['frame_rate'], 3).'fps' : '')).'</td>';
|
||||
if (isset($_REQUEST['ShowMD5']) && GETID3_DEMO_BROWSE_ALLOW_MD5_LINK) {
|
||||
echo '<td align="left"><tt>'.(isset($fileinfo['md5_file']) ? $fileinfo['md5_file'] : ' ').'</tt></td>';
|
||||
echo '<td align="left"><tt>'.(isset($fileinfo['md5_data']) ? $fileinfo['md5_data'] : ' ').'</tt></td>';
|
||||
echo '<td align="left"><tt>'.(isset($fileinfo['md5_data_source']) ? $fileinfo['md5_data_source'] : ' ').'</tt></td>';
|
||||
} else {
|
||||
echo '<td align="center" colspan="3">-</td>';
|
||||
}
|
||||
echo '<td align="left"> '.(!empty($fileinfo['tags']) ? implode(', ', array_keys($fileinfo['tags'])) : '').'</td>';
|
||||
|
||||
echo '<td align="left"> ';
|
||||
if (!empty($fileinfo['warning'])) {
|
||||
$FilesWithWarnings++;
|
||||
echo '<a href="#" onClick="alert(\''.htmlentities(str_replace("'", "\\'", preg_replace('#[\r\n\t]+#', ' ', implode('\\n', $fileinfo['warning']))), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'\'); return false;" title="'.htmlentities(implode("; \n", $fileinfo['warning']), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">warning</a><br>';
|
||||
}
|
||||
if (!empty($fileinfo['error'])) {
|
||||
$FilesWithErrors++;
|
||||
echo '<a href="#" onClick="alert(\''.htmlentities(str_replace("'", "\\'", preg_replace('#[\r\n\t]+#', ' ', implode('\\n', $fileinfo['error']))), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'\'); return false;" title="'.htmlentities(implode("; \n", $fileinfo['error']), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">error</a><br>';
|
||||
}
|
||||
echo '</td>';
|
||||
|
||||
if (GETID3_DEMO_BROWSE_ALLOW_EDIT_LINK) {
|
||||
echo '<td align="left"> ';
|
||||
$fileinfo['fileformat'] = (isset($fileinfo['fileformat']) ? $fileinfo['fileformat'] : '');
|
||||
switch ($fileinfo['fileformat']) {
|
||||
case 'mp3':
|
||||
case 'mp2':
|
||||
case 'mp1':
|
||||
case 'flac':
|
||||
case 'mpc':
|
||||
case 'real':
|
||||
echo '<a href="'.htmlentities($writescriptfilename.'?Filename='.urlencode($dirname.$filename), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'" title="Edit tags">edit tags</a>';
|
||||
break;
|
||||
case 'ogg':
|
||||
if (isset($fileinfo['audio']['dataformat']) && ($fileinfo['audio']['dataformat'] == 'vorbis')) {
|
||||
echo '<a href="'.htmlentities($writescriptfilename.'?Filename='.urlencode($dirname.$filename), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'" title="Edit tags">edit tags</a>';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
echo '</td>';
|
||||
}
|
||||
if (GETID3_DEMO_BROWSE_ALLOW_DELETE_LINK) {
|
||||
echo '<td align="left"> <a href="'.htmlentities($_SERVER['PHP_SELF'].'?listdirectory='.urlencode($listdirectory).'&deletefile='.urlencode($dirname.$filename), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'" onClick="return confirm(\'Are you sure you want to delete '.addslashes(htmlentities($dirname.$filename)).'? \n(this action cannot be un-done)\');" title="'.htmlentities('Permanently delete '."\n".$filename."\n".' from'."\n".' '.$dirname, ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">delete</a></td>';
|
||||
}
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($DirectoryContents[$dirname]['other']) && is_array($DirectoryContents[$dirname]['other'])) {
|
||||
uksort($DirectoryContents[$dirname]['other'], 'MoreNaturalSort');
|
||||
foreach ($DirectoryContents[$dirname]['other'] as $filename => $fileinfo) {
|
||||
echo '<tr bgcolor="#'.(($rowcounter++ % 2) ? $getID3checkColor_UnknownDark : $getID3checkColor_UnknownLight).'">';
|
||||
$escaped_filename = htmlentities($filename, ENT_SUBSTITUTE, $PageEncoding);
|
||||
$escaped_filename = ($escaped_filename ? $escaped_filename : rawurlencode($filename));
|
||||
echo '<td><a href="'.htmlentities($_SERVER['PHP_SELF'].'?filename='.urlencode($dirname.$filename), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'"><i>'.$escaped_filename.'</i></a></td>';
|
||||
echo '<td align="right"> '.(isset($fileinfo['filesize']) ? number_format($fileinfo['filesize']) : '-').'</td>';
|
||||
echo '<td align="right"> '.NiceDisplayFiletypeFormat($fileinfo).'</td>';
|
||||
echo '<td align="right"> '.(isset($fileinfo['playtime_string']) ? $fileinfo['playtime_string'] : '-').'</td>';
|
||||
echo '<td align="right"> '.(isset($fileinfo['bitrate']) ? BitrateText($fileinfo['bitrate'] / 1000) : '-').'</td>';
|
||||
echo '<td align="left"> </td>'; // Artist
|
||||
echo '<td align="left"> </td>'; // Title
|
||||
echo '<td align="left" colspan="3"> </td>'; // MD5_data
|
||||
echo '<td align="left"> </td>'; // Tags
|
||||
|
||||
//echo '<td align="left"> </td>'; // Warning/Error
|
||||
echo '<td align="left"> ';
|
||||
if (!empty($fileinfo['warning'])) {
|
||||
$FilesWithWarnings++;
|
||||
echo '<a href="#" onClick="alert(\''.htmlentities(implode('\\n', $fileinfo['warning']), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'\'); return false;" title="'.htmlentities(implode("\n", $fileinfo['warning']), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">warning</a><br>';
|
||||
}
|
||||
if (!empty($fileinfo['error'])) {
|
||||
if ($fileinfo['error'][0] != 'unable to determine file format') {
|
||||
$FilesWithErrors++;
|
||||
echo '<a href="#" onClick="alert(\''.htmlentities(implode('\\n', $fileinfo['error']), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'\'); return false;" title="'.htmlentities(implode("\n", $fileinfo['error']), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">error</a><br>';
|
||||
}
|
||||
}
|
||||
echo '</td>';
|
||||
|
||||
if (GETID3_DEMO_BROWSE_ALLOW_EDIT_LINK) {
|
||||
echo '<td align="left"> </td>'; // Edit
|
||||
}
|
||||
if (GETID3_DEMO_BROWSE_ALLOW_DELETE_LINK) {
|
||||
echo '<td align="left"> <a href="'.htmlentities($_SERVER['PHP_SELF'].'?listdirectory='.urlencode($listdirectory).'&deletefile='.urlencode($dirname.$filename), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'" onClick="return confirm(\'Are you sure you want to delete '.addslashes($dirname.$filename).'? \n(this action cannot be un-done)\');" title="Permanently delete '.addslashes($dirname.$filename).'">delete</a></td>';
|
||||
}
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '<tr bgcolor="#'.$getID3checkColor_Head.'">';
|
||||
echo '<td><b>Average:</b></td>';
|
||||
echo '<td align="right">'.number_format($TotalScannedFilesize / max($TotalScannedKnownFiles, 1)).'</td>';
|
||||
echo '<td> </td>';
|
||||
echo '<td align="right">'.getid3_lib::PlaytimeString($TotalScannedPlaytime / max($TotalScannedPlaytimeFiles, 1)).'</td>';
|
||||
echo '<td align="right">'.BitrateText(round(($TotalScannedBitrate / 1000) / max($TotalScannedBitrateFiles, 1))).'</td>';
|
||||
echo '<td rowspan="2" colspan="'.($columnsintable - 5).'"><table class="table" border="0" cellspacing="0" cellpadding="2"><tr><th align="right">Identified Files:</th><td align="right">'.number_format($TotalScannedKnownFiles).'</td><td> </td><th align="right">Errors:</th><td align="right">'.number_format($FilesWithErrors).'</td></tr><tr><th align="right">Unknown Files:</th><td align="right">'.number_format($TotalScannedUnknownFiles).'</td><td> </td><th align="right">Warnings:</th><td align="right">'.number_format($FilesWithWarnings).'</td></tr></table>';
|
||||
echo '</tr>';
|
||||
echo '<tr bgcolor="#'.$getID3checkColor_Head.'">';
|
||||
echo '<td><b>Total:</b></td>';
|
||||
echo '<td align="right">'.number_format($TotalScannedFilesize).'</td>';
|
||||
echo '<td> </td>';
|
||||
echo '<td align="right">'.getid3_lib::PlaytimeString($TotalScannedPlaytime).'</td>';
|
||||
echo '<td> </td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
echo '</table>';
|
||||
} else {
|
||||
$errormessage = ob_get_contents();
|
||||
ob_end_clean();
|
||||
echo '<b>ERROR: Could not open directory: <u>'.htmlentities($currentfulldir, ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'</u></b><br>';
|
||||
//echo $errormessage.'<br>'; // uncomment for debugging
|
||||
}
|
||||
}
|
||||
echo PoweredBygetID3().'<br clear="all">';
|
||||
echo '</body></html>';
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
function RemoveAccents($string) {
|
||||
// Revised version by markstewardרotmail*com
|
||||
// Again revised by James Heinrich (19-June-2006)
|
||||
return strtr(
|
||||
strtr(
|
||||
$string,
|
||||
"\x8A\x8E\x9A\x9E\x9F\xC0\xC1\xC2\xC3\xC4\xC5\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD1\xD2\xD3\xD4\xD5\xD6\xD8\xD9\xDA\xDB\xDC\xDD\xE0\xE1\xE2\xE3\xE4\xE5\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFF",
|
||||
'SZszYAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy'
|
||||
),
|
||||
array(
|
||||
"\xDE" => 'TH',
|
||||
"\xFE" => 'th',
|
||||
"\xD0" => 'DH',
|
||||
"\xF0" => 'dh',
|
||||
"\xDF" => 'ss',
|
||||
"\x8C" => 'OE',
|
||||
"\x9C" => 'oe',
|
||||
"\xC6" => 'AE',
|
||||
"\xE6" => 'ae',
|
||||
"\xB5" => 'u'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function BitrateColor($bitrate, $BitrateMaxScale=768) {
|
||||
// $BitrateMaxScale is bitrate of maximum-quality color (bright green)
|
||||
// below this is gradient, above is solid green
|
||||
|
||||
$bitrate *= (256 / $BitrateMaxScale); // scale from 1-[768]kbps to 1-256
|
||||
$bitrate = round(min(max($bitrate, 1), 256));
|
||||
$bitrate--; // scale from 1-256kbps to 0-255kbps
|
||||
|
||||
$Rcomponent = max(255 - ($bitrate * 2), 0);
|
||||
$Gcomponent = max(($bitrate * 2) - 255, 0);
|
||||
if ($bitrate > 127) {
|
||||
$Bcomponent = max((255 - $bitrate) * 2, 0);
|
||||
} else {
|
||||
$Bcomponent = max($bitrate * 2, 0);
|
||||
}
|
||||
return str_pad(dechex($Rcomponent), 2, '0', STR_PAD_LEFT).str_pad(dechex($Gcomponent), 2, '0', STR_PAD_LEFT).str_pad(dechex($Bcomponent), 2, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
function BitrateText($bitrate, $decimals=0, $vbr=false) {
|
||||
return '<span style="color: #'.BitrateColor($bitrate).($vbr ? '; font-weight: bold;' : '').'">'.number_format($bitrate, $decimals).' kbps</span>';
|
||||
}
|
||||
|
||||
function string_var_dump($variable) {
|
||||
if (version_compare(PHP_VERSION, '4.3.0', '>=')) {
|
||||
return print_r($variable, true);
|
||||
}
|
||||
ob_start();
|
||||
var_dump($variable);
|
||||
$dumpedvariable = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $dumpedvariable;
|
||||
}
|
||||
|
||||
function table_var_dump($variable, $wrap_in_td=false, $encoding='') {
|
||||
global $FileSystemEncoding;
|
||||
$encoding = ($encoding ? $encoding : $FileSystemEncoding);
|
||||
$returnstring = '';
|
||||
switch (gettype($variable)) {
|
||||
case 'array':
|
||||
$returnstring .= ($wrap_in_td ? '<td>' : '');
|
||||
$returnstring .= '<table class="dump" cellspacing="0" cellpadding="2">';
|
||||
foreach ($variable as $key => $value) {
|
||||
$returnstring .= '<tr><td valign="top"><b>'.str_replace("\x00", ' ', $key).'</b></td>'."\n";
|
||||
$returnstring .= '<td valign="top">'.gettype($value);
|
||||
if (is_array($value)) {
|
||||
$returnstring .= ' ('.count($value).')';
|
||||
} elseif (is_string($value)) {
|
||||
$returnstring .= ' ('.strlen($value).')';
|
||||
}
|
||||
//if (($key == 'data') && isset($variable['image_mime']) && isset($variable['dataoffset'])) {
|
||||
if (($key == 'data') && isset($variable['image_mime'])) {
|
||||
$imageinfo = array();
|
||||
if ($imagechunkcheck = getid3_lib::GetDataImageSize($value, $imageinfo)) {
|
||||
$returnstring .= '</td>'."\n".'<td><img src="data:'.$variable['image_mime'].';base64,'.base64_encode($value).'" width="'.$imagechunkcheck[0].'" height="'.$imagechunkcheck[1].'"></td></tr>'."\n";
|
||||
} else {
|
||||
$returnstring .= '</td>'."\n".'<td><i>invalid image data</i></td></tr>'."\n";
|
||||
}
|
||||
} else {
|
||||
$returnstring .= '</td>'."\n".table_var_dump($value, true, $encoding).'</tr>'."\n";
|
||||
}
|
||||
}
|
||||
$returnstring .= '</table>'."\n";
|
||||
$returnstring .= ($wrap_in_td ? '</td>'."\n" : '');
|
||||
break;
|
||||
|
||||
case 'boolean':
|
||||
$returnstring .= ($wrap_in_td ? '<td class="dump_boolean">' : '').($variable ? 'TRUE' : 'FALSE').($wrap_in_td ? '</td>'."\n" : '');
|
||||
break;
|
||||
|
||||
case 'integer':
|
||||
$returnstring .= ($wrap_in_td ? '<td class="dump_integer">' : '').$variable.($wrap_in_td ? '</td>'."\n" : '');
|
||||
break;
|
||||
|
||||
case 'double':
|
||||
case 'float':
|
||||
$returnstring .= ($wrap_in_td ? '<td class="dump_double">' : '').$variable.($wrap_in_td ? '</td>'."\n" : '');
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
case 'null':
|
||||
$returnstring .= ($wrap_in_td ? '<td>' : '').string_var_dump($variable).($wrap_in_td ? '</td>'."\n" : '');
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
$returnstring = htmlentities($variable, ENT_QUOTES | ENT_SUBSTITUTE, $encoding);
|
||||
$returnstring = ($wrap_in_td ? '<td class="dump_string">' : '').nl2br($returnstring).($wrap_in_td ? '</td>'."\n" : '');
|
||||
break;
|
||||
|
||||
default:
|
||||
$imageinfo = array();
|
||||
if (($imagechunkcheck = getid3_lib::GetDataImageSize($variable, $imageinfo)) && ($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
|
||||
$returnstring .= ($wrap_in_td ? '<td>' : '');
|
||||
$returnstring .= '<table class="dump" cellspacing="0" cellpadding="2">';
|
||||
$returnstring .= '<tr><td><b>type</b></td><td>'.image_type_to_mime_type($imagechunkcheck[2]).'</td></tr>'."\n";
|
||||
$returnstring .= '<tr><td><b>width</b></td><td>'.number_format($imagechunkcheck[0]).' px</td></tr>'."\n";
|
||||
$returnstring .= '<tr><td><b>height</b></td><td>'.number_format($imagechunkcheck[1]).' px</td></tr>'."\n";
|
||||
$returnstring .= '<tr><td><b>size</b></td><td>'.number_format(strlen($variable)).' bytes</td></tr></table>'."\n";
|
||||
$returnstring .= ($wrap_in_td ? '</td>'."\n" : '');
|
||||
} else {
|
||||
$returnstring .= ($wrap_in_td ? '<td>' : '').nl2br(htmlspecialchars(str_replace("\x00", ' ', $variable))).($wrap_in_td ? '</td>'."\n" : '');
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $returnstring;
|
||||
}
|
||||
|
||||
|
||||
function NiceDisplayFiletypeFormat(&$fileinfo) {
|
||||
|
||||
if (empty($fileinfo['fileformat'])) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
$output = $fileinfo['fileformat'];
|
||||
if (empty($fileinfo['video']['dataformat']) && empty($fileinfo['audio']['dataformat'])) {
|
||||
return $output; // 'gif'
|
||||
}
|
||||
if (empty($fileinfo['video']['dataformat']) && !empty($fileinfo['audio']['dataformat'])) {
|
||||
if ($fileinfo['fileformat'] == $fileinfo['audio']['dataformat']) {
|
||||
return $output; // 'mp3'
|
||||
}
|
||||
$output .= '.'.$fileinfo['audio']['dataformat']; // 'ogg.flac'
|
||||
return $output;
|
||||
}
|
||||
if (!empty($fileinfo['video']['dataformat']) && empty($fileinfo['audio']['dataformat'])) {
|
||||
if ($fileinfo['fileformat'] == $fileinfo['video']['dataformat']) {
|
||||
return $output; // 'mpeg'
|
||||
}
|
||||
$output .= '.'.$fileinfo['video']['dataformat']; // 'riff.avi'
|
||||
return $output;
|
||||
}
|
||||
if ($fileinfo['video']['dataformat'] == $fileinfo['audio']['dataformat']) {
|
||||
if ($fileinfo['fileformat'] == $fileinfo['video']['dataformat']) {
|
||||
return $output; // 'real'
|
||||
}
|
||||
$output .= '.'.$fileinfo['video']['dataformat']; // any examples?
|
||||
return $output;
|
||||
}
|
||||
$output .= '.'.$fileinfo['video']['dataformat'];
|
||||
$output .= '.'.$fileinfo['audio']['dataformat']; // asf.wmv.wma
|
||||
return $output;
|
||||
|
||||
}
|
||||
|
||||
function MoreNaturalSort($ar1, $ar2) {
|
||||
if ($ar1 === $ar2) {
|
||||
return 0;
|
||||
}
|
||||
$len1 = strlen($ar1);
|
||||
$len2 = strlen($ar2);
|
||||
$shortest = min($len1, $len2);
|
||||
if (substr($ar1, 0, $shortest) === substr($ar2, 0, $shortest)) {
|
||||
// the shorter argument is the beginning of the longer one, like "str" and "string"
|
||||
if ($len1 < $len2) {
|
||||
return -1;
|
||||
} elseif ($len1 > $len2) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
$ar1 = RemoveAccents(strtolower(trim($ar1)));
|
||||
$ar2 = RemoveAccents(strtolower(trim($ar2)));
|
||||
$translatearray = array('\''=>'', '"'=>'', '_'=>' ', '('=>'', ')'=>'', '-'=>' ', ' '=>' ', '.'=>'', ','=>'');
|
||||
foreach ($translatearray as $key => $val) {
|
||||
$ar1 = str_replace($key, $val, $ar1);
|
||||
$ar2 = str_replace($key, $val, $ar2);
|
||||
}
|
||||
|
||||
if ($ar1 < $ar2) {
|
||||
return -1;
|
||||
} elseif ($ar1 > $ar2) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function PoweredBygetID3($string='') {
|
||||
global $getID3;
|
||||
if (!$string) {
|
||||
$string = '<div style="border: 1px #CCCCCC solid; padding: 5px; margin: 5px 0; float: left; background-color: #EEEEEE; font-size: 8pt; font-family: sans-serif;">Powered by <a href="https://www.getid3.org/"><b>getID3() v<!--GETID3VER--></b><br>https://www.getid3.org/</a><br>Running on PHP v'.PHP_VERSION.' ('.(8 * PHP_INT_SIZE).'-bit, '.(defined('PHP_OS_FAMILY') ? PHP_OS_FAMILY : PHP_OS).')</div>';
|
||||
}
|
||||
return str_replace('<!--GETID3VER-->', $getID3->version(), $string);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// /demo/demo.cache.dbm.php - part of getID3() //
|
||||
// Sample script demonstrating the use of the DBM caching //
|
||||
// extension for getID3() //
|
||||
// see readme.txt for more details //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
die('For security reasons, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in demos/'.basename(__FILE__));
|
||||
|
||||
|
||||
require_once('../getid3/getid3.php');
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'extension.cache.dbm.php', __FILE__, true);
|
||||
|
||||
$getID3 = new getID3_cached_dbm('db3', '/zimweb/test/test.dbm', '/zimweb/test/test.lock');
|
||||
|
||||
$r = $getID3->analyze('/path/to/files/filename.mp3');
|
||||
|
||||
echo '<pre>';
|
||||
var_dump($r);
|
||||
echo '</pre>';
|
||||
|
||||
// uncomment to clear cache
|
||||
// $getID3->clear_cache();
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// /demo/demo.cache.mysql.php - part of getID3() //
|
||||
// Sample script demonstrating the use of the DBM caching //
|
||||
// extension for getID3() //
|
||||
// see readme.txt for more details //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
die('For security reasons, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in demos/'.basename(__FILE__));
|
||||
|
||||
|
||||
require_once('../getid3/getid3.php');
|
||||
require_once('../getid3/getid3.lib.php');
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'extension.cache.mysql.php', __FILE__, true);
|
||||
|
||||
$getID3 = new getID3_cached_mysql('localhost', 'database', 'username', 'password');
|
||||
|
||||
$r = $getID3->analyze('/path/to/files/filename.mp3');
|
||||
|
||||
echo '<pre>';
|
||||
var_dump($r);
|
||||
echo '</pre>';
|
||||
|
||||
// uncomment to clear cache
|
||||
//$getID3->clear_cache();
|
|
@ -0,0 +1,260 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// /demo/demo.dirscan.php - part of getID3() //
|
||||
// Directory Scanning and Caching CLI tool for batch media //
|
||||
// file processing with getID3() //
|
||||
// by Karl G. Holz <newaeonØmac*com> //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
die('For security reasons, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in demos/'.basename(__FILE__));
|
||||
|
||||
|
||||
/**
|
||||
* This is a directory scanning and caching cli tool for getID3().
|
||||
*
|
||||
* use like so for the default sqlite3 database, which is hidden:
|
||||
*
|
||||
* cd <path you want to start scanning from>
|
||||
* php <path to getid3 files>/demo.dirscan.php
|
||||
*
|
||||
* or
|
||||
*
|
||||
* php <path to getid3 files>/demo.dirscan.php <dir to scan> <file ext in csv list>
|
||||
*
|
||||
* Supported Cache Types (this extension)
|
||||
*
|
||||
* SQL Databases:
|
||||
*
|
||||
* cache_type
|
||||
* -------------------------------------------------------------------
|
||||
* mysql
|
||||
|
||||
$cache='mysql';
|
||||
$database['host']='';
|
||||
$database['database']='';
|
||||
$database['username']='';
|
||||
$database['password']='';
|
||||
$database['table']='';
|
||||
|
||||
* sqlite3
|
||||
|
||||
$cache='sqlite3';
|
||||
$database['table']='getid3_cache';
|
||||
$database['hide']=true;
|
||||
|
||||
*/
|
||||
$dir = $_SERVER['PWD'];
|
||||
$media = array('mp4', 'm4v', 'mov', 'mp3', 'm4a', 'jpg', 'png', 'gif');
|
||||
$database = array();
|
||||
/**
|
||||
* configure the database bellow
|
||||
*/
|
||||
// sqlite3
|
||||
$cache = 'sqlite3';
|
||||
$database['table'] = 'getid3_cache';
|
||||
$database['hide'] = true;
|
||||
/**
|
||||
* mysql
|
||||
$cache = 'mysql';
|
||||
$database['host'] = '';
|
||||
$database['database'] = '';
|
||||
$database['username'] = '';
|
||||
$database['password'] = '';
|
||||
$database['table'] = '';
|
||||
*/
|
||||
|
||||
/**
|
||||
* id3 tags class file
|
||||
*/
|
||||
require_once(dirname(__FILE__).'/getid3.php');
|
||||
/**
|
||||
* dirscan scans all directories for files that match your selected filetypes into the cache database
|
||||
* this is useful for a lot of media files
|
||||
*
|
||||
*
|
||||
* @package dirscan
|
||||
* @author Karl Holz
|
||||
*
|
||||
*/
|
||||
|
||||
class dirscan {
|
||||
/**
|
||||
* type_brace() * Might not work on Solaris and other non GNU systems *
|
||||
*
|
||||
* Configures a filetype list for use with glob searches,
|
||||
* will match uppercase or lowercase extensions only, no mixing
|
||||
* @param string $dir directory to use
|
||||
* @param mixed $search cvs list of extentions or an array
|
||||
* @return string or null if checks fail
|
||||
*/
|
||||
private function type_brace($dir, $search=array()) {
|
||||
$dir = str_replace(array('///', '//'), array('/', '/'), $dir);
|
||||
if (!is_dir($dir)) {
|
||||
return null;
|
||||
}
|
||||
if (!is_array($search)) {
|
||||
$e = explode(',', $search);
|
||||
} elseif (count($search) < 1) {
|
||||
return null;
|
||||
} else {
|
||||
$e = $search;
|
||||
}
|
||||
$ext = array();
|
||||
foreach ($e as $new) {
|
||||
$ext[] = strtolower(trim($new));
|
||||
$ext[] = strtoupper(trim($new));
|
||||
}
|
||||
$b = $dir.'/*.{'.implode(',', $ext).'}';
|
||||
return $b;
|
||||
}
|
||||
|
||||
/**
|
||||
* this function will search 4 levels deep for directories
|
||||
* will return null on failure
|
||||
* @param string $root
|
||||
* @return array return an array of dirs under root
|
||||
* @todo figure out how to block tabo directories with ease
|
||||
*/
|
||||
private function getDirs($root) {
|
||||
switch ($root) { // return null on tabo directories, add as needed -> case {dir to block }: this is not perfect yet
|
||||
case '/':
|
||||
case '/var':
|
||||
case '/etc':
|
||||
case '/home':
|
||||
case '/usr':
|
||||
case '/root':
|
||||
case '/private/etc':
|
||||
case '/private/var':
|
||||
case '/etc/apache2':
|
||||
case '/home':
|
||||
case '/tmp':
|
||||
case '/var/log':
|
||||
return null;
|
||||
break;
|
||||
default: // scan 4 directories deep
|
||||
if (!is_dir($root)) {
|
||||
return null;
|
||||
}
|
||||
$dirs = array_merge(glob($root.'/*', GLOB_ONLYDIR), glob($root.'/*/*', GLOB_ONLYDIR), glob($root.'/*/*/*', GLOB_ONLYDIR), glob($root.'/*/*/*/*', GLOB_ONLYDIR), glob($root.'/*/*/*/*/*', GLOB_ONLYDIR), glob($root.'/*/*/*/*/*/*', GLOB_ONLYDIR), glob($root.'/*/*/*/*/*/*/*', GLOB_ONLYDIR));
|
||||
break;
|
||||
}
|
||||
if (count($dirs) < 1) {
|
||||
$dirs = array($root);
|
||||
}
|
||||
return $dirs;
|
||||
}
|
||||
|
||||
/**
|
||||
* file_check() check the number of file that are found that match the brace search
|
||||
*
|
||||
* @param string $search
|
||||
* @return mixed
|
||||
*/
|
||||
private function file_check($search) {
|
||||
$t = array();
|
||||
$s = glob($search, GLOB_BRACE);
|
||||
foreach ($s as $file) {
|
||||
$t[] = str_replace(array('///', '//'), array('/', '/'), $file);
|
||||
}
|
||||
if (count($t) > 0) {
|
||||
return $t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getTime() {
|
||||
return microtime(true);
|
||||
// old method for PHP < 5
|
||||
//$a = explode(' ', microtime());
|
||||
//return (double) $a[0] + $a[1];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $dir
|
||||
* @param mixed $match search type name extentions, can be an array or csv list
|
||||
* @param string $cache caching extention, select one of sqlite3, mysql, dbm
|
||||
* @param array $opt database options,
|
||||
*/
|
||||
function scan_files($dir, $match, $cache='sqlite3', $opt=array('table'=>'getid3_cache', 'hide'=>true)) {
|
||||
$Start = self::getTime();
|
||||
switch ($cache) { // load the caching module
|
||||
case 'sqlite3':
|
||||
if (!class_exists('getID3_cached_sqlite3')) {
|
||||
require_once(dirname(__FILE__)).'/extension.cache.sqlite3.php';
|
||||
}
|
||||
$id3 = new getID3_cached_sqlite3($opt['table'], $opt['hide']);
|
||||
break;
|
||||
case 'mysql':
|
||||
if (!class_exists('getID3_cached_mysql')) {
|
||||
require_once(dirname(__FILE__)).'/extension.cache.mysql.php';
|
||||
}
|
||||
$id3 = new getID3_cached_mysql($opt['host'], $opt['database'], $opt['username'], $opt['password'], $opt['table']);
|
||||
break;
|
||||
// I'll leave this for some one else
|
||||
//case 'dbm':
|
||||
// if (!class_exists('getID3_cached_dbm')) {
|
||||
// require_once(dirname(__FILE__)).'/extension.cache.dbm.php';
|
||||
// }
|
||||
// die(' This has not be implemented, sorry for the inconvenience');
|
||||
// break;
|
||||
default:
|
||||
die(' You have selected an Invalid cache type, only "sqlite3" and "mysql" are valid'."\n");
|
||||
break;
|
||||
}
|
||||
$count = array('dir'=>0, 'file'=>0);
|
||||
$dirs = self::getDirs($dir);
|
||||
if ($dirs !== null) {
|
||||
foreach ($dirs as $d) {
|
||||
echo ' Scanning: '.$d."\n";
|
||||
$search = self::type_brace($d, $match);
|
||||
if ($search !== null) {
|
||||
$files = self::file_check($search);
|
||||
if ($files !== null) {
|
||||
foreach ($files as $f) {
|
||||
echo ' * Analyzing '.$f.' '."\n";
|
||||
$id3->analyze($f);
|
||||
$count['file']++;
|
||||
}
|
||||
$count['dir']++;
|
||||
} else {
|
||||
echo 'Failed to get files '."\n";
|
||||
}
|
||||
} else {
|
||||
echo 'Failed to create match string '."\n";
|
||||
}
|
||||
}
|
||||
echo '**************************************'."\n";
|
||||
echo '* Finished Scanning your directories '."\n*\n";
|
||||
echo '* Directories '.$count['dir']."\n";
|
||||
echo '* Files '.$count['file']."\n";
|
||||
$End = self::getTime();
|
||||
$t = number_format(($End - $Start) / 60, 2);
|
||||
echo '* Time taken to scan '.$dir.' '.$t.' min '."\n";
|
||||
echo '**************************************'."\n";
|
||||
} else {
|
||||
echo ' failed to get directories '."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PHP_SAPI === 'cli') {
|
||||
if (count($argv) == 2) {
|
||||
if (is_dir($argv[1])) {
|
||||
$dir = $argv[1];
|
||||
}
|
||||
if (count(explode(',', $argv[2])) > 0) {
|
||||
$media = $arg[2];
|
||||
}
|
||||
}
|
||||
echo ' * Starting to scan directory: '.$dir."\n";
|
||||
echo ' * Using default media types: '.implode(',', $media)."\n";
|
||||
dirscan::scan_files($dir, $media, $cache, $database);
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// /demo/demo.joinmp3.php - part of getID3() //
|
||||
// Sample script for splicing two or more MP3s together into //
|
||||
// one file. Does not attempt to fix VBR header frames. //
|
||||
// Can also be used to extract portion from single file. //
|
||||
// Note: all joined MP3s need to be the same sample rate. //
|
||||
// see readme.txt for more details //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
die('For security reasons, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in demos/'.basename(__FILE__));
|
||||
|
||||
|
||||
// sample usage:
|
||||
// $FilenameOut = 'combined.mp3';
|
||||
// $FilenamesIn[] = 'first.mp3'; // filename with no start/length parameters
|
||||
// $FilenamesIn[] = array('second.mp3', 0, 0); // filename with zero for start/length is the same as not specified (start = beginning, length = full duration)
|
||||
// $FilenamesIn[] = array('third.mp3', 0, 10); // extract first 10 seconds of audio
|
||||
// $FilenamesIn[] = array('fourth.mp3', -10, 0); // extract last 10 seconds of audio
|
||||
// $FilenamesIn[] = array('fifth.mp3', 10, 0); // extract everything except first 10 seconds of audio
|
||||
// $FilenamesIn[] = array('sixth.mp3', 0, -10); // extract everything except last 10 seconds of audio
|
||||
// if (CombineMultipleMP3sTo($FilenameOut, $FilenamesIn)) {
|
||||
// echo 'Successfully copied '.implode(' + ', $FilenamesIn).' to '.$FilenameOut;
|
||||
// } else {
|
||||
// echo 'Failed to copy '.implode(' + ', $FilenamesIn).' to '.$FilenameOut;
|
||||
// }
|
||||
//
|
||||
// Could also be called like this to extract portion from single file:
|
||||
// CombineMultipleMP3sTo('sample.mp3', array(array('input.mp3', 0, 30))); // extract first 30 seconds of audio
|
||||
|
||||
|
||||
function CombineMultipleMP3sTo($FilenameOut, $FilenamesIn) {
|
||||
|
||||
foreach ($FilenamesIn as $nextinputfilename) {
|
||||
if (is_array($nextinputfilename)) {
|
||||
$nextinputfilename = $nextinputfilename[0];
|
||||
}
|
||||
if (!is_readable($nextinputfilename)) {
|
||||
echo 'Cannot read "'.$nextinputfilename.'"<BR>';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((file_exists($FilenameOut) && !is_writeable($FilenameOut)) || (!file_exists($FilenameOut) && !is_writeable(dirname($FilenameOut)))) {
|
||||
echo 'Cannot write "'.$FilenameOut.'"<BR>';
|
||||
return false;
|
||||
}
|
||||
|
||||
require_once(dirname(__FILE__).'/../getid3/getid3.php');
|
||||
ob_start();
|
||||
if ($fp_output = fopen($FilenameOut, 'wb')) {
|
||||
|
||||
ob_end_clean();
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
foreach ($FilenamesIn as $nextinputfilename) {
|
||||
$startoffset = 0;
|
||||
$length_seconds = 0;
|
||||
if (is_array($nextinputfilename)) {
|
||||
@list($nextinputfilename, $startoffset, $length_seconds) = $nextinputfilename;
|
||||
}
|
||||
$CurrentFileInfo = $getID3->analyze($nextinputfilename);
|
||||
if ($CurrentFileInfo['fileformat'] == 'mp3') {
|
||||
|
||||
ob_start();
|
||||
if ($fp_source = fopen($nextinputfilename, 'rb')) {
|
||||
|
||||
ob_end_clean();
|
||||
$CurrentOutputPosition = ftell($fp_output);
|
||||
|
||||
// copy audio data from first file
|
||||
$start_offset_bytes = $CurrentFileInfo['avdataoffset'];
|
||||
if ($startoffset > 0) { // start X seconds from start of audio
|
||||
$start_offset_bytes = $CurrentFileInfo['avdataoffset'] + round(($CurrentFileInfo['bitrate'] / 8) * $startoffset);
|
||||
} elseif ($startoffset < 0) { // start X seconds from end of audio
|
||||
$start_offset_bytes = $CurrentFileInfo['avdataend'] + round(($CurrentFileInfo['bitrate'] / 8) * $startoffset);
|
||||
}
|
||||
$start_offset_bytes = max($CurrentFileInfo['avdataoffset'], min($CurrentFileInfo['avdataend'], $start_offset_bytes));
|
||||
|
||||
$end_offset_bytes = $CurrentFileInfo['avdataend'];
|
||||
if ($length_seconds > 0) { // set end offset to X seconds from start of audio
|
||||
$end_offset_bytes = $start_offset_bytes + round(($CurrentFileInfo['bitrate'] / 8) * $length_seconds);
|
||||
} elseif ($length_seconds < 0) { // set end offset to X seconds from end of audio
|
||||
$end_offset_bytes = $CurrentFileInfo['avdataend'] + round(($CurrentFileInfo['bitrate'] / 8) * $length_seconds);
|
||||
}
|
||||
$end_offset_bytes = max($CurrentFileInfo['avdataoffset'], min($CurrentFileInfo['avdataend'], $end_offset_bytes));
|
||||
|
||||
if ($end_offset_bytes <= $start_offset_bytes) {
|
||||
echo 'failed to copy '.$nextinputfilename.' from '.$startoffset.'-seconds start for '.$length_seconds.'-seconds length (not enough data)';
|
||||
fclose($fp_source);
|
||||
fclose($fp_output);
|
||||
return false;
|
||||
}
|
||||
|
||||
fseek($fp_source, $start_offset_bytes, SEEK_SET);
|
||||
while (!feof($fp_source) && (ftell($fp_source) < $end_offset_bytes)) {
|
||||
fwrite($fp_output, fread($fp_source, min(32768, $end_offset_bytes - ftell($fp_source))));
|
||||
}
|
||||
fclose($fp_source);
|
||||
|
||||
} else {
|
||||
|
||||
$errormessage = ob_get_contents();
|
||||
ob_end_clean();
|
||||
echo 'failed to open '.$nextinputfilename.' for reading';
|
||||
fclose($fp_output);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
echo $nextinputfilename.' is not MP3 format';
|
||||
fclose($fp_output);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$errormessage = ob_get_contents();
|
||||
ob_end_clean();
|
||||
echo 'failed to open '.$FilenameOut.' for writing';
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
fclose($fp_output);
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// /demo/demo.mimeonly.php - part of getID3() //
|
||||
// Sample script for scanning a single file and returning only //
|
||||
// the MIME information //
|
||||
// see readme.txt for more details //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
die('For security reasons, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in demos/'.basename(__FILE__));
|
||||
|
||||
|
||||
echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">';
|
||||
echo '<html><head><title>getID3 demos - MIME type only</title><style type="text/css">BODY, TD, TH { font-family: sans-serif; font-size: 10pt; }</style></head><body>';
|
||||
|
||||
if (!empty($_REQUEST['filename'])) {
|
||||
|
||||
echo 'The file "'.htmlentities($_REQUEST['filename']).'" has a MIME type of "'.htmlentities(GetMIMEtype($_REQUEST['filename'])).'"';
|
||||
|
||||
} else {
|
||||
|
||||
echo 'Usage: <span style="font-family: monospace;">'.htmlentities($_SERVER['PHP_SELF']).'?filename=<i>filename.ext</i></span>';
|
||||
|
||||
}
|
||||
|
||||
|
||||
function GetMIMEtype($filename) {
|
||||
$filename = realpath($filename);
|
||||
if (!file_exists($filename)) {
|
||||
echo 'File does not exist: "'.htmlentities($filename).'"<br>';
|
||||
return '';
|
||||
} elseif (!is_readable($filename)) {
|
||||
echo 'File is not readable: "'.htmlentities($filename).'"<br>';
|
||||
return '';
|
||||
}
|
||||
|
||||
// include getID3() library (can be in a different directory if full path is specified)
|
||||
require_once('../getid3/getid3.php');
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
|
||||
$DeterminedMIMEtype = '';
|
||||
if ($fp = fopen($filename, 'rb')) {
|
||||
$getID3->openfile($filename);
|
||||
if (empty($getID3->info['error'])) {
|
||||
|
||||
// ID3v2 is the only tag format that might be prepended in front of files, and it's non-trivial to skip, easier just to parse it and know where to skip to
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
|
||||
$getid3_id3v2 = new getid3_id3v2($getID3);
|
||||
$getid3_id3v2->Analyze();
|
||||
|
||||
fseek($fp, $getID3->info['avdataoffset'], SEEK_SET);
|
||||
$formattest = fread($fp, 16); // 16 bytes is sufficient for any format except ISO CD-image
|
||||
fclose($fp);
|
||||
|
||||
$DeterminedFormatInfo = $getID3->GetFileFormat($formattest);
|
||||
$DeterminedMIMEtype = $DeterminedFormatInfo['mime_type'];
|
||||
|
||||
} else {
|
||||
echo 'Failed to getID3->openfile "'.htmlentities($filename).'"<br>';
|
||||
}
|
||||
} else {
|
||||
echo 'Failed to fopen "'.htmlentities($filename).'"<br>';
|
||||
}
|
||||
return $DeterminedMIMEtype;
|
||||
}
|
||||
|
||||
echo '</body></html>';
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// /demo/demo.simple.php - part of getID3() //
|
||||
// Sample script for scanning a single directory and //
|
||||
// displaying a few pieces of information for each file //
|
||||
// see readme.txt for more details //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
die('For security reasons, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in demos/'.basename(__FILE__));
|
||||
|
||||
|
||||
echo '<html><head>';
|
||||
echo '<title>getID3() - /demo/demo.simple.php (sample script)</title>';
|
||||
echo '<style type="text/css">BODY,TD,TH { font-family: sans-serif; font-size: 9pt; }</style>';
|
||||
echo '</head><body>';
|
||||
|
||||
// include getID3() library (can be in a different directory if full path is specified)
|
||||
require_once('../getid3/getid3.php');
|
||||
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
|
||||
$DirectoryToScan = '/change/to/directory/you/want/to/scan'; // change to whatever directory you want to scan
|
||||
$dir = opendir($DirectoryToScan);
|
||||
echo '<table border="1" cellspacing="0" cellpadding="3">';
|
||||
echo '<tr><th>Filename</th><th>Artist</th><th>Title</th><th>Bitrate</th><th>Playtime</th></tr>';
|
||||
while (($file = readdir($dir)) !== false) {
|
||||
$FullFileName = realpath($DirectoryToScan.'/'.$file);
|
||||
if ((substr($file, 0, 1) != '.') && is_file($FullFileName)) {
|
||||
set_time_limit(30);
|
||||
|
||||
$ThisFileInfo = $getID3->analyze($FullFileName);
|
||||
|
||||
$getID3->CopyTagsToComments($ThisFileInfo);
|
||||
|
||||
// output desired information in whatever format you want
|
||||
echo '<tr>';
|
||||
echo '<td>'.htmlentities($ThisFileInfo['filenamepath']).'</td>';
|
||||
echo '<td>' .htmlentities(!empty($ThisFileInfo['comments_html']['artist']) ? implode('<br>', $ThisFileInfo['comments_html']['artist']) : chr(160)).'</td>';
|
||||
echo '<td>' .htmlentities(!empty($ThisFileInfo['comments_html']['title']) ? implode('<br>', $ThisFileInfo['comments_html']['title']) : chr(160)).'</td>';
|
||||
echo '<td align="right">'.htmlentities(!empty($ThisFileInfo['audio']['bitrate']) ? round($ThisFileInfo['audio']['bitrate'] / 1000).' kbps' : chr(160)).'</td>';
|
||||
echo '<td align="right">'.htmlentities(!empty($ThisFileInfo['playtime_string']) ? $ThisFileInfo['playtime_string'] : chr(160)).'</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
echo '</table>';
|
||||
|
||||
echo '</body></html>';
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// /demo/demo.simple.write.php - part of getID3() //
|
||||
// Sample script showing basic syntax for writing tags //
|
||||
// see readme.txt for more details //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
die('For security reasons, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in demos/'.basename(__FILE__));
|
||||
|
||||
|
||||
$TextEncoding = 'UTF-8';
|
||||
|
||||
require_once('../getid3/getid3.php');
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$getID3->setOption(array('encoding'=>$TextEncoding));
|
||||
|
||||
require_once('../getid3/write.php');
|
||||
// Initialize getID3 tag-writing module
|
||||
$tagwriter = new getid3_writetags;
|
||||
//$tagwriter->filename = '/path/to/file.mp3';
|
||||
$tagwriter->filename = 'c:/file.mp3';
|
||||
|
||||
//$tagwriter->tagformats = array('id3v1', 'id3v2.3');
|
||||
$tagwriter->tagformats = array('id3v2.3');
|
||||
|
||||
// set various options (optional)
|
||||
$tagwriter->overwrite_tags = true; // if true will erase existing tag data and write only passed data; if false will merge passed data with existing tag data (experimental)
|
||||
$tagwriter->remove_other_tags = false; // if true removes other tag formats (e.g. ID3v1, ID3v2, APE, Lyrics3, etc) that may be present in the file and only write the specified tag format(s). If false leaves any unspecified tag formats as-is.
|
||||
$tagwriter->tag_encoding = $TextEncoding;
|
||||
$tagwriter->remove_other_tags = true;
|
||||
|
||||
// populate data array
|
||||
$TagData = array(
|
||||
'title' => array('My Song'),
|
||||
'artist' => array('The Artist'),
|
||||
'album' => array('Greatest Hits'),
|
||||
'year' => array('2004'),
|
||||
'genre' => array('Rock'),
|
||||
'comment' => array('excellent!'),
|
||||
'track_number' => array('04/16'),
|
||||
'popularimeter' => array('email'=>'user@example.net', 'rating'=>128, 'data'=>0),
|
||||
'unique_file_identifier' => array('ownerid'=>'user@example.net', 'data'=>md5(time())),
|
||||
);
|
||||
$tagwriter->tag_data = $TagData;
|
||||
|
||||
// write tags
|
||||
if ($tagwriter->WriteTags()) {
|
||||
echo 'Successfully wrote tags<br>';
|
||||
if (!empty($tagwriter->warnings)) {
|
||||
echo 'There were some warnings:<br>'.implode('<br><br>', $tagwriter->warnings);
|
||||
}
|
||||
} else {
|
||||
echo 'Failed to write tags!<br>'.implode('<br><br>', $tagwriter->errors);
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// /demo/demo.write.php - part of getID3() //
|
||||
// sample script for demonstrating writing ID3v1 and ID3v2 //
|
||||
// tags for MP3, or Ogg comment tags for Ogg Vorbis //
|
||||
// see readme.txt for more details //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
die('For security reasons, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in demos/'.basename(__FILE__));
|
||||
|
||||
|
||||
$TaggingFormat = 'UTF-8';
|
||||
|
||||
header('Content-Type: text/html; charset='.$TaggingFormat);
|
||||
echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">';
|
||||
echo '<html><head><title>getID3() - Sample tag writer</title></head><style type="text/css">BODY,TD,TH { font-family: sans-serif; font-size: 9pt;" }</style><body>';
|
||||
|
||||
require_once('../getid3/getid3.php');
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$getID3->setOption(array('encoding'=>$TaggingFormat));
|
||||
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.php', __FILE__, true);
|
||||
|
||||
$browsescriptfilename = 'demo.browse.php';
|
||||
|
||||
$Filename = (isset($_REQUEST['Filename']) ? $_REQUEST['Filename'] : '');
|
||||
|
||||
|
||||
|
||||
if (isset($_POST['WriteTags'])) {
|
||||
|
||||
$TagFormatsToWrite = (isset($_POST['TagFormatsToWrite']) ? $_POST['TagFormatsToWrite'] : array());
|
||||
if (!empty($TagFormatsToWrite)) {
|
||||
echo 'starting to write tag(s)<BR>';
|
||||
|
||||
$tagwriter = new getid3_writetags;
|
||||
$tagwriter->filename = $Filename;
|
||||
$tagwriter->tagformats = $TagFormatsToWrite;
|
||||
$tagwriter->overwrite_tags = false;
|
||||
$tagwriter->tag_encoding = $TaggingFormat;
|
||||
if (!empty($_POST['remove_other_tags'])) {
|
||||
$tagwriter->remove_other_tags = true;
|
||||
}
|
||||
|
||||
$commonkeysarray = array('Title', 'Artist', 'Album', 'Year', 'Comment');
|
||||
foreach ($commonkeysarray as $key) {
|
||||
if (!empty($_POST[$key])) {
|
||||
$TagData[strtolower($key)][] = $_POST[$key];
|
||||
}
|
||||
}
|
||||
if (!empty($_POST['Genre'])) {
|
||||
$TagData['genre'][] = $_POST['Genre'];
|
||||
}
|
||||
if (!empty($_POST['GenreOther'])) {
|
||||
$TagData['genre'][] = $_POST['GenreOther'];
|
||||
}
|
||||
if (!empty($_POST['Track'])) {
|
||||
$TagData['track_number'][] = $_POST['Track'].(!empty($_POST['TracksTotal']) ? '/'.$_POST['TracksTotal'] : '');
|
||||
}
|
||||
|
||||
if (!empty($_FILES['userfile']['tmp_name'])) {
|
||||
if (in_array('id3v2.4', $tagwriter->tagformats) || in_array('id3v2.3', $tagwriter->tagformats) || in_array('id3v2.2', $tagwriter->tagformats)) {
|
||||
if (is_uploaded_file($_FILES['userfile']['tmp_name'])) {
|
||||
if ($APICdata = file_get_contents($_FILES['userfile']['tmp_name'])) {
|
||||
|
||||
if ($exif_imagetype = exif_imagetype($_FILES['userfile']['tmp_name'])) {
|
||||
|
||||
$TagData['attached_picture'][0]['data'] = $APICdata;
|
||||
$TagData['attached_picture'][0]['picturetypeid'] = $_POST['APICpictureType'];
|
||||
$TagData['attached_picture'][0]['description'] = $_FILES['userfile']['name'];
|
||||
$TagData['attached_picture'][0]['mime'] = image_type_to_mime_type($exif_imagetype);
|
||||
|
||||
} else {
|
||||
echo '<b>invalid image format (only GIF, JPEG, PNG)</b><br>';
|
||||
}
|
||||
} else {
|
||||
echo '<b>cannot open '.htmlentities($_FILES['userfile']['tmp_name']).'</b><br>';
|
||||
}
|
||||
} else {
|
||||
echo '<b>!is_uploaded_file('.htmlentities($_FILES['userfile']['tmp_name']).')</b><br>';
|
||||
}
|
||||
} else {
|
||||
echo '<b>WARNING:</b> Can only embed images for ID3v2<br>';
|
||||
}
|
||||
}
|
||||
|
||||
$tagwriter->tag_data = $TagData;
|
||||
if ($tagwriter->WriteTags()) {
|
||||
echo 'Successfully wrote tags<BR>';
|
||||
if (!empty($tagwriter->warnings)) {
|
||||
echo 'There were some warnings:<blockquote style="background-color: #FFCC33; padding: 10px;">'.implode('<br><br>', $tagwriter->warnings).'</div>';
|
||||
}
|
||||
} else {
|
||||
echo 'Failed to write tags!<div style="background-color: #FF9999; padding: 10px;">'.implode('<br><br>', $tagwriter->errors).'</div>';
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
echo 'WARNING: no tag formats selected for writing - nothing written';
|
||||
|
||||
}
|
||||
echo '<HR>';
|
||||
|
||||
}
|
||||
|
||||
|
||||
echo '<div style="font-size: 1.2em; font-weight: bold;">Sample tag editor/writer</div>';
|
||||
echo '<a href="'.htmlentities($browsescriptfilename.'?listdirectory='.rawurlencode(realpath(dirname($Filename))), ENT_QUOTES).'">Browse current directory</a><br>';
|
||||
if (!empty($Filename)) {
|
||||
echo '<a href="'.htmlentities($_SERVER['PHP_SELF'], ENT_QUOTES).'">Start Over</a><br><br>';
|
||||
echo '<form action="'.htmlentities($_SERVER['PHP_SELF'], ENT_QUOTES).'" method="post" enctype="multipart/form-data">';
|
||||
echo '<table border="3" cellspacing="0" cellpadding="4">';
|
||||
echo '<tr><th align="right">Filename:</th><td><input type="hidden" name="Filename" value="'.htmlentities($Filename, ENT_QUOTES).'"><a href="'.htmlentities($browsescriptfilename.'?filename='.rawurlencode($Filename), ENT_QUOTES).'" target="_blank">'.$Filename.'</a></td></tr>';
|
||||
if (file_exists($Filename)) {
|
||||
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$OldThisFileInfo = $getID3->analyze($Filename);
|
||||
getid3_lib::CopyTagsToComments($OldThisFileInfo);
|
||||
|
||||
switch ($OldThisFileInfo['fileformat']) {
|
||||
case 'mp3':
|
||||
case 'mp2':
|
||||
case 'mp1':
|
||||
$ValidTagTypes = array('id3v1', 'id3v2.3', 'ape');
|
||||
break;
|
||||
|
||||
case 'mpc':
|
||||
$ValidTagTypes = array('ape');
|
||||
break;
|
||||
|
||||
case 'ogg':
|
||||
if (!empty($OldThisFileInfo['audio']['dataformat']) && ($OldThisFileInfo['audio']['dataformat'] == 'flac')) {
|
||||
//$ValidTagTypes = array('metaflac');
|
||||
// metaflac doesn't (yet) work with OggFLAC files
|
||||
$ValidTagTypes = array();
|
||||
} else {
|
||||
$ValidTagTypes = array('vorbiscomment');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'flac':
|
||||
$ValidTagTypes = array('metaflac');
|
||||
break;
|
||||
|
||||
case 'real':
|
||||
$ValidTagTypes = array('real');
|
||||
break;
|
||||
|
||||
default:
|
||||
$ValidTagTypes = array();
|
||||
break;
|
||||
}
|
||||
echo '<tr><td align="right"><b>Title</b></td> <td><input type="text" size="40" name="Title" value="'.htmlentities((!empty($OldThisFileInfo['comments']['title']) ? implode(', ', $OldThisFileInfo['comments']['title'] ) : ''), ENT_QUOTES).'"></td></tr>';
|
||||
echo '<tr><td align="right"><b>Artist</b></td><td><input type="text" size="40" name="Artist" value="'.htmlentities((!empty($OldThisFileInfo['comments']['artist']) ? implode(', ', $OldThisFileInfo['comments']['artist']) : ''), ENT_QUOTES).'"></td></tr>';
|
||||
echo '<tr><td align="right"><b>Album</b></td> <td><input type="text" size="40" name="Album" value="'.htmlentities((!empty($OldThisFileInfo['comments']['album']) ? implode(', ', $OldThisFileInfo['comments']['album'] ) : ''), ENT_QUOTES).'"></td></tr>';
|
||||
echo '<tr><td align="right"><b>Year</b></td> <td><input type="text" size="4" name="Year" value="'.htmlentities((!empty($OldThisFileInfo['comments']['year']) ? implode(', ', $OldThisFileInfo['comments']['year'] ) : ''), ENT_QUOTES).'"></td></tr>';
|
||||
|
||||
$TracksTotal = '';
|
||||
$TrackNumber = '';
|
||||
if (!empty($OldThisFileInfo['comments']['track_number']) && is_array($OldThisFileInfo['comments']['track_number'])) {
|
||||
$RawTrackNumberArray = $OldThisFileInfo['comments']['track_number'];
|
||||
} elseif (!empty($OldThisFileInfo['comments']['track_number']) && is_array($OldThisFileInfo['comments']['track_number'])) {
|
||||
$RawTrackNumberArray = $OldThisFileInfo['comments']['track_number'];
|
||||
} else {
|
||||
$RawTrackNumberArray = array();
|
||||
}
|
||||
foreach ($RawTrackNumberArray as $key => $value) {
|
||||
if (strlen($value) > strlen($TrackNumber)) {
|
||||
// ID3v1 may store track as "3" but ID3v2/APE would store as "03/16"
|
||||
$TrackNumber = $value;
|
||||
}
|
||||
}
|
||||
if (strstr($TrackNumber, '/')) {
|
||||
list($TrackNumber, $TracksTotal) = explode('/', $TrackNumber);
|
||||
}
|
||||
echo '<tr><td align="right"><b>Track</b></td><td><input type="text" size="2" name="Track" value="'.htmlentities($TrackNumber, ENT_QUOTES).'"> of <input type="text" size="2" name="TracksTotal" value="'.htmlentities($TracksTotal, ENT_QUOTES).'"></TD></TR>';
|
||||
|
||||
$ArrayOfGenresTemp = getid3_id3v1::ArrayOfGenres(); // get the array of genres
|
||||
foreach ($ArrayOfGenresTemp as $key => $value) { // change keys to match displayed value
|
||||
$ArrayOfGenres[$value] = $value;
|
||||
}
|
||||
unset($ArrayOfGenresTemp); // remove temporary array
|
||||
unset($ArrayOfGenres['Cover']); // take off these special cases
|
||||
unset($ArrayOfGenres['Remix']);
|
||||
unset($ArrayOfGenres['Unknown']);
|
||||
$ArrayOfGenres[''] = '- Unknown -'; // Add special cases back in with renamed key/value
|
||||
$ArrayOfGenres['Cover'] = '-Cover-';
|
||||
$ArrayOfGenres['Remix'] = '-Remix-';
|
||||
asort($ArrayOfGenres); // sort into alphabetical order
|
||||
echo '<tr><th align="right">Genre</th><td><select name="Genre">';
|
||||
$AllGenresArray = (!empty($OldThisFileInfo['comments']['genre']) ? $OldThisFileInfo['comments']['genre'] : array());
|
||||
foreach ($ArrayOfGenres as $key => $value) {
|
||||
echo '<option value="'.htmlentities($key, ENT_QUOTES).'"';
|
||||
if (in_array($key, $AllGenresArray)) {
|
||||
echo ' selected="selected"';
|
||||
unset($AllGenresArray[array_search($key, $AllGenresArray)]);
|
||||
sort($AllGenresArray);
|
||||
}
|
||||
echo '>'.htmlentities($value).'</option>';
|
||||
}
|
||||
echo '</select><input type="text" name="GenreOther" size="10" value="'.htmlentities((!empty($AllGenresArray[0]) ? $AllGenresArray[0] : ''), ENT_QUOTES).'"></td></tr>';
|
||||
|
||||
echo '<tr><td align="right"><b>Write Tags</b></td><td>';
|
||||
foreach ($ValidTagTypes as $ValidTagType) {
|
||||
echo '<input type="checkbox" name="TagFormatsToWrite[]" value="'.$ValidTagType.'"';
|
||||
if (count($ValidTagTypes) == 1) {
|
||||
echo ' checked="checked"';
|
||||
} else {
|
||||
switch ($ValidTagType) {
|
||||
case 'id3v2.2':
|
||||
case 'id3v2.3':
|
||||
case 'id3v2.4':
|
||||
if (isset($OldThisFileInfo['tags']['id3v2'])) {
|
||||
echo ' checked="checked"';
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isset($OldThisFileInfo['tags'][$ValidTagType])) {
|
||||
echo ' checked="checked"';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
echo '>'.$ValidTagType.'<br>';
|
||||
}
|
||||
if (count($ValidTagTypes) > 1) {
|
||||
echo '<hr><input type="checkbox" name="remove_other_tags" value="1"> Remove non-selected tag formats when writing new tag<br>';
|
||||
}
|
||||
echo '</td></tr>';
|
||||
|
||||
echo '<tr><td align="right"><b>Comment</b></td><td><textarea cols="30" rows="3" name="Comment" wrap="virtual">'.((isset($OldThisFileInfo['comments']['comment']) && is_array($OldThisFileInfo['comments']['comment'])) ? implode("\n", $OldThisFileInfo['comments']['comment']) : '').'</textarea></td></tr>';
|
||||
|
||||
echo '<tr><td align="right"><b>Picture</b><br>(ID3v2 only)</td><td><input type="file" name="userfile" accept="image/jpeg, image/gif, image/png"><br>';
|
||||
echo '<select name="APICpictureType">';
|
||||
$APICtypes = getid3_id3v2::APICPictureTypeLookup('', true);
|
||||
foreach ($APICtypes as $key => $value) {
|
||||
echo '<option value="'.htmlentities($key, ENT_QUOTES).'">'.htmlentities($value).'</option>';
|
||||
}
|
||||
echo '</select></td></tr>';
|
||||
echo '<tr><td align="center" colspan="2"><input type="submit" name="WriteTags" value="Save Changes"> ';
|
||||
echo '<input type="reset" value="Reset"></td></tr>';
|
||||
|
||||
} else {
|
||||
|
||||
echo '<tr><td align="right"><b>Error</b></td><td>'.htmlentities($Filename).' does not exist</td></tr>';
|
||||
|
||||
}
|
||||
echo '</table>';
|
||||
echo '</form>';
|
||||
|
||||
}
|
||||
|
||||
echo '</body></html>';
|
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// /demo/demo.zip.php - part of getID3() //
|
||||
// Sample script how to use getID3() to decompress zip files //
|
||||
// see readme.txt for more details //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
die('For security reasons, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in demos/'.basename(__FILE__));
|
||||
|
||||
|
||||
function UnzipFileContents($filename, &$errors) {
|
||||
$errors = array();
|
||||
$DecompressedFileContents = array();
|
||||
if (!class_exists('getID3')) {
|
||||
$errors[] = 'class getID3 not defined, please include getid3.php';
|
||||
} elseif (include_once('module.archive.zip.php')) {
|
||||
$getid3 = new getID3();
|
||||
$getid3->info['filesize'] = filesize($filename);
|
||||
ob_start();
|
||||
if ($getid3->fp = fopen($filename, 'rb')) {
|
||||
ob_end_clean();
|
||||
$getid3_zip = new getid3_zip($getid3);
|
||||
$getid3_zip->analyze();
|
||||
if (($getid3->info['fileformat'] == 'zip') && !empty($getid3->info['zip']['files'])) {
|
||||
if (!empty($getid3->info['zip']['central_directory'])) {
|
||||
$ZipDirectoryToWalk = $getid3->info['zip']['central_directory'];
|
||||
} elseif (!empty($getid3->info['zip']['entries'])) {
|
||||
$ZipDirectoryToWalk = $getid3->info['zip']['entries'];
|
||||
} else {
|
||||
$errors[] = 'failed to parse ZIP attachment "'.$filename.'" (no central directory)<br>';
|
||||
fclose($getid3->fp);
|
||||
return false;
|
||||
}
|
||||
foreach ($ZipDirectoryToWalk as $key => $valuearray) {
|
||||
fseek($getid3->fp, $valuearray['entry_offset'], SEEK_SET);
|
||||
$LocalFileHeader = $getid3_zip->ZIPparseLocalFileHeader();
|
||||
if ($LocalFileHeader['flags']['encrypted']) {
|
||||
// password-protected
|
||||
$DecompressedFileContents[$valuearray['filename']] = '';
|
||||
} else {
|
||||
fseek($getid3->fp, $LocalFileHeader['data_offset'], SEEK_SET);
|
||||
$compressedFileData = '';
|
||||
while ((strlen($compressedFileData) < $LocalFileHeader['compressed_size']) && !feof($getid3->fp)) {
|
||||
$compressedFileData .= fread($getid3->fp, 32768);
|
||||
}
|
||||
switch ($LocalFileHeader['raw']['compression_method']) {
|
||||
case 0: // store - great, just copy data unchanged
|
||||
$uncompressedFileData = $compressedFileData;
|
||||
break;
|
||||
|
||||
case 8: // deflate
|
||||
ob_start();
|
||||
$uncompressedFileData = gzinflate($compressedFileData);
|
||||
$gzinflate_errors = trim(strip_tags(ob_get_contents()));
|
||||
ob_end_clean();
|
||||
if ($gzinflate_errors) {
|
||||
$errors[] = 'gzinflate() failed for file ['.$LocalFileHeader['filename'].']: "'.$gzinflate_errors.'"';
|
||||
continue 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // shrink
|
||||
case 2: // reduce-1
|
||||
case 3: // reduce-2
|
||||
case 4: // reduce-3
|
||||
case 5: // reduce-4
|
||||
case 6: // implode
|
||||
case 7: // tokenize
|
||||
case 9: // deflate64
|
||||
case 10: // PKWARE Date Compression Library Imploding
|
||||
$DecompressedFileContents[$valuearray['filename']] = '';
|
||||
$errors[] = 'unsupported ZIP compression method ('.$LocalFileHeader['raw']['compression_method'].' = '.$getid3_zip->ZIPcompressionMethodLookup($LocalFileHeader['raw']['compression_method']).')';
|
||||
continue 2;
|
||||
|
||||
default:
|
||||
$DecompressedFileContents[$valuearray['filename']] = '';
|
||||
$errors[] = 'unknown ZIP compression method ('.$LocalFileHeader['raw']['compression_method'].')';
|
||||
continue 2;
|
||||
}
|
||||
$DecompressedFileContents[$valuearray['filename']] = $uncompressedFileData;
|
||||
unset($compressedFileData);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$errors[] = $filename.' does not appear to be a zip file';
|
||||
}
|
||||
} else {
|
||||
$error_message = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$errors[] = 'failed to fopen('.$filename.', rb): '.$error_message;
|
||||
}
|
||||
} else {
|
||||
$errors[] = 'failed to include_once(module.archive.zip.php)';
|
||||
}
|
||||
return $DecompressedFileContents;
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
/**
|
||||
* Common elements
|
||||
*/
|
||||
|
||||
body {
|
||||
font: 12px Verdana, sans-serif;
|
||||
background-color: white;
|
||||
color: black;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 30px;
|
||||
margin-left: 12px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font: bold 18px Verdana, sans-serif;
|
||||
line-height: 26px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 15px;
|
||||
margin-left: 0;
|
||||
margin-right: 7px;
|
||||
background-color: #e6eaf6;
|
||||
padding-left: 10px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font: bold 13px Verdana, sans-serif;
|
||||
line-height: 26px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 0;
|
||||
margin-left: 0;
|
||||
margin-right: 7px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
p, li {
|
||||
font: 9pt/135% sans-serif;
|
||||
margin-top: 1px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
a, a:link, a:visited {
|
||||
color: #0000cc;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 0;
|
||||
border: solid gray 0;
|
||||
border-top-width: thin;
|
||||
width: 700px;
|
||||
}
|
||||
|
||||
table.table td {
|
||||
font: 9pt sans-serif;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
table.table td.header {
|
||||
background-color: #cccccc;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table.table tr.even_files {
|
||||
background-color: #fefefe;
|
||||
}
|
||||
|
||||
table.table tr.odd_files {
|
||||
background-color: #e9e9e9;
|
||||
}
|
||||
|
||||
table.dump {
|
||||
border-top: solid 1px #cccccc;
|
||||
border-left: solid 1px #cccccc;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
table.dump td {
|
||||
font: 9pt sans-serif;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
border-right: solid 1px #cccccc;
|
||||
border-bottom: solid 1px #cccccc;
|
||||
}
|
||||
|
||||
td.dump_string {
|
||||
font-weight: bold;
|
||||
color: #006600;
|
||||
font-family: Zawgyi-One,sans-serif;
|
||||
}
|
||||
|
||||
td.dump_integer {
|
||||
color: #CC0000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
td.dump_double {
|
||||
color: #FF9900;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
td.dump_boolean {
|
||||
color: #0000FF;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tool Tips
|
||||
*/
|
||||
|
||||
.tooltip {
|
||||
font: 9pt sans-serif;
|
||||
background: #ffffe1;
|
||||
color: black;
|
||||
border: black 1px solid;
|
||||
margin: 2px;
|
||||
padding: 7px;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 10000;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.tooltip p {
|
||||
margin-top: -2px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Forms
|
||||
*/
|
||||
|
||||
table.form td {
|
||||
font: 9pt/135% sans-serif;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
select, input {
|
||||
font: 9pt/135% sans-serif;
|
||||
}
|
||||
|
||||
.select, .field {
|
||||
width: 260px;
|
||||
}
|
||||
|
||||
#sel_field {
|
||||
width: 85px;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin-top: 10px;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html><head><title>getID3 demos</title><style type="text/css">BODY, TD, TH { font-family: sans-serif; font-size: 10pt; }</style></head><body>
|
||||
|
||||
<?php
|
||||
die('For security reasons, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in demos/'.basename(__FILE__));
|
||||
?>
|
||||
|
||||
In this directory are a number of examples of how to use <a href="https://www.getid3.org/">getID3()</a>.<br>
|
||||
If you don't know what to run, take a look at <a href="demo.browse.php"><b>demo.browse.php</b></a>
|
||||
<hr>
|
||||
Other demos:<ul>
|
||||
<?php
|
||||
if ($dh = @opendir('.')) {
|
||||
while ($file = @readdir($dh)) {
|
||||
if (preg_match('#^demo\\..+\\.php$#', $file)) {
|
||||
echo '<li><a href="'.htmlentities($file).'">'.htmlentities($file).'</a></li>';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
|
@ -1,7 +1,8 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// or https://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// dependencies.txt - part of getID3() //
|
|
@ -1,16 +1,17 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// extension.cache.dbm.php - part of getID3() //
|
||||
// Please see readme.txt for more information //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// This extension written by Allan Hansen <ahØartemis*dk> //
|
||||
// This extension written by Allan Hansen <ahØartemis*dk> //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -71,9 +72,37 @@
|
|||
|
||||
class getID3_cached_dbm extends getID3
|
||||
{
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $dba;
|
||||
|
||||
// public: constructor - see top of this file for cache type and cache_options
|
||||
function getID3_cached_dbm($cache_type, $dbm_filename, $lock_filename) {
|
||||
/**
|
||||
* @var resource|bool
|
||||
*/
|
||||
private $lock;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $cache_type;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $dbm_filename;
|
||||
|
||||
/**
|
||||
* constructor - see top of this file for cache type and cache_options
|
||||
*
|
||||
* @param string $cache_type
|
||||
* @param string $dbm_filename
|
||||
* @param string $lock_filename
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws getid3_exception
|
||||
*/
|
||||
public function __construct($cache_type, $dbm_filename, $lock_filename) {
|
||||
|
||||
// Check for dba extension
|
||||
if (!extension_loaded('dba')) {
|
||||
|
@ -120,7 +149,7 @@ class getID3_cached_dbm extends getID3
|
|||
}
|
||||
|
||||
// Insert getID3 version number
|
||||
dba_insert(GETID3_VERSION, GETID3_VERSION, $this->dba);
|
||||
dba_insert(getID3::VERSION, getID3::VERSION, $this->dba);
|
||||
}
|
||||
|
||||
// Init misc values
|
||||
|
@ -131,17 +160,19 @@ class getID3_cached_dbm extends getID3
|
|||
register_shutdown_function(array($this, '__destruct'));
|
||||
|
||||
// Check version number and clear cache if changed
|
||||
if (dba_fetch(GETID3_VERSION, $this->dba) != GETID3_VERSION) {
|
||||
if (dba_fetch(getID3::VERSION, $this->dba) != getID3::VERSION) {
|
||||
$this->clear_cache();
|
||||
}
|
||||
|
||||
parent::getID3();
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// public: destuctor
|
||||
function __destruct() {
|
||||
/**
|
||||
* destructor
|
||||
*/
|
||||
public function __destruct() {
|
||||
|
||||
// Close dbm file
|
||||
dba_close($this->dba);
|
||||
|
@ -155,8 +186,12 @@ class getID3_cached_dbm extends getID3
|
|||
|
||||
|
||||
|
||||
// public: clear cache
|
||||
function clear_cache() {
|
||||
/**
|
||||
* clear cache
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function clear_cache() {
|
||||
|
||||
// Close dbm file
|
||||
dba_close($this->dba);
|
||||
|
@ -169,7 +204,7 @@ class getID3_cached_dbm extends getID3
|
|||
}
|
||||
|
||||
// Insert getID3 version number
|
||||
dba_insert(GETID3_VERSION, GETID3_VERSION, $this->dba);
|
||||
dba_insert(getID3::VERSION, getID3::VERSION, $this->dba);
|
||||
|
||||
// Re-register shutdown function
|
||||
register_shutdown_function(array($this, '__destruct'));
|
||||
|
@ -177,9 +212,19 @@ class getID3_cached_dbm extends getID3
|
|||
|
||||
|
||||
|
||||
// public: analyze file
|
||||
function analyze($filename) {
|
||||
/**
|
||||
* clear cache
|
||||
*
|
||||
* @param string $filename
|
||||
* @param int $filesize
|
||||
* @param string $original_filename
|
||||
* @param resource $fp
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function analyze($filename, $filesize=null, $original_filename='', $fp=null) {
|
||||
|
||||
$key = null;
|
||||
if (file_exists($filename)) {
|
||||
|
||||
// Calc key filename::mod_time::size - should be unique
|
||||
|
@ -195,10 +240,10 @@ class getID3_cached_dbm extends getID3
|
|||
}
|
||||
|
||||
// Miss
|
||||
$result = parent::analyze($filename);
|
||||
$result = parent::analyze($filename, $filesize, $original_filename, $fp);
|
||||
|
||||
// Save result
|
||||
if (file_exists($filename)) {
|
||||
if (isset($key) && file_exists($filename)) {
|
||||
dba_insert($key, serialize($result), $this->dba);
|
||||
}
|
||||
|
||||
|
@ -206,6 +251,3 @@ class getID3_cached_dbm extends getID3
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -0,0 +1,227 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// extension.cache.mysql.php - part of getID3() //
|
||||
// Please see readme.txt for more information //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// This extension written by Allan Hansen <ahØartemis*dk> //
|
||||
// Table name mod by Carlo Capocasa <calroØcarlocapocasa*com> //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* This is a caching extension for getID3(). It works the exact same
|
||||
* way as the getID3 class, but return cached information very fast
|
||||
*
|
||||
* Example: (see also demo.cache.mysql.php in /demo/)
|
||||
*
|
||||
* Normal getID3 usage (example):
|
||||
*
|
||||
* require_once 'getid3/getid3.php';
|
||||
* $getID3 = new getID3;
|
||||
* $getID3->encoding = 'UTF-8';
|
||||
* $info1 = $getID3->analyze('file1.flac');
|
||||
* $info2 = $getID3->analyze('file2.wv');
|
||||
*
|
||||
* getID3_cached usage:
|
||||
*
|
||||
* require_once 'getid3/getid3.php';
|
||||
* require_once 'getid3/getid3/extension.cache.mysql.php';
|
||||
* // 5th parameter (tablename) is optional, default is 'getid3_cache'
|
||||
* $getID3 = new getID3_cached_mysql('localhost', 'database', 'username', 'password', 'tablename');
|
||||
* $getID3->encoding = 'UTF-8';
|
||||
* $info1 = $getID3->analyze('file1.flac');
|
||||
* $info2 = $getID3->analyze('file2.wv');
|
||||
*
|
||||
*
|
||||
* Supported Cache Types (this extension)
|
||||
*
|
||||
* SQL Databases:
|
||||
*
|
||||
* cache_type cache_options
|
||||
* -------------------------------------------------------------------
|
||||
* mysql host, database, username, password
|
||||
*
|
||||
*
|
||||
* DBM-Style Databases: (use extension.cache.dbm)
|
||||
*
|
||||
* cache_type cache_options
|
||||
* -------------------------------------------------------------------
|
||||
* gdbm dbm_filename, lock_filename
|
||||
* ndbm dbm_filename, lock_filename
|
||||
* db2 dbm_filename, lock_filename
|
||||
* db3 dbm_filename, lock_filename
|
||||
* db4 dbm_filename, lock_filename (PHP5 required)
|
||||
*
|
||||
* PHP must have write access to both dbm_filename and lock_filename.
|
||||
*
|
||||
*
|
||||
* Recommended Cache Types
|
||||
*
|
||||
* Infrequent updates, many reads any DBM
|
||||
* Frequent updates mysql
|
||||
*/
|
||||
|
||||
|
||||
class getID3_cached_mysql extends getID3
|
||||
{
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $cursor;
|
||||
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $table;
|
||||
|
||||
|
||||
/**
|
||||
* constructor - see top of this file for cache type and cache_options
|
||||
*
|
||||
* @param string $host
|
||||
* @param string $database
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param string $table
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws getid3_exception
|
||||
*/
|
||||
public function __construct($host, $database, $username, $password, $table='getid3_cache') {
|
||||
|
||||
// Check for mysql support
|
||||
if (!function_exists('mysql_pconnect')) {
|
||||
throw new Exception('PHP not compiled with mysql support.');
|
||||
}
|
||||
|
||||
// Connect to database
|
||||
$this->connection = mysql_pconnect($host, $username, $password);
|
||||
if (!$this->connection) {
|
||||
throw new Exception('mysql_pconnect() failed - check permissions and spelling.');
|
||||
}
|
||||
|
||||
// Select database
|
||||
if (!mysql_select_db($database, $this->connection)) {
|
||||
throw new Exception('Cannot use database '.$database);
|
||||
}
|
||||
|
||||
// Set table
|
||||
$this->table = $table;
|
||||
|
||||
// Create cache table if not exists
|
||||
$this->create_table();
|
||||
|
||||
// Check version number and clear cache if changed
|
||||
$version = '';
|
||||
$SQLquery = 'SELECT `value`';
|
||||
$SQLquery .= ' FROM `'.mysql_real_escape_string($this->table).'`';
|
||||
$SQLquery .= ' WHERE (`filename` = \''.mysql_real_escape_string(getID3::VERSION).'\')';
|
||||
$SQLquery .= ' AND (`filesize` = -1)';
|
||||
$SQLquery .= ' AND (`filetime` = -1)';
|
||||
$SQLquery .= ' AND (`analyzetime` = -1)';
|
||||
if ($this->cursor = mysql_query($SQLquery, $this->connection)) {
|
||||
list($version) = mysql_fetch_array($this->cursor);
|
||||
}
|
||||
if ($version != getID3::VERSION) {
|
||||
$this->clear_cache();
|
||||
}
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* clear cache
|
||||
*/
|
||||
public function clear_cache() {
|
||||
|
||||
$this->cursor = mysql_query('DELETE FROM `'.mysql_real_escape_string($this->table).'`', $this->connection);
|
||||
$this->cursor = mysql_query('INSERT INTO `'.mysql_real_escape_string($this->table).'` VALUES (\''.getID3::VERSION.'\', -1, -1, -1, \''.getID3::VERSION.'\')', $this->connection);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* analyze file
|
||||
*
|
||||
* @param string $filename
|
||||
* @param int $filesize
|
||||
* @param string $original_filename
|
||||
* @param resource $fp
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function analyze($filename, $filesize=null, $original_filename='', $fp=null) {
|
||||
|
||||
$filetime = 0;
|
||||
if (file_exists($filename)) {
|
||||
|
||||
// Short-hands
|
||||
$filetime = filemtime($filename);
|
||||
$filesize = filesize($filename);
|
||||
|
||||
// Lookup file
|
||||
$SQLquery = 'SELECT `value`';
|
||||
$SQLquery .= ' FROM `'.mysql_real_escape_string($this->table).'`';
|
||||
$SQLquery .= ' WHERE (`filename` = \''.mysql_real_escape_string($filename).'\')';
|
||||
$SQLquery .= ' AND (`filesize` = \''.mysql_real_escape_string($filesize).'\')';
|
||||
$SQLquery .= ' AND (`filetime` = \''.mysql_real_escape_string($filetime).'\')';
|
||||
$this->cursor = mysql_query($SQLquery, $this->connection);
|
||||
if (mysql_num_rows($this->cursor) > 0) {
|
||||
// Hit
|
||||
list($result) = mysql_fetch_array($this->cursor);
|
||||
return unserialize(base64_decode($result));
|
||||
}
|
||||
}
|
||||
|
||||
// Miss
|
||||
$analysis = parent::analyze($filename, $filesize, $original_filename, $fp);
|
||||
|
||||
// Save result
|
||||
if (file_exists($filename)) {
|
||||
$SQLquery = 'INSERT INTO `'.mysql_real_escape_string($this->table).'` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (';
|
||||
$SQLquery .= '\''.mysql_real_escape_string($filename).'\'';
|
||||
$SQLquery .= ', \''.mysql_real_escape_string($filesize).'\'';
|
||||
$SQLquery .= ', \''.mysql_real_escape_string($filetime).'\'';
|
||||
$SQLquery .= ', \''.mysql_real_escape_string(time() ).'\'';
|
||||
$SQLquery .= ', \''.mysql_real_escape_string(base64_encode(serialize($analysis))).'\')';
|
||||
$this->cursor = mysql_query($SQLquery, $this->connection);
|
||||
}
|
||||
return $analysis;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* (re)create sql table
|
||||
*
|
||||
* @param bool $drop
|
||||
*/
|
||||
private function create_table($drop=false) {
|
||||
|
||||
$SQLquery = 'CREATE TABLE IF NOT EXISTS `'.mysql_real_escape_string($this->table).'` (';
|
||||
$SQLquery .= '`filename` VARCHAR(990) NOT NULL DEFAULT \'\'';
|
||||
$SQLquery .= ', `filesize` INT(11) NOT NULL DEFAULT \'0\'';
|
||||
$SQLquery .= ', `filetime` INT(11) NOT NULL DEFAULT \'0\'';
|
||||
$SQLquery .= ', `analyzetime` INT(11) NOT NULL DEFAULT \'0\'';
|
||||
$SQLquery .= ', `value` LONGTEXT NOT NULL';
|
||||
$SQLquery .= ', PRIMARY KEY (`filename`, `filesize`, `filetime`))';
|
||||
$this->cursor = mysql_query($SQLquery, $this->connection);
|
||||
echo mysql_error($this->connection);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// extension.cache.mysqli.php - part of getID3() //
|
||||
// Please see readme.txt for more information //
|
||||
// //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// This extension written by Allan Hansen <ahØartemis*dk> //
|
||||
// Table name mod by Carlo Capocasa <calroØcarlocapocasa*com> //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* This is a caching extension for getID3(). It works the exact same
|
||||
* way as the getID3 class, but return cached information very fast
|
||||
*
|
||||
* Example: (see also demo.cache.mysql.php in /demo/)
|
||||
*
|
||||
* Normal getID3 usage (example):
|
||||
*
|
||||
* require_once 'getid3/getid3.php';
|
||||
* $getID3 = new getID3;
|
||||
* $getID3->encoding = 'UTF-8';
|
||||
* $info1 = $getID3->analyze('file1.flac');
|
||||
* $info2 = $getID3->analyze('file2.wv');
|
||||
*
|
||||
* getID3_cached usage:
|
||||
*
|
||||
* require_once 'getid3/getid3.php';
|
||||
* require_once 'getid3/getid3/extension.cache.mysqli.php';
|
||||
* // 5th parameter (tablename) is optional, default is 'getid3_cache'
|
||||
* $getID3 = new getID3_cached_mysqli('localhost', 'database', 'username', 'password', 'tablename');
|
||||
* $getID3->encoding = 'UTF-8';
|
||||
* $info1 = $getID3->analyze('file1.flac');
|
||||
* $info2 = $getID3->analyze('file2.wv');
|
||||
*
|
||||
*
|
||||
* Supported Cache Types (this extension)
|
||||
*
|
||||
* SQL Databases:
|
||||
*
|
||||
* cache_type cache_options
|
||||
* -------------------------------------------------------------------
|
||||
* mysqli host, database, username, password
|
||||
*
|
||||
*
|
||||
* DBM-Style Databases: (use extension.cache.dbm)
|
||||
*
|
||||
* cache_type cache_options
|
||||
* -------------------------------------------------------------------
|
||||
* gdbm dbm_filename, lock_filename
|
||||
* ndbm dbm_filename, lock_filename
|
||||
* db2 dbm_filename, lock_filename
|
||||
* db3 dbm_filename, lock_filename
|
||||
* db4 dbm_filename, lock_filename (PHP5 required)
|
||||
*
|
||||
* PHP must have write access to both dbm_filename and lock_filename.
|
||||
*
|
||||
*
|
||||
* Recommended Cache Types
|
||||
*
|
||||
* Infrequent updates, many reads any DBM
|
||||
* Frequent updates mysqli
|
||||
*/
|
||||
|
||||
class getID3_cached_mysqli extends getID3
|
||||
{
|
||||
/**
|
||||
* @var mysqli
|
||||
*/
|
||||
private $mysqli;
|
||||
|
||||
/**
|
||||
* @var mysqli_result
|
||||
*/
|
||||
private $cursor;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $table;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $db_structure_check;
|
||||
|
||||
|
||||
/**
|
||||
* constructor - see top of this file for cache type and cache_options
|
||||
*
|
||||
* @param string $host
|
||||
* @param string $database
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param string $table
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws getid3_exception
|
||||
*/
|
||||
public function __construct($host, $database, $username, $password, $table='getid3_cache') {
|
||||
|
||||
// Check for mysqli support
|
||||
if (!function_exists('mysqli_connect')) {
|
||||
throw new Exception('PHP not compiled with mysqli support.');
|
||||
}
|
||||
|
||||
// Connect to database
|
||||
$this->mysqli = new mysqli($host, $username, $password);
|
||||
if ($this->mysqli->connect_error) {
|
||||
throw new Exception('Connect Error (' . $this->mysqli->connect_errno . ') ' . $this->mysqli->connect_error);
|
||||
}
|
||||
|
||||
// Select database
|
||||
if (!$this->mysqli->select_db($database)) {
|
||||
throw new Exception('Cannot use database '.$database);
|
||||
}
|
||||
|
||||
// Set table
|
||||
$this->table = $table;
|
||||
|
||||
// Create cache table if not exists
|
||||
$this->create_table();
|
||||
|
||||
$this->db_structure_check = true; // set to false if you know your table structure has already been migrated to use `hash` as the primary key to avoid
|
||||
$this->migrate_db_structure();
|
||||
|
||||
// Check version number and clear cache if changed
|
||||
$version = '';
|
||||
$SQLquery = 'SELECT `value`';
|
||||
$SQLquery .= ' FROM `'.$this->mysqli->real_escape_string($this->table).'`';
|
||||
$SQLquery .= ' WHERE (`filename` = \''.$this->mysqli->real_escape_string(getID3::VERSION).'\')';
|
||||
$SQLquery .= ' AND (`hash` = \'getID3::VERSION\')';
|
||||
if ($this->cursor = $this->mysqli->query($SQLquery)) {
|
||||
list($version) = $this->cursor->fetch_array();
|
||||
}
|
||||
if ($version != getID3::VERSION) {
|
||||
$this->clear_cache();
|
||||
}
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* clear cache
|
||||
*/
|
||||
public function clear_cache() {
|
||||
$this->mysqli->query('TRUNCATE TABLE `'.$this->mysqli->real_escape_string($this->table).'`');
|
||||
$this->mysqli->query('INSERT INTO `'.$this->mysqli->real_escape_string($this->table).'` (`hash`, `filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (\'getID3::VERSION\', \''.getID3::VERSION.'\', -1, -1, -1, \''.getID3::VERSION.'\')');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* migrate database structure if needed
|
||||
*/
|
||||
public function migrate_db_structure() {
|
||||
// Check for table structure
|
||||
if ($this->db_structure_check) {
|
||||
$SQLquery = 'SHOW COLUMNS';
|
||||
$SQLquery .= ' FROM `'.$this->mysqli->real_escape_string($this->table).'`';
|
||||
$SQLquery .= ' LIKE \'hash\'';
|
||||
$this->cursor = $this->mysqli->query($SQLquery);
|
||||
if ($this->cursor->num_rows == 0) {
|
||||
// table has not been migrated, add column, add hashes, change index
|
||||
$SQLquery = 'ALTER TABLE `getid3_cache` DROP PRIMARY KEY, ADD `hash` CHAR(32) NOT NULL DEFAULT \'\' FIRST, ADD PRIMARY KEY(`hash`)';
|
||||
$this->mysqli->query($SQLquery);
|
||||
|
||||
$SQLquery = 'UPDATE `getid3_cache` SET';
|
||||
$SQLquery .= ' `hash` = MD5(`filename`, `filesize`, `filetime`)';
|
||||
$SQLquery .= ' WHERE (`filesize` > -1)';
|
||||
$this->mysqli->query($SQLquery);
|
||||
|
||||
$SQLquery = 'UPDATE `getid3_cache` SET';
|
||||
$SQLquery .= ' `hash` = \'getID3::VERSION\'';
|
||||
$SQLquery .= ' WHERE (`filesize` = -1)';
|
||||
$SQLquery .= ' AND (`filetime` = -1)';
|
||||
$SQLquery .= ' AND (`filetime` = -1)';
|
||||
$this->mysqli->query($SQLquery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* analyze file
|
||||
*
|
||||
* @param string $filename
|
||||
* @param int $filesize
|
||||
* @param string $original_filename
|
||||
* @param resource $fp
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function analyze($filename, $filesize=null, $original_filename='', $fp=null) {
|
||||
|
||||
$filetime = 0;
|
||||
if (file_exists($filename)) {
|
||||
|
||||
// Short-hands
|
||||
$filetime = filemtime($filename);
|
||||
$filesize = filesize($filename);
|
||||
|
||||
// Lookup file
|
||||
$SQLquery = 'SELECT `value`';
|
||||
$SQLquery .= ' FROM `'.$this->mysqli->real_escape_string($this->table).'`';
|
||||
$SQLquery .= ' WHERE (`hash` = \''.$this->mysqli->real_escape_string(md5($filename.$filesize.$filetime)).'\')';
|
||||
$this->cursor = $this->mysqli->query($SQLquery);
|
||||
if ($this->cursor->num_rows > 0) {
|
||||
// Hit
|
||||
list($result) = $this->cursor->fetch_array();
|
||||
return unserialize(base64_decode($result));
|
||||
}
|
||||
}
|
||||
|
||||
// Miss
|
||||
$analysis = parent::analyze($filename, $filesize, $original_filename, $fp);
|
||||
|
||||
// Save result
|
||||
if (file_exists($filename)) {
|
||||
$SQLquery = 'INSERT INTO `'.$this->mysqli->real_escape_string($this->table).'` (`hash`, `filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (';
|
||||
$SQLquery .= '\''.$this->mysqli->real_escape_string(md5($filename.$filesize.$filetime)).'\'';
|
||||
$SQLquery .= ', \''.$this->mysqli->real_escape_string($filename).'\'';
|
||||
$SQLquery .= ', \''.$this->mysqli->real_escape_string($filesize).'\'';
|
||||
$SQLquery .= ', \''.$this->mysqli->real_escape_string($filetime).'\'';
|
||||
$SQLquery .= ', UNIX_TIMESTAMP()';
|
||||
$SQLquery .= ', \''.$this->mysqli->real_escape_string(base64_encode(serialize($analysis))).'\'';
|
||||
$SQLquery .= ')';
|
||||
$this->cursor = $this->mysqli->query($SQLquery);
|
||||
}
|
||||
return $analysis;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* (re)create mysqli table
|
||||
*
|
||||
* @param bool $drop
|
||||
*/
|
||||
private function create_table($drop=false) {
|
||||
if ($drop) {
|
||||
$SQLquery = 'DROP TABLE IF EXISTS `'.$this->mysqli->real_escape_string($this->table).'`';
|
||||
$this->mysqli->query($SQLquery);
|
||||
}
|
||||
$SQLquery = 'CREATE TABLE IF NOT EXISTS `'.$this->mysqli->real_escape_string($this->table).'` (';
|
||||
$SQLquery .= '`hash` CHAR(32) NOT NULL DEFAULT \'\'';
|
||||
$SQLquery .= ', `filename` VARCHAR(1000) NOT NULL DEFAULT \'\'';
|
||||
$SQLquery .= ', `filesize` INT(11) NOT NULL DEFAULT \'0\'';
|
||||
$SQLquery .= ', `filetime` INT(11) NOT NULL DEFAULT \'0\'';
|
||||
$SQLquery .= ', `analyzetime` INT(11) NOT NULL DEFAULT \'0\'';
|
||||
$SQLquery .= ', `value` LONGTEXT NOT NULL';
|
||||
$SQLquery .= ', PRIMARY KEY (`hash`))';
|
||||
$this->cursor = $this->mysqli->query($SQLquery);
|
||||
echo $this->mysqli->error;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,297 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// //
|
||||
// extension.cache.mysqli.php - part of getID3() //
|
||||
// Please see readme.txt for more information //
|
||||
// //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// extension.cache.sqlite3.php - part of getID3() //
|
||||
// Please see readme.txt for more information //
|
||||
// //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// //
|
||||
// MySQL extension written by Allan Hansen <ahØartemis*dk> //
|
||||
// Table name mod by Carlo Capocasa <calroØcarlocapocasa*com> //
|
||||
// MySQL extension was reworked for SQLite3 by //
|
||||
// Karl G. Holz <newaeonØmac*com> //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* This is a caching extension for getID3(). It works the exact same
|
||||
* way as the getID3 class, but return cached information much faster
|
||||
*
|
||||
* Normal getID3 usage (example):
|
||||
*
|
||||
* require_once 'getid3/getid3.php';
|
||||
* $getID3 = new getID3;
|
||||
* $getID3->encoding = 'UTF-8';
|
||||
* $info1 = $getID3->analyze('file1.flac');
|
||||
* $info2 = $getID3->analyze('file2.wv');
|
||||
*
|
||||
* getID3_cached usage:
|
||||
*
|
||||
* require_once 'getid3/getid3.php';
|
||||
* require_once 'getid3/extension.cache.sqlite3.php';
|
||||
* // all parameters are optional, defaults are:
|
||||
* $getID3 = new getID3_cached_sqlite3($table='getid3_cache', $hide=FALSE);
|
||||
* $getID3->encoding = 'UTF-8';
|
||||
* $info1 = $getID3->analyze('file1.flac');
|
||||
* $info2 = $getID3->analyze('file2.wv');
|
||||
*
|
||||
*
|
||||
* Supported Cache Types (this extension)
|
||||
*
|
||||
* SQL Databases:
|
||||
*
|
||||
* cache_type cache_options
|
||||
* -------------------------------------------------------------------
|
||||
* mysql host, database, username, password
|
||||
*
|
||||
* sqlite3 table='getid3_cache', hide=false (PHP5)
|
||||
*
|
||||
*
|
||||
* *** database file will be stored in the same directory as this script,
|
||||
* *** webserver must have write access to that directory!
|
||||
* *** set $hide to TRUE to prefix db file with .ht to pervent access from web client
|
||||
* *** this is a default setting in the Apache configuration:
|
||||
*
|
||||
* The following lines prevent .htaccess and .htpasswd files from being viewed by Web clients.
|
||||
*
|
||||
* <Files ~ "^\.ht">
|
||||
* Order allow,deny
|
||||
* Deny from all
|
||||
* Satisfy all
|
||||
* </Files>
|
||||
*
|
||||
********************************************************************************
|
||||
*
|
||||
* -------------------------------------------------------------------
|
||||
* DBM-Style Databases: (use extension.cache.dbm)
|
||||
*
|
||||
* cache_type cache_options
|
||||
* -------------------------------------------------------------------
|
||||
* gdbm dbm_filename, lock_filename
|
||||
* ndbm dbm_filename, lock_filename
|
||||
* db2 dbm_filename, lock_filename
|
||||
* db3 dbm_filename, lock_filename
|
||||
* db4 dbm_filename, lock_filename (PHP5 required)
|
||||
*
|
||||
* PHP must have write access to both dbm_filename and lock_filename.
|
||||
*
|
||||
* Recommended Cache Types
|
||||
*
|
||||
* Infrequent updates, many reads any DBM
|
||||
* Frequent updates mysql
|
||||
********************************************************************************
|
||||
*
|
||||
* IMHO this is still a bit slow, I'm using this with MP4/MOV/ M4v files
|
||||
* there is a plan to add directory scanning and analyzing to make things work much faster
|
||||
*
|
||||
*
|
||||
*/
|
||||
class getID3_cached_sqlite3 extends getID3
|
||||
{
|
||||
/**
|
||||
* hold the sqlite db
|
||||
*
|
||||
* @var SQLite3 Resource
|
||||
*/
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* table to use for caching
|
||||
*
|
||||
* @var string $table
|
||||
*/
|
||||
private $table;
|
||||
|
||||
/**
|
||||
* @param string $table holds name of sqlite table
|
||||
* @param boolean $hide
|
||||
*
|
||||
* @throws getid3_exception
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct($table='getid3_cache', $hide=false) {
|
||||
// Check for SQLite3 support
|
||||
if (!function_exists('sqlite_open')) {
|
||||
throw new Exception('PHP not compiled with SQLite3 support.');
|
||||
}
|
||||
|
||||
$this->table = $table; // Set table
|
||||
$file = dirname(__FILE__).'/'.basename(__FILE__, 'php').'sqlite';
|
||||
if ($hide) {
|
||||
$file = dirname(__FILE__).'/.ht.'.basename(__FILE__, 'php').'sqlite';
|
||||
}
|
||||
$this->db = new SQLite3($file);
|
||||
$db = $this->db;
|
||||
$this->create_table(); // Create cache table if not exists
|
||||
$version = '';
|
||||
$sql = $this->getQuery('version_check');
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->bindValue(':filename', getID3::VERSION, SQLITE3_TEXT);
|
||||
$result = $stmt->execute();
|
||||
list($version) = $result->fetchArray();
|
||||
if ($version != getID3::VERSION) { // Check version number and clear cache if changed
|
||||
$this->clear_cache();
|
||||
}
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* close the database connection
|
||||
*/
|
||||
public function __destruct() {
|
||||
$db=$this->db;
|
||||
$db->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* clear the cache
|
||||
*
|
||||
* @return SQLite3Result
|
||||
*/
|
||||
private function clear_cache() {
|
||||
$db = $this->db;
|
||||
$sql = $this->getQuery('delete_cache');
|
||||
$db->exec($sql);
|
||||
$sql = $this->getQuery('set_version');
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->bindValue(':filename', getID3::VERSION, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':dirname', getID3::VERSION, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':val', getID3::VERSION, SQLITE3_TEXT);
|
||||
return $stmt->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* analyze file and cache them, if cached pull from the db
|
||||
*
|
||||
* @param string $filename
|
||||
* @param integer $filesize
|
||||
* @param string $original_filename
|
||||
* @param resource $fp
|
||||
*
|
||||
* @return mixed|false
|
||||
*/
|
||||
public function analyze($filename, $filesize=null, $original_filename='', $fp=null) {
|
||||
if (!file_exists($filename)) {
|
||||
return false;
|
||||
}
|
||||
// items to track for caching
|
||||
$filetime = filemtime($filename);
|
||||
$filesize_real = filesize($filename);
|
||||
// this will be saved for a quick directory lookup of analized files
|
||||
// ... why do 50 seperate sql quries when you can do 1 for the same result
|
||||
$dirname = dirname($filename);
|
||||
// Lookup file
|
||||
$db = $this->db;
|
||||
$sql = $this->getQuery('get_id3_data');
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->bindValue(':filename', $filename, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':filesize', $filesize_real, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER);
|
||||
$res = $stmt->execute();
|
||||
list($result) = $res->fetchArray();
|
||||
if (count($result) > 0 ) {
|
||||
return unserialize(base64_decode($result));
|
||||
}
|
||||
// if it hasn't been analyzed before, then do it now
|
||||
$analysis = parent::analyze($filename, $filesize, $original_filename, $fp);
|
||||
// Save result
|
||||
$sql = $this->getQuery('cache_file');
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->bindValue(':filename', $filename, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':dirname', $dirname, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':filesize', $filesize_real, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':atime', time(), SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':val', base64_encode(serialize($analysis)), SQLITE3_TEXT);
|
||||
$res = $stmt->execute();
|
||||
return $analysis;
|
||||
}
|
||||
|
||||
/**
|
||||
* create data base table
|
||||
* this is almost the same as MySQL, with the exception of the dirname being added
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function create_table() {
|
||||
$db = $this->db;
|
||||
$sql = $this->getQuery('make_table');
|
||||
return $db->exec($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* get cached directory
|
||||
*
|
||||
* This function is not in the MySQL extention, it's ment to speed up requesting multiple files
|
||||
* which is ideal for podcasting, playlists, etc.
|
||||
*
|
||||
* @param string $dir directory to search the cache database for
|
||||
*
|
||||
* @return array return an array of matching id3 data
|
||||
*/
|
||||
public function get_cached_dir($dir) {
|
||||
$db = $this->db;
|
||||
$rows = array();
|
||||
$sql = $this->getQuery('get_cached_dir');
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->bindValue(':dirname', $dir, SQLITE3_TEXT);
|
||||
$res = $stmt->execute();
|
||||
while ($row=$res->fetchArray()) {
|
||||
$rows[] = unserialize(base64_decode($row));
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns NULL if query is not found
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getQuery($name)
|
||||
{
|
||||
switch ($name) {
|
||||
case 'version_check':
|
||||
return "SELECT val FROM $this->table WHERE filename = :filename AND filesize = '-1' AND filetime = '-1' AND analyzetime = '-1'";
|
||||
case 'delete_cache':
|
||||
return "DELETE FROM $this->table";
|
||||
case 'set_version':
|
||||
return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, -1, -1, -1, :val)";
|
||||
case 'get_id3_data':
|
||||
return "SELECT val FROM $this->table WHERE filename = :filename AND filesize = :filesize AND filetime = :filetime";
|
||||
case 'cache_file':
|
||||
return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, :filesize, :filetime, :atime, :val)";
|
||||
case 'make_table':
|
||||
return "CREATE TABLE IF NOT EXISTS $this->table (filename VARCHAR(255) DEFAULT '', dirname VARCHAR(255) DEFAULT '', filesize INT(11) DEFAULT '0', filetime INT(11) DEFAULT '0', analyzetime INT(11) DEFAULT '0', val text, PRIMARY KEY (filename, filesize, filetime))";
|
||||
case 'get_cached_dir':
|
||||
return "SELECT val FROM $this->table WHERE dirname = :dirname";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* use the magical __get() for sql queries
|
||||
*
|
||||
* access as easy as $this->{case name}, returns NULL if query is not found
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
* @deprecated use getQuery() instead
|
||||
*/
|
||||
public function __get($name) {
|
||||
return $this->getQuery($name);
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,10 +1,11 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.archive.gzip.php //
|
||||
|
@ -14,34 +15,50 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Module originally written by //
|
||||
// Mike Mozolin <teddybearØmail*ru> //
|
||||
// Mike Mozolin <teddybearØmail*ru> //
|
||||
// //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
class getid3_gzip {
|
||||
class getid3_gzip extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* Optional file list - disable for speed.
|
||||
* Decode gzipped files, if possible, and parse recursively (.tar.gz for example).
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $parse_contents = false;
|
||||
|
||||
// public: Optional file list - disable for speed.
|
||||
var $option_gzip_parse_contents = false; // decode gzipped files, if possible, and parse recursively (.tar.gz for example)
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
function getid3_gzip(&$fd, &$ThisFileInfo) {
|
||||
$ThisFileInfo['fileformat'] = 'gzip';
|
||||
$info['fileformat'] = 'gzip';
|
||||
|
||||
$start_length = 10;
|
||||
$unpack_header = 'a1id1/a1id2/a1cmethod/a1flags/a4mtime/a1xflags/a1os';
|
||||
//+---+---+---+---+---+---+---+---+---+---+
|
||||
//|ID1|ID2|CM |FLG| MTIME |XFL|OS |
|
||||
//+---+---+---+---+---+---+---+---+---+---+
|
||||
ob_start();
|
||||
fseek($fd, 0);
|
||||
$buffer = fread($fd, $ThisFileInfo['filesize']);
|
||||
$errormessage = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
if ($info['php_memory_limit'] && ($info['filesize'] > $info['php_memory_limit'])) {
|
||||
$this->error('File is too large ('.number_format($info['filesize']).' bytes) to read into memory (limit: '.number_format($info['php_memory_limit'] / 1048576).'MB)');
|
||||
return false;
|
||||
}
|
||||
$this->fseek(0);
|
||||
$buffer = $this->fread($info['filesize']);
|
||||
|
||||
$arr_members = explode("\x1F\x8B\x08", $buffer);
|
||||
$num_members = 0;
|
||||
while (true) {
|
||||
$is_wrong_members = false;
|
||||
$num_members = intval(count($arr_members));
|
||||
$num_members = count($arr_members);
|
||||
for ($i = 0; $i < $num_members; $i++) {
|
||||
if (strlen($arr_members[$i]) == 0) {
|
||||
continue;
|
||||
|
@ -51,7 +68,7 @@ class getid3_gzip {
|
|||
$attr = unpack($unpack_header, substr($buf, 0, $start_length));
|
||||
if (!$this->get_os_type(ord($attr['os']))) {
|
||||
// Merge member with previous if wrong OS type
|
||||
$arr_members[$i - 1] .= $buf;
|
||||
$arr_members[($i - 1)] .= $buf;
|
||||
$arr_members[$i] = '';
|
||||
$is_wrong_members = true;
|
||||
continue;
|
||||
|
@ -62,37 +79,37 @@ class getid3_gzip {
|
|||
}
|
||||
}
|
||||
|
||||
$ThisFileInfo['gzip']['files'] = array();
|
||||
$info['gzip']['files'] = array();
|
||||
|
||||
$fpointer = 0;
|
||||
$idx = 0;
|
||||
for ($i = 0; $i < $num_members; $i++) {
|
||||
if (strlen($arr_members[$i]) == 0) {
|
||||
foreach ($arr_members as $member) {
|
||||
if (strlen($member) == 0) {
|
||||
continue;
|
||||
}
|
||||
$thisThisFileInfo = &$ThisFileInfo['gzip']['member_header'][++$idx];
|
||||
$thisInfo = &$info['gzip']['member_header'][++$idx];
|
||||
|
||||
$buff = "\x1F\x8B\x08".$arr_members[$i];
|
||||
$buff = "\x1F\x8B\x08". $member;
|
||||
|
||||
$attr = unpack($unpack_header, substr($buff, 0, $start_length));
|
||||
$thisThisFileInfo['filemtime'] = getid3_lib::LittleEndian2Int($attr['mtime']);
|
||||
$thisThisFileInfo['raw']['id1'] = ord($attr['cmethod']);
|
||||
$thisThisFileInfo['raw']['id2'] = ord($attr['cmethod']);
|
||||
$thisThisFileInfo['raw']['cmethod'] = ord($attr['cmethod']);
|
||||
$thisThisFileInfo['raw']['os'] = ord($attr['os']);
|
||||
$thisThisFileInfo['raw']['xflags'] = ord($attr['xflags']);
|
||||
$thisThisFileInfo['raw']['flags'] = ord($attr['flags']);
|
||||
$thisInfo['filemtime'] = getid3_lib::LittleEndian2Int($attr['mtime']);
|
||||
$thisInfo['raw']['id1'] = ord($attr['cmethod']);
|
||||
$thisInfo['raw']['id2'] = ord($attr['cmethod']);
|
||||
$thisInfo['raw']['cmethod'] = ord($attr['cmethod']);
|
||||
$thisInfo['raw']['os'] = ord($attr['os']);
|
||||
$thisInfo['raw']['xflags'] = ord($attr['xflags']);
|
||||
$thisInfo['raw']['flags'] = ord($attr['flags']);
|
||||
|
||||
$thisThisFileInfo['flags']['crc16'] = (bool) ($thisThisFileInfo['raw']['flags'] & 0x02);
|
||||
$thisThisFileInfo['flags']['extra'] = (bool) ($thisThisFileInfo['raw']['flags'] & 0x04);
|
||||
$thisThisFileInfo['flags']['filename'] = (bool) ($thisThisFileInfo['raw']['flags'] & 0x08);
|
||||
$thisThisFileInfo['flags']['comment'] = (bool) ($thisThisFileInfo['raw']['flags'] & 0x10);
|
||||
$thisInfo['flags']['crc16'] = (bool) ($thisInfo['raw']['flags'] & 0x02);
|
||||
$thisInfo['flags']['extra'] = (bool) ($thisInfo['raw']['flags'] & 0x04);
|
||||
$thisInfo['flags']['filename'] = (bool) ($thisInfo['raw']['flags'] & 0x08);
|
||||
$thisInfo['flags']['comment'] = (bool) ($thisInfo['raw']['flags'] & 0x10);
|
||||
|
||||
$thisThisFileInfo['compression'] = $this->get_xflag_type($thisThisFileInfo['raw']['xflags']);
|
||||
$thisInfo['compression'] = $this->get_xflag_type($thisInfo['raw']['xflags']);
|
||||
|
||||
$thisThisFileInfo['os'] = $this->get_os_type($thisThisFileInfo['raw']['os']);
|
||||
if (!$thisThisFileInfo['os']) {
|
||||
$ThisFileInfo['error'][] = 'Read error on gzip file';
|
||||
$thisInfo['os'] = $this->get_os_type($thisInfo['raw']['os']);
|
||||
if (!$thisInfo['os']) {
|
||||
$this->error('Read error on gzip file');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -102,12 +119,12 @@ class getid3_gzip {
|
|||
//+---+---+=================================+
|
||||
//| XLEN |...XLEN bytes of "extra field"...|
|
||||
//+---+---+=================================+
|
||||
if ($thisThisFileInfo['flags']['extra']) {
|
||||
if ($thisInfo['flags']['extra']) {
|
||||
$w_xlen = substr($buff, $fpointer, 2);
|
||||
$xlen = getid3_lib::LittleEndian2Int($w_xlen);
|
||||
$fpointer += 2;
|
||||
|
||||
$thisThisFileInfo['raw']['xfield'] = substr($buff, $fpointer, $xlen);
|
||||
$thisInfo['raw']['xfield'] = substr($buff, $fpointer, $xlen);
|
||||
// Extra SubFields
|
||||
//+---+---+---+---+==================================+
|
||||
//|SI1|SI2| LEN |... LEN bytes of subfield data ...|
|
||||
|
@ -136,14 +153,15 @@ class getid3_gzip {
|
|||
//|...original file name, zero-terminated...|
|
||||
//+=========================================+
|
||||
// GZIP files may have only one file, with no filename, so assume original filename is current filename without .gz
|
||||
$thisThisFileInfo['filename'] = preg_replace('#\.gz$#i', '', $ThisFileInfo['filename']);
|
||||
if ($thisThisFileInfo['flags']['filename']) {
|
||||
$thisInfo['filename'] = preg_replace('#\\.gz$#i', '', $info['filename']);
|
||||
if ($thisInfo['flags']['filename']) {
|
||||
$thisInfo['filename'] = '';
|
||||
while (true) {
|
||||
if (ord($buff[$fpointer]) == 0) {
|
||||
$fpointer++;
|
||||
break;
|
||||
}
|
||||
$thisThisFileInfo['filename'] .= $buff[$fpointer];
|
||||
$thisInfo['filename'] .= $buff[$fpointer];
|
||||
$fpointer++;
|
||||
}
|
||||
}
|
||||
|
@ -151,13 +169,13 @@ class getid3_gzip {
|
|||
//+===================================+
|
||||
//|...file comment, zero-terminated...|
|
||||
//+===================================+
|
||||
if ($thisThisFileInfo['flags']['comment']) {
|
||||
if ($thisInfo['flags']['comment']) {
|
||||
while (true) {
|
||||
if (ord($buff[$fpointer]) == 0) {
|
||||
$fpointer++;
|
||||
break;
|
||||
}
|
||||
$thisThisFileInfo['comment'] .= $buff[$fpointer];
|
||||
$thisInfo['comment'] .= $buff[$fpointer];
|
||||
$fpointer++;
|
||||
}
|
||||
}
|
||||
|
@ -165,23 +183,23 @@ class getid3_gzip {
|
|||
//+---+---+
|
||||
//| CRC16 |
|
||||
//+---+---+
|
||||
if ($thisThisFileInfo['flags']['crc16']) {
|
||||
if ($thisInfo['flags']['crc16']) {
|
||||
$w_crc = substr($buff, $fpointer, 2);
|
||||
$thisThisFileInfo['crc16'] = getid3_lib::LittleEndian2Int($w_crc);
|
||||
$thisInfo['crc16'] = getid3_lib::LittleEndian2Int($w_crc);
|
||||
$fpointer += 2;
|
||||
}
|
||||
// bit 0 - FLG.FTEXT
|
||||
//if ($thisThisFileInfo['raw']['flags'] & 0x01) {
|
||||
//if ($thisInfo['raw']['flags'] & 0x01) {
|
||||
// Ignored...
|
||||
//}
|
||||
// bits 5, 6, 7 - reserved
|
||||
|
||||
$thisThisFileInfo['crc32'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 8, 4));
|
||||
$thisThisFileInfo['filesize'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 4));
|
||||
$thisInfo['crc32'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 8, 4));
|
||||
$thisInfo['filesize'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 4));
|
||||
|
||||
$ThisFileInfo['gzip']['files'] = getid3_lib::array_merge_clobber($ThisFileInfo['gzip']['files'], getid3_lib::CreateDeepArray($thisThisFileInfo['filename'], '/', $thisThisFileInfo['filesize']));
|
||||
$info['gzip']['files'] = getid3_lib::array_merge_clobber($info['gzip']['files'], getid3_lib::CreateDeepArray($thisInfo['filename'], '/', $thisInfo['filesize']));
|
||||
|
||||
if ($this->option_gzip_parse_contents) {
|
||||
if ($this->parse_contents) {
|
||||
// Try to inflate GZip
|
||||
$csize = 0;
|
||||
$inflated = '';
|
||||
|
@ -193,13 +211,13 @@ class getid3_gzip {
|
|||
$inflated = gzinflate($cdata);
|
||||
|
||||
// Calculate CRC32 for inflated content
|
||||
$thisThisFileInfo['crc32_valid'] = (bool) (sprintf('%u', crc32($inflated)) == $thisThisFileInfo['crc32']);
|
||||
$thisInfo['crc32_valid'] = sprintf('%u', crc32($inflated)) == $thisInfo['crc32'];
|
||||
|
||||
// determine format
|
||||
$formattest = substr($inflated, 0, 32774);
|
||||
$newgetID3 = new getID3();
|
||||
$determined_format = $newgetID3->GetFileFormat($formattest);
|
||||
unset($newgetID3);
|
||||
$getid3_temp = new getID3();
|
||||
$determined_format = $getid3_temp->GetFileFormat($formattest);
|
||||
unset($getid3_temp);
|
||||
|
||||
// file format is determined
|
||||
$determined_format['module'] = (isset($determined_format['module']) ? $determined_format['module'] : '');
|
||||
|
@ -209,20 +227,21 @@ class getid3_gzip {
|
|||
if (file_exists(GETID3_INCLUDEPATH.$determined_format['include']) && include_once(GETID3_INCLUDEPATH.$determined_format['include'])) {
|
||||
if (($temp_tar_filename = tempnam(GETID3_TEMP_DIR, 'getID3')) === false) {
|
||||
// can't find anywhere to create a temp file, abort
|
||||
$ThisFileInfo['error'][] = 'Unable to create temp file to parse TAR inside GZIP file';
|
||||
$this->error('Unable to create temp file to parse TAR inside GZIP file');
|
||||
break;
|
||||
}
|
||||
if ($fp_temp_tar = fopen($temp_tar_filename, 'w+b')) {
|
||||
fwrite($fp_temp_tar, $inflated);
|
||||
rewind($fp_temp_tar);
|
||||
$getid3_tar = new getid3_tar($fp_temp_tar, $dummy);
|
||||
$ThisFileInfo['gzip']['member_header'][$idx]['tar'] = $dummy['tar'];
|
||||
unset($dummy);
|
||||
unset($getid3_tar);
|
||||
fclose($fp_temp_tar);
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($temp_tar_filename);
|
||||
$getid3_tar = new getid3_tar($getid3_temp);
|
||||
$getid3_tar->Analyze();
|
||||
$info['gzip']['member_header'][$idx]['tar'] = $getid3_temp->info['tar'];
|
||||
unset($getid3_temp, $getid3_tar);
|
||||
unlink($temp_tar_filename);
|
||||
} else {
|
||||
$ThisFileInfo['error'][] = 'Unable to fopen() temp file to parse TAR inside GZIP file';
|
||||
$this->error('Unable to fopen() temp file to parse TAR inside GZIP file');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -233,14 +252,22 @@ class getid3_gzip {
|
|||
// unknown or unhandled format
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$this->warning('PHP is not compiled with gzinflate() support. Please enable PHP Zlib extension or recompile with the --with-zlib switch');
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Converts the OS type
|
||||
function get_os_type($key) {
|
||||
/**
|
||||
* Converts the OS type.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_os_type($key) {
|
||||
static $os_type = array(
|
||||
'0' => 'FAT filesystem (MS-DOS, OS/2, NT/Win32)',
|
||||
'1' => 'Amiga',
|
||||
|
@ -261,8 +288,14 @@ class getid3_gzip {
|
|||
return (isset($os_type[$key]) ? $os_type[$key] : '');
|
||||
}
|
||||
|
||||
// Converts the eXtra FLags
|
||||
function get_xflag_type($key) {
|
||||
/**
|
||||
* Converts the eXtra FLags.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_xflag_type($key) {
|
||||
static $xflag_type = array(
|
||||
'0' => 'unknown',
|
||||
'2' => 'maximum compression',
|
||||
|
@ -272,4 +305,3 @@ class getid3_gzip {
|
|||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.archive.hpk.php //
|
||||
// module for analyzing HPK files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
class getid3_hpk extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'hpk';
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$HPKheader = $this->fread(36);
|
||||
|
||||
if (substr($HPKheader, 0, 4) == 'BPUL') {
|
||||
|
||||
$info['hpk']['header']['signature'] = substr($HPKheader, 0, 4);
|
||||
$info['hpk']['header']['data_offset'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 4, 4));
|
||||
$info['hpk']['header']['fragments_per_file'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 8, 4));
|
||||
//$info['hpk']['header']['unknown1'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 12, 4));
|
||||
$info['hpk']['header']['fragments_residual_offset'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 16, 4));
|
||||
$info['hpk']['header']['fragments_residual_count'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 20, 4));
|
||||
//$info['hpk']['header']['unknown2'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 24, 4));
|
||||
$info['hpk']['header']['fragmented_filesystem_offset'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 28, 4));
|
||||
$info['hpk']['header']['fragmented_filesystem_length'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 32, 4));
|
||||
|
||||
$info['hpk']['header']['filesystem_entries'] = $info['hpk']['header']['fragmented_filesystem_length'] / ($info['hpk']['header']['fragments_per_file'] * 8);
|
||||
$this->fseek($info['hpk']['header']['fragmented_filesystem_offset']);
|
||||
for ($i = 0; $i < $info['hpk']['header']['filesystem_entries']; $i++) {
|
||||
$offset = getid3_lib::LittleEndian2Int($this->fread(4));
|
||||
$length = getid3_lib::LittleEndian2Int($this->fread(4));
|
||||
$info['hpk']['filesystem'][$i] = array('offset' => $offset, 'length' => $length);
|
||||
}
|
||||
|
||||
$this->error('HPK parsing incomplete (and mostly broken) in this version of getID3() ['.$this->getid3->version().']');
|
||||
|
||||
/*
|
||||
$filename = '';
|
||||
$dirs = array();
|
||||
foreach ($info['hpk']['filesystem'] as $key => $filesystemdata) {
|
||||
$this->fseek($filesystemdata['offset']);
|
||||
$first4 = $this->fread(4);
|
||||
if (($first4 == 'LZ4 ') || ($first4 == 'ZLIB')) {
|
||||
// actual data, ignore
|
||||
$info['hpk']['toc'][$key] = array(
|
||||
'filename' => ltrim(implode('/', $dirs).'/'.$filename, '/'),
|
||||
'offset' => $filesystemdata['offset'],
|
||||
'length' => $filesystemdata['length'],
|
||||
);
|
||||
$filename = '';
|
||||
$dirs = array();
|
||||
} else {
|
||||
$fragment_index = getid3_lib::LittleEndian2Int($first4);
|
||||
$fragment_type = getid3_lib::LittleEndian2Int($this->fread(4)); // file = 0, directory = 1
|
||||
$name_length = getid3_lib::LittleEndian2Int($this->fread(2));
|
||||
if ($fragment_type == 1) {
|
||||
$dirs[] = $this->fread($name_length);
|
||||
} else {
|
||||
$filename = $this->fread($name_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
} else {
|
||||
$this->error('Expecting "BPUL" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($HPKheader, 0, 4)).'"');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.archive.rar.php //
|
||||
// module for analyzing RAR files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
class getid3_rar extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* if true use PHP RarArchive extension, if false (non-extension parsing not yet written in getID3)
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $use_php_rar_extension = true;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'rar';
|
||||
|
||||
if ($this->use_php_rar_extension === true) {
|
||||
if (function_exists('rar_open')) {
|
||||
if ($rp = rar_open($info['filenamepath'])) {
|
||||
$info['rar']['files'] = array();
|
||||
$entries = rar_list($rp);
|
||||
foreach ($entries as $entry) {
|
||||
$info['rar']['files'] = getid3_lib::array_merge_clobber($info['rar']['files'], getid3_lib::CreateDeepArray($entry->getName(), '/', $entry->getUnpackedSize()));
|
||||
}
|
||||
rar_close($rp);
|
||||
return true;
|
||||
} else {
|
||||
$this->error('failed to rar_open('.$info['filename'].')');
|
||||
}
|
||||
} else {
|
||||
$this->error('RAR support does not appear to be available in this PHP installation');
|
||||
}
|
||||
} else {
|
||||
$this->error('PHP-RAR processing has been disabled (set $getid3_rar->use_php_rar_extension=true to enable)');
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.archive.szip.php //
|
||||
|
@ -13,37 +14,43 @@
|
|||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
class getid3_szip
|
||||
class getid3_szip extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
function getid3_szip(&$fd, &$ThisFileInfo) {
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$SZIPHeader = fread($fd, 6);
|
||||
if (substr($SZIPHeader, 0, 4) != 'SZ'."\x0A\x04") {
|
||||
$ThisFileInfo['error'][] = 'Expecting "SZ[x0A][x04]" at offset '.$ThisFileInfo['avdataoffset'].', found "'.substr($SZIPHeader, 0, 4).'"';
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$SZIPHeader = $this->fread(6);
|
||||
if (substr($SZIPHeader, 0, 4) != "SZ\x0A\x04") {
|
||||
$this->error('Expecting "53 5A 0A 04" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($SZIPHeader, 0, 4)).'"');
|
||||
return false;
|
||||
}
|
||||
$info['fileformat'] = 'szip';
|
||||
$info['szip']['major_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 4, 1));
|
||||
$info['szip']['minor_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 5, 1));
|
||||
$this->error('SZIP parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
|
||||
return false;
|
||||
|
||||
$ThisFileInfo['fileformat'] = 'szip';
|
||||
|
||||
$ThisFileInfo['szip']['major_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 4, 1));
|
||||
$ThisFileInfo['szip']['minor_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 5, 1));
|
||||
|
||||
while (!feof($fd)) {
|
||||
$NextBlockID = fread($fd, 2);
|
||||
while (!$this->feof()) {
|
||||
$NextBlockID = $this->fread(2);
|
||||
switch ($NextBlockID) {
|
||||
case 'SZ':
|
||||
// Note that szip files can be concatenated, this has the same effect as
|
||||
// concatenating the files. this also means that global header blocks
|
||||
// might be present between directory/data blocks.
|
||||
fseek($fd, 4, SEEK_CUR);
|
||||
$this->fseek(4, SEEK_CUR);
|
||||
break;
|
||||
|
||||
case 'BH':
|
||||
$BHheaderbytes = getid3_lib::BigEndian2Int(fread($fd, 3));
|
||||
$BHheaderdata = fread($fd, $BHheaderbytes);
|
||||
$BHheaderbytes = getid3_lib::BigEndian2Int($this->fread(3));
|
||||
$BHheaderdata = $this->fread($BHheaderbytes);
|
||||
$BHheaderoffset = 0;
|
||||
while (strpos($BHheaderdata, "\x00", $BHheaderoffset) > 0) {
|
||||
//filename as \0 terminated string (empty string indicates end)
|
||||
|
@ -79,7 +86,7 @@ class getid3_szip
|
|||
$BHdataArray['access_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4));
|
||||
$BHheaderoffset += 4;
|
||||
|
||||
$ThisFileInfo['szip']['BH'][] = $BHdataArray;
|
||||
$info['szip']['BH'][] = $BHdataArray;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -93,5 +100,3 @@ class getid3_szip
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,10 +1,11 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.archive.tar.php //
|
||||
|
@ -14,26 +15,31 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Module originally written by //
|
||||
// Mike Mozolin <teddybearØmail*ru> //
|
||||
// Mike Mozolin <teddybearØmail*ru> //
|
||||
// //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
class getid3_tar {
|
||||
class getid3_tar extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
function getid3_tar(&$fd, &$ThisFileInfo) {
|
||||
$ThisFileInfo['fileformat'] = 'tar';
|
||||
$ThisFileInfo['tar']['files'] = array();
|
||||
$info['fileformat'] = 'tar';
|
||||
$info['tar']['files'] = array();
|
||||
|
||||
$unpack_header = 'a100fname/a8mode/a8uid/a8gid/a12size/a12mtime/a8chksum/a1typflag/a100lnkname/a6magic/a2ver/a32uname/a32gname/a8devmaj/a8devmin/a155prefix';
|
||||
$null_512k = str_repeat("\x00", 512); // end-of-file marker
|
||||
|
||||
ob_start();
|
||||
fseek($fd, 0);
|
||||
$errormessage = ob_get_contents();
|
||||
ob_end_clean();
|
||||
while (!feof($fd)) {
|
||||
$buffer = fread($fd, 512);
|
||||
$this->fseek(0);
|
||||
while (!feof($this->getid3->fp)) {
|
||||
$buffer = $this->fread(512);
|
||||
if (strlen($buffer) < 512) {
|
||||
break;
|
||||
}
|
||||
|
@ -41,13 +47,13 @@ class getid3_tar {
|
|||
// check the block
|
||||
$checksum = 0;
|
||||
for ($i = 0; $i < 148; $i++) {
|
||||
$checksum += ord($buffer{$i});
|
||||
$checksum += ord($buffer[$i]);
|
||||
}
|
||||
for ($i = 148; $i < 156; $i++) {
|
||||
$checksum += ord(' ');
|
||||
}
|
||||
for ($i = 156; $i < 512; $i++) {
|
||||
$checksum += ord($buffer{$i});
|
||||
$checksum += ord($buffer[$i]);
|
||||
}
|
||||
$attr = unpack($unpack_header, $buffer);
|
||||
$name = (isset($attr['fname'] ) ? trim($attr['fname'] ) : '');
|
||||
|
@ -82,27 +88,27 @@ class getid3_tar {
|
|||
}
|
||||
|
||||
// Read to the next chunk
|
||||
fseek($fd, $size, SEEK_CUR);
|
||||
$this->fseek($size, SEEK_CUR);
|
||||
|
||||
$diff = $size % 512;
|
||||
if ($diff != 0) {
|
||||
// Padding, throw away
|
||||
fseek($fd, (512 - $diff), SEEK_CUR);
|
||||
$this->fseek((512 - $diff), SEEK_CUR);
|
||||
}
|
||||
// Protect against tar-files with garbage at the end
|
||||
if ($name == '') {
|
||||
break;
|
||||
}
|
||||
$ThisFileInfo['tar']['file_details'][$name] = array (
|
||||
$info['tar']['file_details'][$name] = array (
|
||||
'name' => $name,
|
||||
'mode_raw' => $mode,
|
||||
'mode' => getid3_tar::display_perms($mode),
|
||||
'mode' => self::display_perms($mode),
|
||||
'uid' => $uid,
|
||||
'gid' => $gid,
|
||||
'size' => $size,
|
||||
'mtime' => $mtime,
|
||||
'chksum' => $chksum,
|
||||
'typeflag' => getid3_tar::get_flag_type($typflag),
|
||||
'typeflag' => self::get_flag_type($typflag),
|
||||
'linkname' => $lnkname,
|
||||
'magic' => $magic,
|
||||
'version' => $ver,
|
||||
|
@ -111,13 +117,19 @@ class getid3_tar {
|
|||
'devmajor' => $devmaj,
|
||||
'devminor' => $devmin
|
||||
);
|
||||
$ThisFileInfo['tar']['files'] = getid3_lib::array_merge_clobber($ThisFileInfo['tar']['files'], getid3_lib::CreateDeepArray($ThisFileInfo['tar']['file_details'][$name]['name'], '/', $size));
|
||||
$info['tar']['files'] = getid3_lib::array_merge_clobber($info['tar']['files'], getid3_lib::CreateDeepArray($info['tar']['file_details'][$name]['name'], '/', $size));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parses the file mode to file permissions
|
||||
function display_perms($mode) {
|
||||
/**
|
||||
* Parses the file mode to file permissions.
|
||||
*
|
||||
* @param int $mode
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function display_perms($mode) {
|
||||
// Determine Type
|
||||
if ($mode & 0x1000) $type='p'; // FIFO pipe
|
||||
elseif ($mode & 0x2000) $type='c'; // Character special
|
||||
|
@ -129,6 +141,9 @@ class getid3_tar {
|
|||
else $type='u'; // UNKNOWN
|
||||
|
||||
// Determine permissions
|
||||
$owner = array();
|
||||
$group = array();
|
||||
$world = array();
|
||||
$owner['read'] = (($mode & 00400) ? 'r' : '-');
|
||||
$owner['write'] = (($mode & 00200) ? 'w' : '-');
|
||||
$owner['execute'] = (($mode & 00100) ? 'x' : '-');
|
||||
|
@ -151,8 +166,14 @@ class getid3_tar {
|
|||
return $s;
|
||||
}
|
||||
|
||||
// Converts the file type
|
||||
function get_flag_type($typflag) {
|
||||
/**
|
||||
* Converts the file type.
|
||||
*
|
||||
* @param string $typflag
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function get_flag_type($typflag) {
|
||||
static $flag_types = array(
|
||||
'0' => 'LF_NORMAL',
|
||||
'1' => 'LF_LINK',
|
||||
|
@ -174,5 +195,3 @@ class getid3_tar {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.archive.xz.php //
|
||||
// module for analyzing XZ files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
class getid3_xz extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$xzheader = $this->fread(6);
|
||||
|
||||
// https://tukaani.org/xz/xz-file-format-1.0.4.txt
|
||||
$info['xz']['stream_header']['magic'] = substr($xzheader, 0, 6);
|
||||
if ($info['xz']['stream_header']['magic'] != "\xFD".'7zXZ'."\x00") {
|
||||
$this->error('Invalid XZ stream header magic (expecting FD 37 7A 58 5A 00, found '.getid3_lib::PrintHexBytes($info['xz']['stream_header']['magic']).') at offset '.$info['avdataoffset']);
|
||||
return false;
|
||||
}
|
||||
$info['fileformat'] = 'xz';
|
||||
$this->error('XZ parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,573 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.archive.zip.php //
|
||||
// module for analyzing pkZip files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
class getid3_zip extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'zip';
|
||||
$info['zip']['encoding'] = 'ISO-8859-1';
|
||||
$info['zip']['files'] = array();
|
||||
|
||||
$info['zip']['compressed_size'] = 0;
|
||||
$info['zip']['uncompressed_size'] = 0;
|
||||
$info['zip']['entries_count'] = 0;
|
||||
|
||||
if (!getid3_lib::intValueSupported($info['filesize'])) {
|
||||
$this->error('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB, not supported by PHP');
|
||||
return false;
|
||||
} else {
|
||||
$EOCDsearchData = '';
|
||||
$EOCDsearchCounter = 0;
|
||||
while ($EOCDsearchCounter++ < 512) {
|
||||
|
||||
$this->fseek(-128 * $EOCDsearchCounter, SEEK_END);
|
||||
$EOCDsearchData = $this->fread(128).$EOCDsearchData;
|
||||
|
||||
if (strstr($EOCDsearchData, 'PK'."\x05\x06")) {
|
||||
|
||||
$EOCDposition = strpos($EOCDsearchData, 'PK'."\x05\x06");
|
||||
$this->fseek((-128 * $EOCDsearchCounter) + $EOCDposition, SEEK_END);
|
||||
$info['zip']['end_central_directory'] = $this->ZIPparseEndOfCentralDirectory();
|
||||
|
||||
$this->fseek($info['zip']['end_central_directory']['directory_offset']);
|
||||
$info['zip']['entries_count'] = 0;
|
||||
while ($centraldirectoryentry = $this->ZIPparseCentralDirectory()) {
|
||||
$info['zip']['central_directory'][] = $centraldirectoryentry;
|
||||
$info['zip']['entries_count']++;
|
||||
$info['zip']['compressed_size'] += $centraldirectoryentry['compressed_size'];
|
||||
$info['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size'];
|
||||
|
||||
//if ($centraldirectoryentry['uncompressed_size'] > 0) { zero-byte files are valid
|
||||
if (!empty($centraldirectoryentry['filename'])) {
|
||||
$info['zip']['files'] = getid3_lib::array_merge_clobber($info['zip']['files'], getid3_lib::CreateDeepArray($centraldirectoryentry['filename'], '/', $centraldirectoryentry['uncompressed_size']));
|
||||
}
|
||||
}
|
||||
|
||||
if ($info['zip']['entries_count'] == 0) {
|
||||
$this->error('No Central Directory entries found (truncated file?)');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($info['zip']['end_central_directory']['comment'])) {
|
||||
$info['zip']['comments']['comment'][] = $info['zip']['end_central_directory']['comment'];
|
||||
}
|
||||
|
||||
if (isset($info['zip']['central_directory'][0]['compression_method'])) {
|
||||
$info['zip']['compression_method'] = $info['zip']['central_directory'][0]['compression_method'];
|
||||
}
|
||||
if (isset($info['zip']['central_directory'][0]['flags']['compression_speed'])) {
|
||||
$info['zip']['compression_speed'] = $info['zip']['central_directory'][0]['flags']['compression_speed'];
|
||||
}
|
||||
if (isset($info['zip']['compression_method']) && ($info['zip']['compression_method'] == 'store') && !isset($info['zip']['compression_speed'])) {
|
||||
$info['zip']['compression_speed'] = 'store';
|
||||
}
|
||||
|
||||
// secondary check - we (should) already have all the info we NEED from the Central Directory above, but scanning each
|
||||
// Local File Header entry will
|
||||
foreach ($info['zip']['central_directory'] as $central_directory_entry) {
|
||||
$this->fseek($central_directory_entry['entry_offset']);
|
||||
if ($fileentry = $this->ZIPparseLocalFileHeader()) {
|
||||
$info['zip']['entries'][] = $fileentry;
|
||||
} else {
|
||||
$this->warning('Error parsing Local File Header at offset '.$central_directory_entry['entry_offset']);
|
||||
}
|
||||
}
|
||||
|
||||
// check for EPUB files
|
||||
if (!empty($info['zip']['entries'][0]['filename']) &&
|
||||
($info['zip']['entries'][0]['filename'] == 'mimetype') &&
|
||||
($info['zip']['entries'][0]['compression_method'] == 'store') &&
|
||||
($info['zip']['entries'][0]['uncompressed_size'] == 20) &&
|
||||
isset($info['zip']['entries'][0]['data_offset'])) {
|
||||
// http://idpf.org/epub/30/spec/epub30-ocf.html
|
||||
// "3.3 OCF ZIP Container Media Type Identification
|
||||
// OCF ZIP Containers must include a mimetype file as the first file in the Container, and the contents of this file must be the MIME type string application/epub+zip.
|
||||
// The contents of the mimetype file must not contain any leading padding or whitespace, must not begin with the Unicode signature (or Byte Order Mark),
|
||||
// and the case of the MIME type string must be exactly as presented above. The mimetype file additionally must be neither compressed nor encrypted,
|
||||
// and there must not be an extra field in its ZIP header."
|
||||
$this->fseek($info['zip']['entries'][0]['data_offset']);
|
||||
if ($this->fread(20) == 'application/epub+zip') {
|
||||
$info['fileformat'] = 'zip.epub';
|
||||
$info['mime_type'] = 'application/epub+zip';
|
||||
}
|
||||
}
|
||||
|
||||
// check for Office Open XML files (e.g. .docx, .xlsx)
|
||||
if (!empty($info['zip']['files']['[Content_Types].xml']) &&
|
||||
!empty($info['zip']['files']['_rels']['.rels']) &&
|
||||
!empty($info['zip']['files']['docProps']['app.xml']) &&
|
||||
!empty($info['zip']['files']['docProps']['core.xml'])) {
|
||||
// http://technet.microsoft.com/en-us/library/cc179224.aspx
|
||||
$info['fileformat'] = 'zip.msoffice';
|
||||
if (!empty($info['zip']['files']['ppt'])) {
|
||||
$info['mime_type'] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
|
||||
} elseif (!empty($info['zip']['files']['xl'])) {
|
||||
$info['mime_type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
||||
} elseif (!empty($info['zip']['files']['word'])) {
|
||||
$info['mime_type'] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->getZIPentriesFilepointer()) {
|
||||
unset($info['zip']);
|
||||
$info['fileformat'] = '';
|
||||
$this->error('Cannot find End Of Central Directory (truncated file?)');
|
||||
return false;
|
||||
}
|
||||
|
||||
// central directory couldn't be found and/or parsed
|
||||
// scan through actual file data entries, recover as much as possible from probable trucated file
|
||||
if ($info['zip']['compressed_size'] > ($info['filesize'] - 46 - 22)) {
|
||||
$this->error('Warning: Truncated file! - Total compressed file sizes ('.$info['zip']['compressed_size'].' bytes) is greater than filesize minus Central Directory and End Of Central Directory structures ('.($info['filesize'] - 46 - 22).' bytes)');
|
||||
}
|
||||
$this->error('Cannot find End Of Central Directory - returned list of files in [zip][entries] array may not be complete');
|
||||
foreach ($info['zip']['entries'] as $key => $valuearray) {
|
||||
$info['zip']['files'][$valuearray['filename']] = $valuearray['uncompressed_size'];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getZIPHeaderFilepointerTopDown() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'zip';
|
||||
|
||||
$info['zip']['compressed_size'] = 0;
|
||||
$info['zip']['uncompressed_size'] = 0;
|
||||
$info['zip']['entries_count'] = 0;
|
||||
|
||||
rewind($this->getid3->fp);
|
||||
while ($fileentry = $this->ZIPparseLocalFileHeader()) {
|
||||
$info['zip']['entries'][] = $fileentry;
|
||||
$info['zip']['entries_count']++;
|
||||
}
|
||||
if ($info['zip']['entries_count'] == 0) {
|
||||
$this->error('No Local File Header entries found');
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['zip']['entries_count'] = 0;
|
||||
while ($centraldirectoryentry = $this->ZIPparseCentralDirectory()) {
|
||||
$info['zip']['central_directory'][] = $centraldirectoryentry;
|
||||
$info['zip']['entries_count']++;
|
||||
$info['zip']['compressed_size'] += $centraldirectoryentry['compressed_size'];
|
||||
$info['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size'];
|
||||
}
|
||||
if ($info['zip']['entries_count'] == 0) {
|
||||
$this->error('No Central Directory entries found (truncated file?)');
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($EOCD = $this->ZIPparseEndOfCentralDirectory()) {
|
||||
$info['zip']['end_central_directory'] = $EOCD;
|
||||
} else {
|
||||
$this->error('No End Of Central Directory entry found (truncated file?)');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($info['zip']['end_central_directory']['comment'])) {
|
||||
$info['zip']['comments']['comment'][] = $info['zip']['end_central_directory']['comment'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getZIPentriesFilepointer() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['zip']['compressed_size'] = 0;
|
||||
$info['zip']['uncompressed_size'] = 0;
|
||||
$info['zip']['entries_count'] = 0;
|
||||
|
||||
rewind($this->getid3->fp);
|
||||
while ($fileentry = $this->ZIPparseLocalFileHeader()) {
|
||||
$info['zip']['entries'][] = $fileentry;
|
||||
$info['zip']['entries_count']++;
|
||||
$info['zip']['compressed_size'] += $fileentry['compressed_size'];
|
||||
$info['zip']['uncompressed_size'] += $fileentry['uncompressed_size'];
|
||||
}
|
||||
if ($info['zip']['entries_count'] == 0) {
|
||||
$this->error('No Local File Header entries found');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|false
|
||||
*/
|
||||
public function ZIPparseLocalFileHeader() {
|
||||
$LocalFileHeader = array();
|
||||
$LocalFileHeader['offset'] = $this->ftell();
|
||||
|
||||
$ZIPlocalFileHeader = $this->fread(30);
|
||||
|
||||
$LocalFileHeader['raw']['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 0, 4));
|
||||
if ($LocalFileHeader['raw']['signature'] != 0x04034B50) { // "PK\x03\x04"
|
||||
// invalid Local File Header Signature
|
||||
$this->fseek($LocalFileHeader['offset']); // seek back to where filepointer originally was so it can be handled properly
|
||||
return false;
|
||||
}
|
||||
$LocalFileHeader['raw']['extract_version'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 4, 2));
|
||||
$LocalFileHeader['raw']['general_flags'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 6, 2));
|
||||
$LocalFileHeader['raw']['compression_method'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 8, 2));
|
||||
$LocalFileHeader['raw']['last_mod_file_time'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 10, 2));
|
||||
$LocalFileHeader['raw']['last_mod_file_date'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 12, 2));
|
||||
$LocalFileHeader['raw']['crc_32'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 14, 4));
|
||||
$LocalFileHeader['raw']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 18, 4));
|
||||
$LocalFileHeader['raw']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 22, 4));
|
||||
$LocalFileHeader['raw']['filename_length'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 26, 2));
|
||||
$LocalFileHeader['raw']['extra_field_length'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 28, 2));
|
||||
|
||||
$LocalFileHeader['extract_version'] = sprintf('%1.1f', $LocalFileHeader['raw']['extract_version'] / 10);
|
||||
$LocalFileHeader['host_os'] = $this->ZIPversionOSLookup(($LocalFileHeader['raw']['extract_version'] & 0xFF00) >> 8);
|
||||
$LocalFileHeader['compression_method'] = $this->ZIPcompressionMethodLookup($LocalFileHeader['raw']['compression_method']);
|
||||
$LocalFileHeader['compressed_size'] = $LocalFileHeader['raw']['compressed_size'];
|
||||
$LocalFileHeader['uncompressed_size'] = $LocalFileHeader['raw']['uncompressed_size'];
|
||||
$LocalFileHeader['flags'] = $this->ZIPparseGeneralPurposeFlags($LocalFileHeader['raw']['general_flags'], $LocalFileHeader['raw']['compression_method']);
|
||||
$LocalFileHeader['last_modified_timestamp'] = $this->DOStime2UNIXtime($LocalFileHeader['raw']['last_mod_file_date'], $LocalFileHeader['raw']['last_mod_file_time']);
|
||||
|
||||
$FilenameExtrafieldLength = $LocalFileHeader['raw']['filename_length'] + $LocalFileHeader['raw']['extra_field_length'];
|
||||
if ($FilenameExtrafieldLength > 0) {
|
||||
$ZIPlocalFileHeader .= $this->fread($FilenameExtrafieldLength);
|
||||
|
||||
if ($LocalFileHeader['raw']['filename_length'] > 0) {
|
||||
$LocalFileHeader['filename'] = substr($ZIPlocalFileHeader, 30, $LocalFileHeader['raw']['filename_length']);
|
||||
}
|
||||
if ($LocalFileHeader['raw']['extra_field_length'] > 0) {
|
||||
$LocalFileHeader['raw']['extra_field_data'] = substr($ZIPlocalFileHeader, 30 + $LocalFileHeader['raw']['filename_length'], $LocalFileHeader['raw']['extra_field_length']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($LocalFileHeader['compressed_size'] == 0) {
|
||||
// *Could* be a zero-byte file
|
||||
// But could also be a file written on the fly that didn't know compressed filesize beforehand.
|
||||
// Correct compressed filesize should be in the data_descriptor located after this file data, and also in Central Directory (at end of zip file)
|
||||
if (!empty($this->getid3->info['zip']['central_directory'])) {
|
||||
foreach ($this->getid3->info['zip']['central_directory'] as $central_directory_entry) {
|
||||
if ($central_directory_entry['entry_offset'] == $LocalFileHeader['offset']) {
|
||||
if ($central_directory_entry['compressed_size'] > 0) {
|
||||
// overwrite local zero value (but not ['raw']'compressed_size']) so that seeking for data_descriptor (and next file entry) works correctly
|
||||
$LocalFileHeader['compressed_size'] = $central_directory_entry['compressed_size'];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
$LocalFileHeader['data_offset'] = $this->ftell();
|
||||
$this->fseek($LocalFileHeader['compressed_size'], SEEK_CUR); // this should (but may not) match value in $LocalFileHeader['raw']['compressed_size'] -- $LocalFileHeader['compressed_size'] could have been overwritten above with value from Central Directory
|
||||
|
||||
if ($LocalFileHeader['flags']['data_descriptor_used']) {
|
||||
$DataDescriptor = $this->fread(16);
|
||||
$LocalFileHeader['data_descriptor']['signature'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 0, 4));
|
||||
if ($LocalFileHeader['data_descriptor']['signature'] != 0x08074B50) { // "PK\x07\x08"
|
||||
$this->getid3->warning('invalid Local File Header Data Descriptor Signature at offset '.($this->ftell() - 16).' - expecting 08 07 4B 50, found '.getid3_lib::PrintHexBytes(substr($DataDescriptor, 0, 4)));
|
||||
$this->fseek($LocalFileHeader['offset']); // seek back to where filepointer originally was so it can be handled properly
|
||||
return false;
|
||||
}
|
||||
$LocalFileHeader['data_descriptor']['crc_32'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 4, 4));
|
||||
$LocalFileHeader['data_descriptor']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 8, 4));
|
||||
$LocalFileHeader['data_descriptor']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 12, 4));
|
||||
if (!$LocalFileHeader['raw']['compressed_size'] && $LocalFileHeader['data_descriptor']['compressed_size']) {
|
||||
foreach ($this->getid3->info['zip']['central_directory'] as $central_directory_entry) {
|
||||
if ($central_directory_entry['entry_offset'] == $LocalFileHeader['offset']) {
|
||||
if ($LocalFileHeader['data_descriptor']['compressed_size'] == $central_directory_entry['compressed_size']) {
|
||||
// $LocalFileHeader['compressed_size'] already set from Central Directory
|
||||
} else {
|
||||
$this->warning('conflicting compressed_size from data_descriptor ('.$LocalFileHeader['data_descriptor']['compressed_size'].') vs Central Directory ('.$central_directory_entry['compressed_size'].') for file at offset '.$LocalFileHeader['offset']);
|
||||
}
|
||||
|
||||
if ($LocalFileHeader['data_descriptor']['uncompressed_size'] == $central_directory_entry['uncompressed_size']) {
|
||||
$LocalFileHeader['uncompressed_size'] = $LocalFileHeader['data_descriptor']['uncompressed_size'];
|
||||
} else {
|
||||
$this->warning('conflicting uncompressed_size from data_descriptor ('.$LocalFileHeader['data_descriptor']['uncompressed_size'].') vs Central Directory ('.$central_directory_entry['uncompressed_size'].') for file at offset '.$LocalFileHeader['offset']);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $LocalFileHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|false
|
||||
*/
|
||||
public function ZIPparseCentralDirectory() {
|
||||
$CentralDirectory = array();
|
||||
$CentralDirectory['offset'] = $this->ftell();
|
||||
|
||||
$ZIPcentralDirectory = $this->fread(46);
|
||||
|
||||
$CentralDirectory['raw']['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 0, 4));
|
||||
if ($CentralDirectory['raw']['signature'] != 0x02014B50) {
|
||||
// invalid Central Directory Signature
|
||||
$this->fseek($CentralDirectory['offset']); // seek back to where filepointer originally was so it can be handled properly
|
||||
return false;
|
||||
}
|
||||
$CentralDirectory['raw']['create_version'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 4, 2));
|
||||
$CentralDirectory['raw']['extract_version'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 6, 2));
|
||||
$CentralDirectory['raw']['general_flags'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 8, 2));
|
||||
$CentralDirectory['raw']['compression_method'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 10, 2));
|
||||
$CentralDirectory['raw']['last_mod_file_time'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 12, 2));
|
||||
$CentralDirectory['raw']['last_mod_file_date'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 14, 2));
|
||||
$CentralDirectory['raw']['crc_32'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 16, 4));
|
||||
$CentralDirectory['raw']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 20, 4));
|
||||
$CentralDirectory['raw']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 24, 4));
|
||||
$CentralDirectory['raw']['filename_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 28, 2));
|
||||
$CentralDirectory['raw']['extra_field_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 30, 2));
|
||||
$CentralDirectory['raw']['file_comment_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 32, 2));
|
||||
$CentralDirectory['raw']['disk_number_start'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 34, 2));
|
||||
$CentralDirectory['raw']['internal_file_attrib'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 36, 2));
|
||||
$CentralDirectory['raw']['external_file_attrib'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 38, 4));
|
||||
$CentralDirectory['raw']['local_header_offset'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 42, 4));
|
||||
|
||||
$CentralDirectory['entry_offset'] = $CentralDirectory['raw']['local_header_offset'];
|
||||
$CentralDirectory['create_version'] = sprintf('%1.1f', $CentralDirectory['raw']['create_version'] / 10);
|
||||
$CentralDirectory['extract_version'] = sprintf('%1.1f', $CentralDirectory['raw']['extract_version'] / 10);
|
||||
$CentralDirectory['host_os'] = $this->ZIPversionOSLookup(($CentralDirectory['raw']['extract_version'] & 0xFF00) >> 8);
|
||||
$CentralDirectory['compression_method'] = $this->ZIPcompressionMethodLookup($CentralDirectory['raw']['compression_method']);
|
||||
$CentralDirectory['compressed_size'] = $CentralDirectory['raw']['compressed_size'];
|
||||
$CentralDirectory['uncompressed_size'] = $CentralDirectory['raw']['uncompressed_size'];
|
||||
$CentralDirectory['flags'] = $this->ZIPparseGeneralPurposeFlags($CentralDirectory['raw']['general_flags'], $CentralDirectory['raw']['compression_method']);
|
||||
$CentralDirectory['last_modified_timestamp'] = $this->DOStime2UNIXtime($CentralDirectory['raw']['last_mod_file_date'], $CentralDirectory['raw']['last_mod_file_time']);
|
||||
|
||||
$FilenameExtrafieldCommentLength = $CentralDirectory['raw']['filename_length'] + $CentralDirectory['raw']['extra_field_length'] + $CentralDirectory['raw']['file_comment_length'];
|
||||
if ($FilenameExtrafieldCommentLength > 0) {
|
||||
$FilenameExtrafieldComment = $this->fread($FilenameExtrafieldCommentLength);
|
||||
|
||||
if ($CentralDirectory['raw']['filename_length'] > 0) {
|
||||
$CentralDirectory['filename'] = substr($FilenameExtrafieldComment, 0, $CentralDirectory['raw']['filename_length']);
|
||||
}
|
||||
if ($CentralDirectory['raw']['extra_field_length'] > 0) {
|
||||
$CentralDirectory['raw']['extra_field_data'] = substr($FilenameExtrafieldComment, $CentralDirectory['raw']['filename_length'], $CentralDirectory['raw']['extra_field_length']);
|
||||
}
|
||||
if ($CentralDirectory['raw']['file_comment_length'] > 0) {
|
||||
$CentralDirectory['file_comment'] = substr($FilenameExtrafieldComment, $CentralDirectory['raw']['filename_length'] + $CentralDirectory['raw']['extra_field_length'], $CentralDirectory['raw']['file_comment_length']);
|
||||
}
|
||||
}
|
||||
|
||||
return $CentralDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|false
|
||||
*/
|
||||
public function ZIPparseEndOfCentralDirectory() {
|
||||
$EndOfCentralDirectory = array();
|
||||
$EndOfCentralDirectory['offset'] = $this->ftell();
|
||||
|
||||
$ZIPendOfCentralDirectory = $this->fread(22);
|
||||
|
||||
$EndOfCentralDirectory['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 0, 4));
|
||||
if ($EndOfCentralDirectory['signature'] != 0x06054B50) {
|
||||
// invalid End Of Central Directory Signature
|
||||
$this->fseek($EndOfCentralDirectory['offset']); // seek back to where filepointer originally was so it can be handled properly
|
||||
return false;
|
||||
}
|
||||
$EndOfCentralDirectory['disk_number_current'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 4, 2));
|
||||
$EndOfCentralDirectory['disk_number_start_directory'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 6, 2));
|
||||
$EndOfCentralDirectory['directory_entries_this_disk'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 8, 2));
|
||||
$EndOfCentralDirectory['directory_entries_total'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 10, 2));
|
||||
$EndOfCentralDirectory['directory_size'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 12, 4));
|
||||
$EndOfCentralDirectory['directory_offset'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 16, 4));
|
||||
$EndOfCentralDirectory['comment_length'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 20, 2));
|
||||
|
||||
if ($EndOfCentralDirectory['comment_length'] > 0) {
|
||||
$EndOfCentralDirectory['comment'] = $this->fread($EndOfCentralDirectory['comment_length']);
|
||||
}
|
||||
|
||||
return $EndOfCentralDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $flagbytes
|
||||
* @param int $compressionmethod
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function ZIPparseGeneralPurposeFlags($flagbytes, $compressionmethod) {
|
||||
// https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip-printable.html
|
||||
$ParsedFlags = array();
|
||||
$ParsedFlags['encrypted'] = (bool) ($flagbytes & 0x0001);
|
||||
// 0x0002 -- see below
|
||||
// 0x0004 -- see below
|
||||
$ParsedFlags['data_descriptor_used'] = (bool) ($flagbytes & 0x0008);
|
||||
$ParsedFlags['enhanced_deflation'] = (bool) ($flagbytes & 0x0010);
|
||||
$ParsedFlags['compressed_patched_data'] = (bool) ($flagbytes & 0x0020);
|
||||
$ParsedFlags['strong_encryption'] = (bool) ($flagbytes & 0x0040);
|
||||
// 0x0080 - unused
|
||||
// 0x0100 - unused
|
||||
// 0x0200 - unused
|
||||
// 0x0400 - unused
|
||||
$ParsedFlags['language_encoding'] = (bool) ($flagbytes & 0x0800);
|
||||
// 0x1000 - reserved
|
||||
$ParsedFlags['mask_header_values'] = (bool) ($flagbytes & 0x2000);
|
||||
// 0x4000 - reserved
|
||||
// 0x8000 - reserved
|
||||
|
||||
switch ($compressionmethod) {
|
||||
case 6:
|
||||
$ParsedFlags['dictionary_size'] = (($flagbytes & 0x0002) ? 8192 : 4096);
|
||||
$ParsedFlags['shannon_fano_trees'] = (($flagbytes & 0x0004) ? 3 : 2);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
case 9:
|
||||
switch (($flagbytes & 0x0006) >> 1) {
|
||||
case 0:
|
||||
$ParsedFlags['compression_speed'] = 'normal';
|
||||
break;
|
||||
case 1:
|
||||
$ParsedFlags['compression_speed'] = 'maximum';
|
||||
break;
|
||||
case 2:
|
||||
$ParsedFlags['compression_speed'] = 'fast';
|
||||
break;
|
||||
case 3:
|
||||
$ParsedFlags['compression_speed'] = 'superfast';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $ParsedFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function ZIPversionOSLookup($index) {
|
||||
static $ZIPversionOSLookup = array(
|
||||
0 => 'MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)',
|
||||
1 => 'Amiga',
|
||||
2 => 'OpenVMS',
|
||||
3 => 'Unix',
|
||||
4 => 'VM/CMS',
|
||||
5 => 'Atari ST',
|
||||
6 => 'OS/2 H.P.F.S.',
|
||||
7 => 'Macintosh',
|
||||
8 => 'Z-System',
|
||||
9 => 'CP/M',
|
||||
10 => 'Windows NTFS',
|
||||
11 => 'MVS',
|
||||
12 => 'VSE',
|
||||
13 => 'Acorn Risc',
|
||||
14 => 'VFAT',
|
||||
15 => 'Alternate MVS',
|
||||
16 => 'BeOS',
|
||||
17 => 'Tandem',
|
||||
18 => 'OS/400',
|
||||
19 => 'OS/X (Darwin)',
|
||||
);
|
||||
|
||||
return (isset($ZIPversionOSLookup[$index]) ? $ZIPversionOSLookup[$index] : '[unknown]');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function ZIPcompressionMethodLookup($index) {
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/ZIP.html
|
||||
static $ZIPcompressionMethodLookup = array(
|
||||
0 => 'store',
|
||||
1 => 'shrink',
|
||||
2 => 'reduce-1',
|
||||
3 => 'reduce-2',
|
||||
4 => 'reduce-3',
|
||||
5 => 'reduce-4',
|
||||
6 => 'implode',
|
||||
7 => 'tokenize',
|
||||
8 => 'deflate',
|
||||
9 => 'deflate64',
|
||||
10 => 'Imploded (old IBM TERSE)',
|
||||
11 => 'RESERVED[11]',
|
||||
12 => 'BZIP2',
|
||||
13 => 'RESERVED[13]',
|
||||
14 => 'LZMA (EFS)',
|
||||
15 => 'RESERVED[15]',
|
||||
16 => 'RESERVED[16]',
|
||||
17 => 'RESERVED[17]',
|
||||
18 => 'IBM TERSE (new)',
|
||||
19 => 'IBM LZ77 z Architecture (PFS)',
|
||||
96 => 'JPEG recompressed',
|
||||
97 => 'WavPack compressed',
|
||||
98 => 'PPMd version I, Rev 1',
|
||||
);
|
||||
|
||||
return (isset($ZIPcompressionMethodLookup[$index]) ? $ZIPcompressionMethodLookup[$index] : '[unknown]');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $DOSdate
|
||||
* @param int $DOStime
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function DOStime2UNIXtime($DOSdate, $DOStime) {
|
||||
// wFatDate
|
||||
// Specifies the MS-DOS date. The date is a packed 16-bit value with the following format:
|
||||
// Bits Contents
|
||||
// 0-4 Day of the month (1-31)
|
||||
// 5-8 Month (1 = January, 2 = February, and so on)
|
||||
// 9-15 Year offset from 1980 (add 1980 to get actual year)
|
||||
|
||||
$UNIXday = ($DOSdate & 0x001F);
|
||||
$UNIXmonth = (($DOSdate & 0x01E0) >> 5);
|
||||
$UNIXyear = (($DOSdate & 0xFE00) >> 9) + 1980;
|
||||
|
||||
// wFatTime
|
||||
// Specifies the MS-DOS time. The time is a packed 16-bit value with the following format:
|
||||
// Bits Contents
|
||||
// 0-4 Second divided by 2
|
||||
// 5-10 Minute (0-59)
|
||||
// 11-15 Hour (0-23 on a 24-hour clock)
|
||||
|
||||
$UNIXsecond = ($DOStime & 0x001F) * 2;
|
||||
$UNIXminute = (($DOStime & 0x07E0) >> 5);
|
||||
$UNIXhour = (($DOStime & 0xF800) >> 11);
|
||||
|
||||
return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.bink.php //
|
||||
// module for analyzing Bink or Smacker audio-video files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
class getid3_bink extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->error('Bink / Smacker files not properly processed by this version of getID3() ['.$this->getid3->version().']');
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$fileTypeID = $this->fread(3);
|
||||
switch ($fileTypeID) {
|
||||
case 'BIK':
|
||||
return $this->ParseBink();
|
||||
|
||||
case 'SMK':
|
||||
return $this->ParseSmacker();
|
||||
|
||||
default:
|
||||
$this->error('Expecting "BIK" or "SMK" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($fileTypeID).'"');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function ParseBink() {
|
||||
$info = &$this->getid3->info;
|
||||
$info['fileformat'] = 'bink';
|
||||
$info['video']['dataformat'] = 'bink';
|
||||
|
||||
$fileData = 'BIK'.$this->fread(13);
|
||||
|
||||
$info['bink']['data_size'] = getid3_lib::LittleEndian2Int(substr($fileData, 4, 4));
|
||||
$info['bink']['frame_count'] = getid3_lib::LittleEndian2Int(substr($fileData, 8, 2));
|
||||
|
||||
if (($info['avdataend'] - $info['avdataoffset']) != ($info['bink']['data_size'] + 8)) {
|
||||
$this->error('Probably truncated file: expecting '.$info['bink']['data_size'].' bytes, found '.($info['avdataend'] - $info['avdataoffset']));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function ParseSmacker() {
|
||||
$info = &$this->getid3->info;
|
||||
$info['fileformat'] = 'smacker';
|
||||
$info['video']['dataformat'] = 'smacker';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,910 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio-video.flv.php //
|
||||
// module for analyzing Shockwave Flash Video files //
|
||||
// dependencies: NONE //
|
||||
// //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// FLV module by Seth Kaufman <sethØwhirl-i-gig*com> //
|
||||
// //
|
||||
// * version 0.1 (26 June 2005) //
|
||||
// //
|
||||
// * version 0.1.1 (15 July 2005) //
|
||||
// minor modifications by James Heinrich <info@getid3.org> //
|
||||
// //
|
||||
// * version 0.2 (22 February 2006) //
|
||||
// Support for On2 VP6 codec and meta information //
|
||||
// by Steve Webster <steve.websterØfeaturecreep*com> //
|
||||
// //
|
||||
// * version 0.3 (15 June 2006) //
|
||||
// Modified to not read entire file into memory //
|
||||
// by James Heinrich <info@getid3.org> //
|
||||
// //
|
||||
// * version 0.4 (07 December 2007) //
|
||||
// Bugfixes for incorrectly parsed FLV dimensions //
|
||||
// and incorrect parsing of onMetaTag //
|
||||
// by Evgeny Moysevich <moysevichØgmail*com> //
|
||||
// //
|
||||
// * version 0.5 (21 May 2009) //
|
||||
// Fixed parsing of audio tags and added additional codec //
|
||||
// details. The duration is now read from onMetaTag (if //
|
||||
// exists), rather than parsing whole file //
|
||||
// by Nigel Barnes <ngbarnesØhotmail*com> //
|
||||
// //
|
||||
// * version 0.6 (24 May 2009) //
|
||||
// Better parsing of files with h264 video //
|
||||
// by Evgeny Moysevich <moysevichØgmail*com> //
|
||||
// //
|
||||
// * 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> //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
define('GETID3_FLV_TAG_AUDIO', 8);
|
||||
define('GETID3_FLV_TAG_VIDEO', 9);
|
||||
define('GETID3_FLV_TAG_META', 18);
|
||||
|
||||
define('GETID3_FLV_VIDEO_H263', 2);
|
||||
define('GETID3_FLV_VIDEO_SCREEN', 3);
|
||||
define('GETID3_FLV_VIDEO_VP6FLV', 4);
|
||||
define('GETID3_FLV_VIDEO_VP6FLV_ALPHA', 5);
|
||||
define('GETID3_FLV_VIDEO_SCREENV2', 6);
|
||||
define('GETID3_FLV_VIDEO_H264', 7);
|
||||
|
||||
define('H264_AVC_SEQUENCE_HEADER', 0);
|
||||
define('H264_PROFILE_BASELINE', 66);
|
||||
define('H264_PROFILE_MAIN', 77);
|
||||
define('H264_PROFILE_EXTENDED', 88);
|
||||
define('H264_PROFILE_HIGH', 100);
|
||||
define('H264_PROFILE_HIGH10', 110);
|
||||
define('H264_PROFILE_HIGH422', 122);
|
||||
define('H264_PROFILE_HIGH444', 144);
|
||||
define('H264_PROFILE_HIGH444_PREDICTIVE', 244);
|
||||
|
||||
class getid3_flv extends getid3_handler
|
||||
{
|
||||
const magic = 'FLV';
|
||||
|
||||
/**
|
||||
* Break out of the loop if too many frames have been scanned; only scan this
|
||||
* many if meta frame does not contain useful duration.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $max_frames = 100000;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
||||
$FLVdataLength = $info['avdataend'] - $info['avdataoffset'];
|
||||
$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));
|
||||
|
||||
if ($info['flv']['header']['signature'] != self::magic) {
|
||||
$this->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($this->fread(4));
|
||||
$FLVheaderFrameLength = 9;
|
||||
if ($FrameSizeDataLength > $FLVheaderFrameLength) {
|
||||
$this->fseek($FrameSizeDataLength - $FLVheaderFrameLength, SEEK_CUR);
|
||||
}
|
||||
$Duration = 0;
|
||||
$found_video = false;
|
||||
$found_audio = false;
|
||||
$found_meta = false;
|
||||
$found_valid_meta_playtime = false;
|
||||
$tagParseCount = 0;
|
||||
$info['flv']['framecount'] = array('total'=>0, 'audio'=>0, 'video'=>0);
|
||||
$flv_framecount = &$info['flv']['framecount'];
|
||||
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 = $this->ftell() - 1 + $DataLength;
|
||||
if ($Timestamp > $Duration) {
|
||||
$Duration = $Timestamp;
|
||||
}
|
||||
|
||||
$flv_framecount['total']++;
|
||||
switch ($TagType) {
|
||||
case GETID3_FLV_TAG_AUDIO:
|
||||
$flv_framecount['audio']++;
|
||||
if (!$found_audio) {
|
||||
$found_audio = true;
|
||||
$info['flv']['audio']['audioFormat'] = ($LastHeaderByte >> 4) & 0x0F;
|
||||
$info['flv']['audio']['audioRate'] = ($LastHeaderByte >> 2) & 0x03;
|
||||
$info['flv']['audio']['audioSampleSize'] = ($LastHeaderByte >> 1) & 0x01;
|
||||
$info['flv']['audio']['audioType'] = $LastHeaderByte & 0x01;
|
||||
}
|
||||
break;
|
||||
|
||||
case GETID3_FLV_TAG_VIDEO:
|
||||
$flv_framecount['video']++;
|
||||
if (!$found_video) {
|
||||
$found_video = true;
|
||||
$info['flv']['video']['videoCodec'] = $LastHeaderByte & 0x07;
|
||||
|
||||
$FLVvideoHeader = $this->fread(11);
|
||||
$PictureSizeEnc = array();
|
||||
|
||||
if ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H264) {
|
||||
// this code block contributed by: moysevichØgmail*com
|
||||
|
||||
$AVCPacketType = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 0, 1));
|
||||
if ($AVCPacketType == H264_AVC_SEQUENCE_HEADER) {
|
||||
// read AVCDecoderConfigurationRecord
|
||||
$configurationVersion = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 1));
|
||||
$AVCProfileIndication = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 1));
|
||||
$profile_compatibility = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 1));
|
||||
$lengthSizeMinusOne = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 7, 1));
|
||||
$numOfSequenceParameterSets = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 8, 1));
|
||||
|
||||
if (($numOfSequenceParameterSets & 0x1F) != 0) {
|
||||
// there is at least one SequenceParameterSet
|
||||
// read size of the first SequenceParameterSet
|
||||
//$spsSize = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 9, 2));
|
||||
$spsSize = getid3_lib::LittleEndian2Int(substr($FLVvideoHeader, 9, 2));
|
||||
// read the first SequenceParameterSet
|
||||
$sps = $this->fread($spsSize);
|
||||
if (strlen($sps) == $spsSize) { // make sure that whole SequenceParameterSet was red
|
||||
$spsReader = new AVCSequenceParameterSetReader($sps);
|
||||
$spsReader->readData();
|
||||
$info['video']['resolution_x'] = $spsReader->getWidth();
|
||||
$info['video']['resolution_y'] = $spsReader->getHeight();
|
||||
}
|
||||
}
|
||||
}
|
||||
// end: moysevichØgmail*com
|
||||
|
||||
} elseif ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H263) {
|
||||
|
||||
$PictureSizeType = (getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 3, 2))) >> 7;
|
||||
$PictureSizeType = $PictureSizeType & 0x0007;
|
||||
$info['flv']['header']['videoSizeType'] = $PictureSizeType;
|
||||
switch ($PictureSizeType) {
|
||||
case 0:
|
||||
//$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2));
|
||||
//$PictureSizeEnc <<= 1;
|
||||
//$info['video']['resolution_x'] = ($PictureSizeEnc & 0xFF00) >> 8;
|
||||
//$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 2));
|
||||
//$PictureSizeEnc <<= 1;
|
||||
//$info['video']['resolution_y'] = ($PictureSizeEnc & 0xFF00) >> 8;
|
||||
|
||||
$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)) >> 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;
|
||||
|
||||
case 2:
|
||||
$info['video']['resolution_x'] = 352;
|
||||
$info['video']['resolution_y'] = 288;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$info['video']['resolution_x'] = 176;
|
||||
$info['video']['resolution_y'] = 144;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
$info['video']['resolution_x'] = 128;
|
||||
$info['video']['resolution_y'] = 96;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
$info['video']['resolution_x'] = 320;
|
||||
$info['video']['resolution_y'] = 240;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
$info['video']['resolution_x'] = 160;
|
||||
$info['video']['resolution_y'] = 120;
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['video']['resolution_x'] = 0;
|
||||
$info['video']['resolution_y'] = 0;
|
||||
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;
|
||||
$this->fseek(-1, SEEK_CUR);
|
||||
$datachunk = $this->fread($DataLength);
|
||||
$AMFstream = new AMFStream($datachunk);
|
||||
$reader = new AMFReader($AMFstream);
|
||||
$eventName = $reader->readData();
|
||||
$info['flv']['meta'][$eventName] = $reader->readData();
|
||||
unset($reader);
|
||||
|
||||
$copykeys = array('framerate'=>'frame_rate', 'width'=>'resolution_x', 'height'=>'resolution_y', 'audiodatarate'=>'bitrate', 'videodatarate'=>'bitrate');
|
||||
foreach ($copykeys as $sourcekey => $destkey) {
|
||||
if (isset($info['flv']['meta']['onMetaData'][$sourcekey])) {
|
||||
switch ($sourcekey) {
|
||||
case 'width':
|
||||
case 'height':
|
||||
$info['video'][$destkey] = intval(round($info['flv']['meta']['onMetaData'][$sourcekey]));
|
||||
break;
|
||||
case 'audiodatarate':
|
||||
$info['audio'][$destkey] = getid3_lib::CastAsInt(round($info['flv']['meta']['onMetaData'][$sourcekey] * 1000));
|
||||
break;
|
||||
case 'videodatarate':
|
||||
case 'frame_rate':
|
||||
default:
|
||||
$info['video'][$destkey] = $info['flv']['meta']['onMetaData'][$sourcekey];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($info['flv']['meta']['onMetaData']['duration'])) {
|
||||
$found_valid_meta_playtime = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// noop
|
||||
break;
|
||||
}
|
||||
$this->fseek($NextOffset);
|
||||
}
|
||||
|
||||
$info['playtime_seconds'] = $Duration / 1000;
|
||||
if ($info['playtime_seconds'] > 0) {
|
||||
$info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
}
|
||||
|
||||
if ($info['flv']['header']['hasAudio']) {
|
||||
$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'] = self::videoCodecLookup($info['flv']['video']['videoCodec']);
|
||||
$info['video']['dataformat'] = 'flv';
|
||||
$info['video']['lossless'] = false;
|
||||
}
|
||||
|
||||
// Set information from meta
|
||||
if (!empty($info['flv']['meta']['onMetaData']['duration'])) {
|
||||
$info['playtime_seconds'] = $info['flv']['meta']['onMetaData']['duration'];
|
||||
$info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
}
|
||||
if (isset($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'] = self::videoCodecLookup($info['flv']['meta']['onMetaData']['videocodecid']);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function audioFormatLookup($id) {
|
||||
static $lookup = array(
|
||||
0 => 'Linear PCM, platform endian',
|
||||
1 => 'ADPCM',
|
||||
2 => 'mp3',
|
||||
3 => 'Linear PCM, little endian',
|
||||
4 => 'Nellymoser 16kHz mono',
|
||||
5 => 'Nellymoser 8kHz mono',
|
||||
6 => 'Nellymoser',
|
||||
7 => 'G.711A-law logarithmic PCM',
|
||||
8 => 'G.711 mu-law logarithmic PCM',
|
||||
9 => 'reserved',
|
||||
10 => 'AAC',
|
||||
11 => 'Speex',
|
||||
12 => false, // unknown?
|
||||
13 => false, // unknown?
|
||||
14 => 'mp3 8kHz',
|
||||
15 => 'Device-specific sound',
|
||||
);
|
||||
return (isset($lookup[$id]) ? $lookup[$id] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public static function audioRateLookup($id) {
|
||||
static $lookup = array(
|
||||
0 => 5500,
|
||||
1 => 11025,
|
||||
2 => 22050,
|
||||
3 => 44100,
|
||||
);
|
||||
return (isset($lookup[$id]) ? $lookup[$id] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public static function audioBitDepthLookup($id) {
|
||||
static $lookup = array(
|
||||
0 => 8,
|
||||
1 => 16,
|
||||
);
|
||||
return (isset($lookup[$id]) ? $lookup[$id] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function videoCodecLookup($id) {
|
||||
static $lookup = array(
|
||||
GETID3_FLV_VIDEO_H263 => 'Sorenson H.263',
|
||||
GETID3_FLV_VIDEO_SCREEN => 'Screen video',
|
||||
GETID3_FLV_VIDEO_VP6FLV => 'On2 VP6',
|
||||
GETID3_FLV_VIDEO_VP6FLV_ALPHA => 'On2 VP6 with alpha channel',
|
||||
GETID3_FLV_VIDEO_SCREENV2 => 'Screen video v2',
|
||||
GETID3_FLV_VIDEO_H264 => 'Sorenson H.264',
|
||||
);
|
||||
return (isset($lookup[$id]) ? $lookup[$id] : false);
|
||||
}
|
||||
}
|
||||
|
||||
class AMFStream
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $bytes;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $pos;
|
||||
|
||||
/**
|
||||
* @param string $bytes
|
||||
*/
|
||||
public function __construct(&$bytes) {
|
||||
$this->bytes =& $bytes;
|
||||
$this->pos = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function readByte() { // 8-bit
|
||||
return ord(substr($this->bytes, $this->pos++, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function readInt() { // 16-bit
|
||||
return ($this->readByte() << 8) + $this->readByte();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function readLong() { // 32-bit
|
||||
return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|false
|
||||
*/
|
||||
public function readDouble() {
|
||||
return getid3_lib::BigEndian2Float($this->read(8));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function readUTF() {
|
||||
$length = $this->readInt();
|
||||
return $this->read($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function readLongUTF() {
|
||||
$length = $this->readLong();
|
||||
return $this->read($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $length
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function read($length) {
|
||||
$val = substr($this->bytes, $this->pos, $length);
|
||||
$this->pos += $length;
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function peekByte() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readByte();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function peekInt() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readInt();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function peekLong() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readLong();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|false
|
||||
*/
|
||||
public function peekDouble() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readDouble();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function peekUTF() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readUTF();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function peekLongUTF() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readLongUTF();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
|
||||
class AMFReader
|
||||
{
|
||||
/**
|
||||
* @var AMFStream
|
||||
*/
|
||||
public $stream;
|
||||
|
||||
/**
|
||||
* @param AMFStream $stream
|
||||
*/
|
||||
public function __construct(AMFStream $stream) {
|
||||
$this->stream = $stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function readData() {
|
||||
$value = null;
|
||||
|
||||
$type = $this->stream->readByte();
|
||||
switch ($type) {
|
||||
|
||||
// Double
|
||||
case 0:
|
||||
$value = $this->readDouble();
|
||||
break;
|
||||
|
||||
// Boolean
|
||||
case 1:
|
||||
$value = $this->readBoolean();
|
||||
break;
|
||||
|
||||
// String
|
||||
case 2:
|
||||
$value = $this->readString();
|
||||
break;
|
||||
|
||||
// Object
|
||||
case 3:
|
||||
$value = $this->readObject();
|
||||
break;
|
||||
|
||||
// null
|
||||
case 6:
|
||||
return null;
|
||||
|
||||
// Mixed array
|
||||
case 8:
|
||||
$value = $this->readMixedArray();
|
||||
break;
|
||||
|
||||
// Array
|
||||
case 10:
|
||||
$value = $this->readArray();
|
||||
break;
|
||||
|
||||
// Date
|
||||
case 11:
|
||||
$value = $this->readDate();
|
||||
break;
|
||||
|
||||
// Long string
|
||||
case 13:
|
||||
$value = $this->readLongString();
|
||||
break;
|
||||
|
||||
// XML (handled as string)
|
||||
case 15:
|
||||
$value = $this->readXML();
|
||||
break;
|
||||
|
||||
// Typed object (handled as object)
|
||||
case 16:
|
||||
$value = $this->readTypedObject();
|
||||
break;
|
||||
|
||||
// Long string
|
||||
default:
|
||||
$value = '(unknown or unsupported data type)';
|
||||
break;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|false
|
||||
*/
|
||||
public function readDouble() {
|
||||
return $this->stream->readDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function readBoolean() {
|
||||
return $this->stream->readByte() == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function readString() {
|
||||
return $this->stream->readUTF();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function readObject() {
|
||||
// Get highest numerical index - ignored
|
||||
// $highestIndex = $this->stream->readLong();
|
||||
|
||||
$data = array();
|
||||
$key = null;
|
||||
|
||||
while ($key = $this->stream->readUTF()) {
|
||||
$data[$key] = $this->readData();
|
||||
}
|
||||
// Mixed array record ends with empty string (0x00 0x00) and 0x09
|
||||
if (($key == '') && ($this->stream->peekByte() == 0x09)) {
|
||||
// Consume byte
|
||||
$this->stream->readByte();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function readMixedArray() {
|
||||
// Get highest numerical index - ignored
|
||||
$highestIndex = $this->stream->readLong();
|
||||
|
||||
$data = array();
|
||||
$key = null;
|
||||
|
||||
while ($key = $this->stream->readUTF()) {
|
||||
if (is_numeric($key)) {
|
||||
$key = (int) $key;
|
||||
}
|
||||
$data[$key] = $this->readData();
|
||||
}
|
||||
// Mixed array record ends with empty string (0x00 0x00) and 0x09
|
||||
if (($key == '') && ($this->stream->peekByte() == 0x09)) {
|
||||
// Consume byte
|
||||
$this->stream->readByte();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function readArray() {
|
||||
$length = $this->stream->readLong();
|
||||
$data = array();
|
||||
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$data[] = $this->readData();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|false
|
||||
*/
|
||||
public function readDate() {
|
||||
$timestamp = $this->stream->readDouble();
|
||||
$timezone = $this->stream->readInt();
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function readLongString() {
|
||||
return $this->stream->readLongUTF();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function readXML() {
|
||||
return $this->stream->readLongUTF();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function readTypedObject() {
|
||||
$className = $this->stream->readUTF();
|
||||
return $this->readObject();
|
||||
}
|
||||
}
|
||||
|
||||
class AVCSequenceParameterSetReader
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sps;
|
||||
public $start = 0;
|
||||
public $currentBytes = 0;
|
||||
public $currentBits = 0;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $width;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $height;
|
||||
|
||||
/**
|
||||
* @param string $sps
|
||||
*/
|
||||
public function __construct($sps) {
|
||||
$this->sps = $sps;
|
||||
}
|
||||
|
||||
public function readData() {
|
||||
$this->skipBits(8);
|
||||
$this->skipBits(8);
|
||||
$profile = $this->getBits(8); // read profile
|
||||
if ($profile > 0) {
|
||||
$this->skipBits(8);
|
||||
$level_idc = $this->getBits(8); // level_idc
|
||||
$this->expGolombUe(); // seq_parameter_set_id // sps
|
||||
$this->expGolombUe(); // log2_max_frame_num_minus4
|
||||
$picOrderType = $this->expGolombUe(); // pic_order_cnt_type
|
||||
if ($picOrderType == 0) {
|
||||
$this->expGolombUe(); // log2_max_pic_order_cnt_lsb_minus4
|
||||
} elseif ($picOrderType == 1) {
|
||||
$this->skipBits(1); // delta_pic_order_always_zero_flag
|
||||
$this->expGolombSe(); // offset_for_non_ref_pic
|
||||
$this->expGolombSe(); // offset_for_top_to_bottom_field
|
||||
$num_ref_frames_in_pic_order_cnt_cycle = $this->expGolombUe(); // num_ref_frames_in_pic_order_cnt_cycle
|
||||
for ($i = 0; $i < $num_ref_frames_in_pic_order_cnt_cycle; $i++) {
|
||||
$this->expGolombSe(); // offset_for_ref_frame[ i ]
|
||||
}
|
||||
}
|
||||
$this->expGolombUe(); // 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $bits
|
||||
*/
|
||||
public function skipBits($bits) {
|
||||
$newBits = $this->currentBits + $bits;
|
||||
$this->currentBytes += (int)floor($newBits / 8);
|
||||
$this->currentBits = $newBits % 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getBit() {
|
||||
$result = (getid3_lib::BigEndian2Int(substr($this->sps, $this->currentBytes, 1)) >> (7 - $this->currentBits)) & 0x01;
|
||||
$this->skipBits(1);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $bits
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getBits($bits) {
|
||||
$result = 0;
|
||||
for ($i = 0; $i < $bits; $i++) {
|
||||
$result = ($result << 1) + $this->getBit();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function expGolombUe() {
|
||||
$significantBits = 0;
|
||||
$bit = $this->getBit();
|
||||
while ($bit == 0) {
|
||||
$significantBits++;
|
||||
$bit = $this->getBit();
|
||||
|
||||
if ($significantBits > 31) {
|
||||
// something is broken, this is an emergency escape to prevent infinite loops
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return (1 << $significantBits) + $this->getBits($significantBits) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function expGolombSe() {
|
||||
$result = $this->expGolombUe();
|
||||
if (($result & 0x01) == 0) {
|
||||
return -($result >> 1);
|
||||
} else {
|
||||
return ($result + 1) >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getWidth() {
|
||||
return $this->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getHeight() {
|
||||
return $this->height;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.ivf.php //
|
||||
// module for analyzing IVF audio-video files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
class getid3_ivf extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'ivf';
|
||||
$info['video']['dataformat'] = 'ivf';
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$IVFheader = $this->fread(32);
|
||||
|
||||
if (substr($IVFheader, 0, 4) == 'DKIF') {
|
||||
|
||||
// https://wiki.multimedia.cx/index.php/IVF
|
||||
$info['ivf']['header']['signature'] = substr($IVFheader, 0, 4);
|
||||
$info['ivf']['header']['version'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 4, 2)); // should be 0
|
||||
$info['ivf']['header']['headersize'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 6, 2));
|
||||
$info['ivf']['header']['fourcc'] = substr($IVFheader, 8, 4);
|
||||
$info['ivf']['header']['resolution_x'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 12, 2));
|
||||
$info['ivf']['header']['resolution_y'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 14, 2));
|
||||
$info['ivf']['header']['timebase_numerator'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 16, 4));
|
||||
$info['ivf']['header']['timebase_denominator'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 20, 4));
|
||||
$info['ivf']['header']['frame_count'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 24, 4));
|
||||
//$info['ivf']['header']['reserved'] = substr($IVFheader, 28, 4);
|
||||
|
||||
$info['ivf']['header']['frame_rate'] = (float) $info['ivf']['header']['timebase_numerator'] / $info['ivf']['header']['timebase_denominator'];
|
||||
|
||||
if ($info['ivf']['header']['version'] > 0) {
|
||||
$this->warning('Expecting IVF header version 0, found version '.$info['ivf']['header']['version'].', results may not be accurate');
|
||||
}
|
||||
|
||||
$info['video']['resolution_x'] = $info['ivf']['header']['resolution_x'];
|
||||
$info['video']['resolution_y'] = $info['ivf']['header']['resolution_y'];
|
||||
$info['video']['codec'] = $info['ivf']['header']['fourcc'];
|
||||
|
||||
$info['ivf']['frame_count'] = 0;
|
||||
$timestamp = 0;
|
||||
while (!$this->feof()) {
|
||||
if ($frameheader = $this->fread(12)) {
|
||||
$framesize = getid3_lib::LittleEndian2Int(substr($frameheader, 0, 4)); // size of frame in bytes (not including the 12-byte header)
|
||||
$timestamp = getid3_lib::LittleEndian2Int(substr($frameheader, 4, 8)); // 64-bit presentation timestamp
|
||||
$this->fseek($framesize, SEEK_CUR);
|
||||
$info['ivf']['frame_count']++;
|
||||
}
|
||||
}
|
||||
if ($info['ivf']['frame_count']) {
|
||||
$info['playtime_seconds'] = $timestamp / 100000;
|
||||
$info['video']['frame_rate'] = (float) $info['ivf']['frame_count'] / $info['playtime_seconds'];
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->error('Expecting "DKIF" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($IVFheader, 0, 4)).'"');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,683 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio-video.mpeg.php //
|
||||
// module for analyzing MPEG files //
|
||||
// dependencies: module.audio.mp3.php //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
|
||||
|
||||
class getid3_mpeg extends getid3_handler
|
||||
{
|
||||
|
||||
const START_CODE_BASE = "\x00\x00\x01";
|
||||
const VIDEO_PICTURE_START = "\x00\x00\x01\x00";
|
||||
const VIDEO_USER_DATA_START = "\x00\x00\x01\xB2";
|
||||
const VIDEO_SEQUENCE_HEADER = "\x00\x00\x01\xB3";
|
||||
const VIDEO_SEQUENCE_ERROR = "\x00\x00\x01\xB4";
|
||||
const VIDEO_EXTENSION_START = "\x00\x00\x01\xB5";
|
||||
const VIDEO_SEQUENCE_END = "\x00\x00\x01\xB7";
|
||||
const VIDEO_GROUP_START = "\x00\x00\x01\xB8";
|
||||
const AUDIO_START = "\x00\x00\x01\xC0";
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'mpeg';
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
||||
$MPEGstreamData = $this->fread($this->getid3->option_fread_buffer_size);
|
||||
$MPEGstreamBaseOffset = 0; // how far are we from the beginning of the file data ($info['avdataoffset'])
|
||||
$MPEGstreamDataOffset = 0; // how far are we from the beginning of the buffer data (~32kB)
|
||||
|
||||
$StartCodeValue = false;
|
||||
$prevStartCodeValue = false;
|
||||
|
||||
$GOPcounter = -1;
|
||||
$FramesByGOP = array();
|
||||
$ParsedAVchannels = array();
|
||||
|
||||
do {
|
||||
//echo $MPEGstreamDataOffset.' vs '.(strlen($MPEGstreamData) - 1024).'<Br>';
|
||||
if ($MPEGstreamDataOffset > (strlen($MPEGstreamData) - 16384)) {
|
||||
// buffer running low, get more data
|
||||
//echo 'reading more data<br>';
|
||||
$MPEGstreamData .= $this->fread($this->getid3->option_fread_buffer_size);
|
||||
if (strlen($MPEGstreamData) > $this->getid3->option_fread_buffer_size) {
|
||||
$MPEGstreamData = substr($MPEGstreamData, $MPEGstreamDataOffset);
|
||||
$MPEGstreamBaseOffset += $MPEGstreamDataOffset;
|
||||
$MPEGstreamDataOffset = 0;
|
||||
}
|
||||
}
|
||||
if (($StartCodeOffset = strpos($MPEGstreamData, self::START_CODE_BASE, $MPEGstreamDataOffset)) === false) {
|
||||
//echo 'no more start codes found.<br>';
|
||||
break;
|
||||
} else {
|
||||
$MPEGstreamDataOffset = $StartCodeOffset;
|
||||
$prevStartCodeValue = $StartCodeValue;
|
||||
$StartCodeValue = ord(substr($MPEGstreamData, $StartCodeOffset + 3, 1));
|
||||
//echo 'Found "'.strtoupper(dechex($StartCodeValue)).'" at offset '.($MPEGstreamBaseOffset + $StartCodeOffset).' ($MPEGstreamDataOffset = '.$MPEGstreamDataOffset.')<br>';
|
||||
}
|
||||
$MPEGstreamDataOffset += 4;
|
||||
switch ($StartCodeValue) {
|
||||
|
||||
case 0x00: // picture_start_code
|
||||
if (!empty($info['mpeg']['video']['bitrate_mode']) && ($info['mpeg']['video']['bitrate_mode'] == 'vbr')) {
|
||||
$bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 4, 4));
|
||||
$bitstreamoffset = 0;
|
||||
|
||||
$PictureHeader = array();
|
||||
|
||||
$PictureHeader['temporal_reference'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 10); // 10-bit unsigned integer associated with each input picture. It is incremented by one, modulo 1024, for each input frame. When a frame is coded as two fields the temporal reference in the picture header of both fields is the same. Following a group start header the temporal reference of the earliest picture (in display order) shall be reset to zero.
|
||||
$PictureHeader['picture_coding_type'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 3); // 3 bits for picture_coding_type
|
||||
$PictureHeader['vbv_delay'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 16); // 16 bits for vbv_delay
|
||||
//... etc
|
||||
|
||||
$FramesByGOP[$GOPcounter][] = $PictureHeader;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB3: // sequence_header_code
|
||||
// Note: purposely doing the less-pretty (and probably a bit slower) method of using string of bits rather than bitwise operations.
|
||||
// Mostly because PHP 32-bit doesn't handle unsigned integers well for bitwise operation.
|
||||
// Also the MPEG stream is designed as a bitstream and often doesn't align nicely with byte boundaries.
|
||||
$info['video']['codec'] = 'MPEG-1'; // will be updated if extension_start_code found
|
||||
|
||||
$bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 4, 8));
|
||||
$bitstreamoffset = 0;
|
||||
|
||||
$info['mpeg']['video']['raw']['horizontal_size_value'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 12); // 12 bits for horizontal frame size. Note: horizontal_size_extension, if present, will add 2 most-significant bits to this value
|
||||
$info['mpeg']['video']['raw']['vertical_size_value'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 12); // 12 bits for vertical frame size. Note: vertical_size_extension, if present, will add 2 most-significant bits to this value
|
||||
$info['mpeg']['video']['raw']['aspect_ratio_information'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 4); // 4 bits for aspect_ratio_information
|
||||
$info['mpeg']['video']['raw']['frame_rate_code'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 4); // 4 bits for Frame Rate id code
|
||||
$info['mpeg']['video']['raw']['bitrate'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 18); // 18 bits for bit_rate_value (18 set bits = VBR, otherwise bitrate = this value * 400)
|
||||
$marker_bit = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // The term "marker_bit" indicates a one bit field in which the value zero is forbidden. These marker bits are introduced at several points in the syntax to avoid start code emulation.
|
||||
$info['mpeg']['video']['raw']['vbv_buffer_size'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 10); // 10 bits vbv_buffer_size_value
|
||||
$info['mpeg']['video']['raw']['constrained_param_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: constrained_param_flag
|
||||
$info['mpeg']['video']['raw']['load_intra_quantiser_matrix'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: load_intra_quantiser_matrix
|
||||
|
||||
if ($info['mpeg']['video']['raw']['load_intra_quantiser_matrix']) {
|
||||
$bitstream .= getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 12, 64));
|
||||
for ($i = 0; $i < 64; $i++) {
|
||||
$info['mpeg']['video']['raw']['intra_quantiser_matrix'][$i] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8);
|
||||
}
|
||||
}
|
||||
$info['mpeg']['video']['raw']['load_non_intra_quantiser_matrix'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1);
|
||||
|
||||
if ($info['mpeg']['video']['raw']['load_non_intra_quantiser_matrix']) {
|
||||
$bitstream .= getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 12 + ($info['mpeg']['video']['raw']['load_intra_quantiser_matrix'] ? 64 : 0), 64));
|
||||
for ($i = 0; $i < 64; $i++) {
|
||||
$info['mpeg']['video']['raw']['non_intra_quantiser_matrix'][$i] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8);
|
||||
}
|
||||
}
|
||||
|
||||
$info['mpeg']['video']['pixel_aspect_ratio'] = self::videoAspectRatioLookup($info['mpeg']['video']['raw']['aspect_ratio_information']); // may be overridden later if file turns out to be MPEG-2
|
||||
$info['mpeg']['video']['pixel_aspect_ratio_text'] = self::videoAspectRatioTextLookup($info['mpeg']['video']['raw']['aspect_ratio_information']); // may be overridden later if file turns out to be MPEG-2
|
||||
$info['mpeg']['video']['frame_rate'] = self::videoFramerateLookup($info['mpeg']['video']['raw']['frame_rate_code']);
|
||||
if ($info['mpeg']['video']['raw']['bitrate'] == 0x3FFFF) { // 18 set bits = VBR
|
||||
//$this->warning('This version of getID3() ['.$this->getid3->version().'] cannot determine average bitrate of VBR MPEG video files');
|
||||
$info['mpeg']['video']['bitrate_mode'] = 'vbr';
|
||||
} else {
|
||||
$info['mpeg']['video']['bitrate'] = $info['mpeg']['video']['raw']['bitrate'] * 400;
|
||||
$info['mpeg']['video']['bitrate_mode'] = 'cbr';
|
||||
$info['video']['bitrate'] = $info['mpeg']['video']['bitrate'];
|
||||
}
|
||||
$info['video']['resolution_x'] = $info['mpeg']['video']['raw']['horizontal_size_value'];
|
||||
$info['video']['resolution_y'] = $info['mpeg']['video']['raw']['vertical_size_value'];
|
||||
$info['video']['frame_rate'] = $info['mpeg']['video']['frame_rate'];
|
||||
$info['video']['bitrate_mode'] = $info['mpeg']['video']['bitrate_mode'];
|
||||
$info['video']['pixel_aspect_ratio'] = $info['mpeg']['video']['pixel_aspect_ratio'];
|
||||
$info['video']['lossless'] = false;
|
||||
$info['video']['bits_per_sample'] = 24;
|
||||
break;
|
||||
|
||||
case 0xB5: // extension_start_code
|
||||
$info['video']['codec'] = 'MPEG-2';
|
||||
|
||||
$bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 4, 8)); // 48 bits for Sequence Extension ID; 61 bits for Sequence Display Extension ID; 59 bits for Sequence Scalable Extension ID
|
||||
$bitstreamoffset = 0;
|
||||
|
||||
$info['mpeg']['video']['raw']['extension_start_code_identifier'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 4); // 4 bits for extension_start_code_identifier
|
||||
//echo $info['mpeg']['video']['raw']['extension_start_code_identifier'].'<br>';
|
||||
switch ($info['mpeg']['video']['raw']['extension_start_code_identifier']) {
|
||||
case 1: // 0001 Sequence Extension ID
|
||||
$info['mpeg']['video']['raw']['profile_and_level_indication'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8); // 8 bits for profile_and_level_indication
|
||||
$info['mpeg']['video']['raw']['progressive_sequence'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: progressive_sequence
|
||||
$info['mpeg']['video']['raw']['chroma_format'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for chroma_format
|
||||
$info['mpeg']['video']['raw']['horizontal_size_extension'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for horizontal_size_extension
|
||||
$info['mpeg']['video']['raw']['vertical_size_extension'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for vertical_size_extension
|
||||
$info['mpeg']['video']['raw']['bit_rate_extension'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 12); // 12 bits for bit_rate_extension
|
||||
$marker_bit = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // The term "marker_bit" indicates a one bit field in which the value zero is forbidden. These marker bits are introduced at several points in the syntax to avoid start code emulation.
|
||||
$info['mpeg']['video']['raw']['vbv_buffer_size_extension'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8); // 8 bits for vbv_buffer_size_extension
|
||||
$info['mpeg']['video']['raw']['low_delay'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: low_delay
|
||||
$info['mpeg']['video']['raw']['frame_rate_extension_n'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for frame_rate_extension_n
|
||||
$info['mpeg']['video']['raw']['frame_rate_extension_d'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 5); // 5 bits for frame_rate_extension_d
|
||||
|
||||
$info['video']['resolution_x'] = ($info['mpeg']['video']['raw']['horizontal_size_extension'] << 12) | $info['mpeg']['video']['raw']['horizontal_size_value'];
|
||||
$info['video']['resolution_y'] = ($info['mpeg']['video']['raw']['vertical_size_extension'] << 12) | $info['mpeg']['video']['raw']['vertical_size_value'];
|
||||
$info['video']['interlaced'] = !$info['mpeg']['video']['raw']['progressive_sequence'];
|
||||
$info['mpeg']['video']['interlaced'] = !$info['mpeg']['video']['raw']['progressive_sequence'];
|
||||
$info['mpeg']['video']['chroma_format'] = self::chromaFormatTextLookup($info['mpeg']['video']['raw']['chroma_format']);
|
||||
|
||||
if (isset($info['mpeg']['video']['raw']['aspect_ratio_information'])) {
|
||||
// MPEG-2 defines the aspect ratio flag differently from MPEG-1, but the MPEG-2 extension start code may occur after we've already looked up the aspect ratio assuming it was MPEG-1, so re-lookup assuming MPEG-2
|
||||
// This must be done after the extended size is known, so the display aspect ratios can be converted to pixel aspect ratios.
|
||||
$info['mpeg']['video']['pixel_aspect_ratio'] = self::videoAspectRatioLookup($info['mpeg']['video']['raw']['aspect_ratio_information'], 2, $info['video']['resolution_x'], $info['video']['resolution_y']);
|
||||
$info['mpeg']['video']['pixel_aspect_ratio_text'] = self::videoAspectRatioTextLookup($info['mpeg']['video']['raw']['aspect_ratio_information'], 2);
|
||||
$info['video']['pixel_aspect_ratio'] = $info['mpeg']['video']['pixel_aspect_ratio'];
|
||||
$info['video']['pixel_aspect_ratio_text'] = $info['mpeg']['video']['pixel_aspect_ratio_text'];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 2: // 0010 Sequence Display Extension ID
|
||||
$info['mpeg']['video']['raw']['video_format'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 3); // 3 bits for video_format
|
||||
$info['mpeg']['video']['raw']['colour_description'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: colour_description
|
||||
if ($info['mpeg']['video']['raw']['colour_description']) {
|
||||
$info['mpeg']['video']['raw']['colour_primaries'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8); // 8 bits for colour_primaries
|
||||
$info['mpeg']['video']['raw']['transfer_characteristics'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8); // 8 bits for transfer_characteristics
|
||||
$info['mpeg']['video']['raw']['matrix_coefficients'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8); // 8 bits for matrix_coefficients
|
||||
}
|
||||
$info['mpeg']['video']['raw']['display_horizontal_size'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 14); // 14 bits for display_horizontal_size
|
||||
$marker_bit = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // The term "marker_bit" indicates a one bit field in which the value zero is forbidden. These marker bits are introduced at several points in the syntax to avoid start code emulation.
|
||||
$info['mpeg']['video']['raw']['display_vertical_size'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 14); // 14 bits for display_vertical_size
|
||||
|
||||
$info['mpeg']['video']['video_format'] = self::videoFormatTextLookup($info['mpeg']['video']['raw']['video_format']);
|
||||
break;
|
||||
|
||||
case 3: // 0011 Quant Matrix Extension ID
|
||||
break;
|
||||
|
||||
case 5: // 0101 Sequence Scalable Extension ID
|
||||
$info['mpeg']['video']['raw']['scalable_mode'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for scalable_mode
|
||||
$info['mpeg']['video']['raw']['layer_id'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 4); // 4 bits for layer_id
|
||||
if ($info['mpeg']['video']['raw']['scalable_mode'] == 1) { // "spatial scalability"
|
||||
$info['mpeg']['video']['raw']['lower_layer_prediction_horizontal_size'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 14); // 14 bits for lower_layer_prediction_horizontal_size
|
||||
$marker_bit = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // The term "marker_bit" indicates a one bit field in which the value zero is forbidden. These marker bits are introduced at several points in the syntax to avoid start code emulation.
|
||||
$info['mpeg']['video']['raw']['lower_layer_prediction_vertical_size'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 14); // 14 bits for lower_layer_prediction_vertical_size
|
||||
$info['mpeg']['video']['raw']['horizontal_subsampling_factor_m'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 5); // 5 bits for horizontal_subsampling_factor_m
|
||||
$info['mpeg']['video']['raw']['horizontal_subsampling_factor_n'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 5); // 5 bits for horizontal_subsampling_factor_n
|
||||
$info['mpeg']['video']['raw']['vertical_subsampling_factor_m'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 5); // 5 bits for vertical_subsampling_factor_m
|
||||
$info['mpeg']['video']['raw']['vertical_subsampling_factor_n'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 5); // 5 bits for vertical_subsampling_factor_n
|
||||
} elseif ($info['mpeg']['video']['raw']['scalable_mode'] == 3) { // "temporal scalability"
|
||||
$info['mpeg']['video']['raw']['picture_mux_enable'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: picture_mux_enable
|
||||
if ($info['mpeg']['video']['raw']['picture_mux_enable']) {
|
||||
$info['mpeg']['video']['raw']['mux_to_progressive_sequence'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: mux_to_progressive_sequence
|
||||
}
|
||||
$info['mpeg']['video']['raw']['picture_mux_order'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 3); // 3 bits for picture_mux_order
|
||||
$info['mpeg']['video']['raw']['picture_mux_factor'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 3); // 3 bits for picture_mux_factor
|
||||
}
|
||||
|
||||
$info['mpeg']['video']['scalable_mode'] = self::scalableModeTextLookup($info['mpeg']['video']['raw']['scalable_mode']);
|
||||
break;
|
||||
|
||||
case 7: // 0111 Picture Display Extension ID
|
||||
break;
|
||||
|
||||
case 8: // 1000 Picture Coding Extension ID
|
||||
$info['mpeg']['video']['raw']['f_code_00'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 4); // 4 bits for f_code[0][0] (forward horizontal)
|
||||
$info['mpeg']['video']['raw']['f_code_01'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 4); // 4 bits for f_code[0][1] (forward vertical)
|
||||
$info['mpeg']['video']['raw']['f_code_10'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 4); // 4 bits for f_code[1][0] (backward horizontal)
|
||||
$info['mpeg']['video']['raw']['f_code_11'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 4); // 4 bits for f_code[1][1] (backward vertical)
|
||||
$info['mpeg']['video']['raw']['intra_dc_precision'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for intra_dc_precision
|
||||
$info['mpeg']['video']['raw']['picture_structure'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for picture_structure
|
||||
$info['mpeg']['video']['raw']['top_field_first'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: top_field_first
|
||||
$info['mpeg']['video']['raw']['frame_pred_frame_dct'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: frame_pred_frame_dct
|
||||
$info['mpeg']['video']['raw']['concealment_motion_vectors'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: concealment_motion_vectors
|
||||
$info['mpeg']['video']['raw']['q_scale_type'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: q_scale_type
|
||||
$info['mpeg']['video']['raw']['intra_vlc_format'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: intra_vlc_format
|
||||
$info['mpeg']['video']['raw']['alternate_scan'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: alternate_scan
|
||||
$info['mpeg']['video']['raw']['repeat_first_field'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: repeat_first_field
|
||||
$info['mpeg']['video']['raw']['chroma_420_type'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: chroma_420_type
|
||||
$info['mpeg']['video']['raw']['progressive_frame'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: progressive_frame
|
||||
$info['mpeg']['video']['raw']['composite_display_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: composite_display_flag
|
||||
if ($info['mpeg']['video']['raw']['composite_display_flag']) {
|
||||
$info['mpeg']['video']['raw']['v_axis'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: v_axis
|
||||
$info['mpeg']['video']['raw']['field_sequence'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 3); // 3 bits for field_sequence
|
||||
$info['mpeg']['video']['raw']['sub_carrier'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: sub_carrier
|
||||
$info['mpeg']['video']['raw']['burst_amplitude'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 7); // 7 bits for burst_amplitude
|
||||
$info['mpeg']['video']['raw']['sub_carrier_phase'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8); // 8 bits for sub_carrier_phase
|
||||
}
|
||||
|
||||
$info['mpeg']['video']['intra_dc_precision_bits'] = $info['mpeg']['video']['raw']['intra_dc_precision'] + 8;
|
||||
$info['mpeg']['video']['picture_structure'] = self::pictureStructureTextLookup($info['mpeg']['video']['raw']['picture_structure']);
|
||||
break;
|
||||
|
||||
case 9: // 1001 Picture Spatial Scalable Extension ID
|
||||
break;
|
||||
case 10: // 1010 Picture Temporal Scalable Extension ID
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->warning('Unexpected $info[mpeg][video][raw][extension_start_code_identifier] value of '.$info['mpeg']['video']['raw']['extension_start_code_identifier']);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0xB8: // group_of_pictures_header
|
||||
$GOPcounter++;
|
||||
if (!empty($info['mpeg']['video']['bitrate_mode']) && ($info['mpeg']['video']['bitrate_mode'] == 'vbr')) {
|
||||
$bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 4, 4)); // 27 bits needed for group_of_pictures_header
|
||||
$bitstreamoffset = 0;
|
||||
|
||||
$GOPheader = array();
|
||||
|
||||
$GOPheader['byte_offset'] = $MPEGstreamBaseOffset + $StartCodeOffset;
|
||||
$GOPheader['drop_frame_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: drop_frame_flag
|
||||
$GOPheader['time_code_hours'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 5); // 5 bits for time_code_hours
|
||||
$GOPheader['time_code_minutes'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 6); // 6 bits for time_code_minutes
|
||||
$marker_bit = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // The term "marker_bit" indicates a one bit field in which the value zero is forbidden. These marker bits are introduced at several points in the syntax to avoid start code emulation.
|
||||
$GOPheader['time_code_seconds'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 6); // 6 bits for time_code_seconds
|
||||
$GOPheader['time_code_pictures'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 6); // 6 bits for time_code_pictures
|
||||
$GOPheader['closed_gop'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: closed_gop
|
||||
$GOPheader['broken_link'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: broken_link
|
||||
|
||||
$time_code_separator = ($GOPheader['drop_frame_flag'] ? ';' : ':'); // While non-drop time code is displayed with colons separating the digit pairs "HH:MM:SS:FF" drop frame is usually represented with a semi-colon (;) or period (.) as the divider between all the digit pairs "HH;MM;SS;FF", "HH.MM.SS.FF"
|
||||
$GOPheader['time_code'] = sprintf('%02d'.$time_code_separator.'%02d'.$time_code_separator.'%02d'.$time_code_separator.'%02d', $GOPheader['time_code_hours'], $GOPheader['time_code_minutes'], $GOPheader['time_code_seconds'], $GOPheader['time_code_pictures']);
|
||||
|
||||
$info['mpeg']['group_of_pictures'][] = $GOPheader;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC0: // audio stream
|
||||
case 0xC1: // audio stream
|
||||
case 0xC2: // audio stream
|
||||
case 0xC3: // audio stream
|
||||
case 0xC4: // audio stream
|
||||
case 0xC5: // audio stream
|
||||
case 0xC6: // audio stream
|
||||
case 0xC7: // audio stream
|
||||
case 0xC8: // audio stream
|
||||
case 0xC9: // audio stream
|
||||
case 0xCA: // audio stream
|
||||
case 0xCB: // audio stream
|
||||
case 0xCC: // audio stream
|
||||
case 0xCD: // audio stream
|
||||
case 0xCE: // audio stream
|
||||
case 0xCF: // audio stream
|
||||
case 0xD0: // audio stream
|
||||
case 0xD1: // audio stream
|
||||
case 0xD2: // audio stream
|
||||
case 0xD3: // audio stream
|
||||
case 0xD4: // audio stream
|
||||
case 0xD5: // audio stream
|
||||
case 0xD6: // audio stream
|
||||
case 0xD7: // audio stream
|
||||
case 0xD8: // audio stream
|
||||
case 0xD9: // audio stream
|
||||
case 0xDA: // audio stream
|
||||
case 0xDB: // audio stream
|
||||
case 0xDC: // audio stream
|
||||
case 0xDD: // audio stream
|
||||
case 0xDE: // audio stream
|
||||
case 0xDF: // audio stream
|
||||
//case 0xE0: // video stream
|
||||
//case 0xE1: // video stream
|
||||
//case 0xE2: // video stream
|
||||
//case 0xE3: // video stream
|
||||
//case 0xE4: // video stream
|
||||
//case 0xE5: // video stream
|
||||
//case 0xE6: // video stream
|
||||
//case 0xE7: // video stream
|
||||
//case 0xE8: // video stream
|
||||
//case 0xE9: // video stream
|
||||
//case 0xEA: // video stream
|
||||
//case 0xEB: // video stream
|
||||
//case 0xEC: // video stream
|
||||
//case 0xED: // video stream
|
||||
//case 0xEE: // video stream
|
||||
//case 0xEF: // video stream
|
||||
if (isset($ParsedAVchannels[$StartCodeValue])) {
|
||||
break;
|
||||
}
|
||||
$ParsedAVchannels[$StartCodeValue] = $StartCodeValue;
|
||||
// http://en.wikipedia.org/wiki/Packetized_elementary_stream
|
||||
// http://dvd.sourceforge.net/dvdinfo/pes-hdr.html
|
||||
/*
|
||||
$PackedElementaryStream = array();
|
||||
if ($StartCodeValue >= 0xE0) {
|
||||
$PackedElementaryStream['stream_type'] = 'video';
|
||||
$PackedElementaryStream['stream_id'] = $StartCodeValue - 0xE0;
|
||||
} else {
|
||||
$PackedElementaryStream['stream_type'] = 'audio';
|
||||
$PackedElementaryStream['stream_id'] = $StartCodeValue - 0xC0;
|
||||
}
|
||||
$PackedElementaryStream['packet_length'] = getid3_lib::BigEndian2Int(substr($MPEGstreamData, $StartCodeOffset + 4, 2));
|
||||
|
||||
$bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 6, 3)); // more may be needed below
|
||||
$bitstreamoffset = 0;
|
||||
|
||||
$PackedElementaryStream['marker_bits'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for marker_bits -- should be "10" = 2
|
||||
echo 'marker_bits = '.$PackedElementaryStream['marker_bits'].'<br>';
|
||||
$PackedElementaryStream['scrambling_control'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for scrambling_control -- 00 implies not scrambled
|
||||
$PackedElementaryStream['priority'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: priority
|
||||
$PackedElementaryStream['data_alignment_indicator'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: data_alignment_indicator -- 1 indicates that the PES packet header is immediately followed by the video start code or audio syncword
|
||||
$PackedElementaryStream['copyright'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: copyright -- 1 implies copyrighted
|
||||
$PackedElementaryStream['original_or_copy'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: original_or_copy -- 1 implies original
|
||||
$PackedElementaryStream['pts_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: pts_flag -- Presentation Time Stamp
|
||||
$PackedElementaryStream['dts_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: dts_flag -- Decode Time Stamp
|
||||
$PackedElementaryStream['escr_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: escr_flag -- Elementary Stream Clock Reference
|
||||
$PackedElementaryStream['es_rate_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: es_rate_flag -- Elementary Stream [data] Rate
|
||||
$PackedElementaryStream['dsm_trick_mode_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: dsm_trick_mode_flag -- DSM trick mode - not used by DVD
|
||||
$PackedElementaryStream['additional_copy_info_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: additional_copy_info_flag
|
||||
$PackedElementaryStream['crc_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: crc_flag
|
||||
$PackedElementaryStream['extension_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: extension_flag
|
||||
$PackedElementaryStream['pes_remain_header_length'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8); // 1 bit flag: priority
|
||||
|
||||
$additional_header_bytes = 0;
|
||||
$additional_header_bytes += ($PackedElementaryStream['pts_flag'] ? 5 : 0);
|
||||
$additional_header_bytes += ($PackedElementaryStream['dts_flag'] ? 5 : 0);
|
||||
$additional_header_bytes += ($PackedElementaryStream['escr_flag'] ? 6 : 0);
|
||||
$additional_header_bytes += ($PackedElementaryStream['es_rate_flag'] ? 3 : 0);
|
||||
$additional_header_bytes += ($PackedElementaryStream['additional_copy_info_flag'] ? 1 : 0);
|
||||
$additional_header_bytes += ($PackedElementaryStream['crc_flag'] ? 2 : 0);
|
||||
$additional_header_bytes += ($PackedElementaryStream['extension_flag'] ? 1 : 0);
|
||||
$PackedElementaryStream['additional_header_bytes'] = $additional_header_bytes;
|
||||
$bitstream .= getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 9, $additional_header_bytes));
|
||||
|
||||
$info['mpeg']['packed_elementary_streams'][$PackedElementaryStream['stream_type']][$PackedElementaryStream['stream_id']][] = $PackedElementaryStream;
|
||||
*/
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
|
||||
$getid3_temp->info = $info;
|
||||
$getid3_mp3 = new getid3_mp3($getid3_temp);
|
||||
for ($i = 0; $i <= 7; $i++) {
|
||||
// some files have the MPEG-audio header 8 bytes after the end of the $00 $00 $01 $C0 signature, some have it up to 13 bytes (or more?) after
|
||||
// I have no idea why or what the difference is, so this is a stupid hack.
|
||||
// If anybody has any better idea of what's going on, please let me know - info@getid3.org
|
||||
$getid3_temp->info = $info; // only overwrite real data if valid header found
|
||||
//echo 'audio at? '.($MPEGstreamBaseOffset + $StartCodeOffset + 4 + 8 + $i).'<br>';
|
||||
if ($getid3_mp3->decodeMPEGaudioHeader($MPEGstreamBaseOffset + $StartCodeOffset + 4 + 8 + $i, $getid3_temp->info, false)) {
|
||||
//echo 'yes!<br>';
|
||||
$info = $getid3_temp->info;
|
||||
$info['audio']['bitrate_mode'] = 'cbr';
|
||||
$info['audio']['lossless'] = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
unset($getid3_temp, $getid3_mp3);
|
||||
break;
|
||||
|
||||
case 0xBC: // Program Stream Map
|
||||
case 0xBD: // Private stream 1 (non MPEG audio, subpictures)
|
||||
case 0xBE: // Padding stream
|
||||
case 0xBF: // Private stream 2 (navigation data)
|
||||
case 0xF0: // ECM stream
|
||||
case 0xF1: // EMM stream
|
||||
case 0xF2: // DSM-CC stream
|
||||
case 0xF3: // ISO/IEC_13522_stream
|
||||
case 0xF4: // ITU-I Rec. H.222.1 type A
|
||||
case 0xF5: // ITU-I Rec. H.222.1 type B
|
||||
case 0xF6: // ITU-I Rec. H.222.1 type C
|
||||
case 0xF7: // ITU-I Rec. H.222.1 type D
|
||||
case 0xF8: // ITU-I Rec. H.222.1 type E
|
||||
case 0xF9: // ancilliary stream
|
||||
case 0xFA: // ISO/IEC 14496-1 SL-packtized stream
|
||||
case 0xFB: // ISO/IEC 14496-1 FlexMux stream
|
||||
case 0xFC: // metadata stream
|
||||
case 0xFD: // extended stream ID
|
||||
case 0xFE: // reserved data stream
|
||||
case 0xFF: // program stream directory
|
||||
// ignore
|
||||
break;
|
||||
|
||||
default:
|
||||
// ignore
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
|
||||
|
||||
// // Temporary hack to account for interleaving overhead:
|
||||
// if (!empty($info['video']['bitrate']) && !empty($info['audio']['bitrate'])) {
|
||||
// $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($info['video']['bitrate'] + $info['audio']['bitrate']);
|
||||
//
|
||||
// // Interleaved MPEG audio/video files have a certain amount of overhead that varies
|
||||
// // by both video and audio bitrates, and not in any sensible, linear/logarithmic pattern
|
||||
// // Use interpolated lookup tables to approximately guess how much is overhead, because
|
||||
// // playtime is calculated as filesize / total-bitrate
|
||||
// $info['playtime_seconds'] *= self::systemNonOverheadPercentage($info['video']['bitrate'], $info['audio']['bitrate']);
|
||||
//
|
||||
// //switch ($info['video']['bitrate']) {
|
||||
// // case('5000000'):
|
||||
// // $multiplier = 0.93292642112380355828048824319889;
|
||||
// // break;
|
||||
// // case('5500000'):
|
||||
// // $multiplier = 0.93582895375200989965359777343219;
|
||||
// // break;
|
||||
// // case('6000000'):
|
||||
// // $multiplier = 0.93796247714820932532911373859139;
|
||||
// // break;
|
||||
// // case('7000000'):
|
||||
// // $multiplier = 0.9413264083635103463010117778776;
|
||||
// // break;
|
||||
// // default:
|
||||
// // $multiplier = 1;
|
||||
// // break;
|
||||
// //}
|
||||
// //$info['playtime_seconds'] *= $multiplier;
|
||||
// //$this->warning('Interleaved MPEG audio/video playtime may be inaccurate. With current hack should be within a few seconds of accurate. Report to info@getid3.org if off by more than 10 seconds.');
|
||||
// if ($info['video']['bitrate'] < 50000) {
|
||||
// $this->warning('Interleaved MPEG audio/video playtime may be slightly inaccurate for video bitrates below 100kbps. Except in extreme low-bitrate situations, error should be less than 1%. Report to info@getid3.org if greater than this.');
|
||||
// }
|
||||
// }
|
||||
//
|
||||
/*
|
||||
$time_prev = 0;
|
||||
$byte_prev = 0;
|
||||
$vbr_bitrates = array();
|
||||
foreach ($info['mpeg']['group_of_pictures'] as $gopkey => $gopdata) {
|
||||
$time_this = ($gopdata['time_code_hours'] * 3600) + ($gopdata['time_code_minutes'] * 60) + $gopdata['time_code_seconds'] + ($gopdata['time_code_seconds'] / 30);
|
||||
$byte_this = $gopdata['byte_offset'];
|
||||
if ($gopkey > 0) {
|
||||
if ($time_this > $time_prev) {
|
||||
$bytedelta = $byte_this - $byte_prev;
|
||||
$timedelta = $time_this - $time_prev;
|
||||
$this_bitrate = ($bytedelta * 8) / $timedelta;
|
||||
echo $gopkey.': ('.number_format($time_prev, 2).'-'.number_format($time_this, 2).') '.number_format($bytedelta).' bytes over '.number_format($timedelta, 3).' seconds = '.number_format($this_bitrate / 1000, 2).'kbps<br>';
|
||||
$time_prev = $time_this;
|
||||
$byte_prev = $byte_this;
|
||||
$vbr_bitrates[] = $this_bitrate;
|
||||
}
|
||||
}
|
||||
}
|
||||
echo 'average_File_bitrate = '.number_format(array_sum($vbr_bitrates) / count($vbr_bitrates), 1).'<br>';
|
||||
*/
|
||||
//echo '<pre>'.print_r($FramesByGOP, true).'</pre>';
|
||||
if (!empty($info['mpeg']['video']['bitrate_mode']) && ($info['mpeg']['video']['bitrate_mode'] == 'vbr')) {
|
||||
$last_GOP_id = max(array_keys($FramesByGOP));
|
||||
$frames_in_last_GOP = count($FramesByGOP[$last_GOP_id]);
|
||||
$gopdata = &$info['mpeg']['group_of_pictures'][$last_GOP_id];
|
||||
$info['playtime_seconds'] = ($gopdata['time_code_hours'] * 3600) + ($gopdata['time_code_minutes'] * 60) + $gopdata['time_code_seconds'] + (($gopdata['time_code_pictures'] + $frames_in_last_GOP + 1) / $info['mpeg']['video']['frame_rate']);
|
||||
if (!isset($info['video']['bitrate'])) {
|
||||
$overall_bitrate = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds'];
|
||||
$info['video']['bitrate'] = $overall_bitrate - (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0);
|
||||
}
|
||||
unset($info['mpeg']['group_of_pictures']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $bitstream
|
||||
* @param int $bitstreamoffset
|
||||
* @param int $bits_to_read
|
||||
* @param bool $return_singlebit_as_boolean
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
private function readBitsFromStream(&$bitstream, &$bitstreamoffset, $bits_to_read, $return_singlebit_as_boolean=true) {
|
||||
$return = bindec(substr($bitstream, $bitstreamoffset, $bits_to_read));
|
||||
$bitstreamoffset += $bits_to_read;
|
||||
if (($bits_to_read == 1) && $return_singlebit_as_boolean) {
|
||||
$return = (bool) $return;
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $VideoBitrate
|
||||
* @param int $AudioBitrate
|
||||
*
|
||||
* @return float|int
|
||||
*/
|
||||
public static function systemNonOverheadPercentage($VideoBitrate, $AudioBitrate) {
|
||||
$OverheadPercentage = 0;
|
||||
|
||||
$AudioBitrate = max(min($AudioBitrate / 1000, 384), 32); // limit to range of 32kbps - 384kbps (should be only legal bitrates, but maybe VBR?)
|
||||
$VideoBitrate = max(min($VideoBitrate / 1000, 10000), 10); // limit to range of 10kbps - 10Mbps (beyond that curves flatten anyways, no big loss)
|
||||
|
||||
|
||||
$OverheadMultiplierByBitrate = array();
|
||||
//OMBB[audiobitrate] = array(video-10kbps, video-100kbps, video-1000kbps, video-10000kbps)
|
||||
$OverheadMultiplierByBitrate[32] = array(0, 0.9676287944368530, 0.9802276264360310, 0.9844916183244460, 0.9852821845179940);
|
||||
$OverheadMultiplierByBitrate[48] = array(0, 0.9779100089209830, 0.9787770035359320, 0.9846738664076130, 0.9852683013799960);
|
||||
$OverheadMultiplierByBitrate[56] = array(0, 0.9731249855367600, 0.9776624308938040, 0.9832606361852130, 0.9843922606633340);
|
||||
$OverheadMultiplierByBitrate[64] = array(0, 0.9755642683275760, 0.9795256705493390, 0.9836573009193170, 0.9851122539404470);
|
||||
$OverheadMultiplierByBitrate[96] = array(0, 0.9788025247497290, 0.9798553314148700, 0.9822956869792560, 0.9834815119124690);
|
||||
$OverheadMultiplierByBitrate[128] = array(0, 0.9816940050925480, 0.9821675936072120, 0.9829756927470870, 0.9839763420152050);
|
||||
$OverheadMultiplierByBitrate[160] = array(0, 0.9825894094561180, 0.9820913399073960, 0.9823907143253970, 0.9832821783651570);
|
||||
$OverheadMultiplierByBitrate[192] = array(0, 0.9832038474336260, 0.9825731694317960, 0.9821028622712400, 0.9828262076447620);
|
||||
$OverheadMultiplierByBitrate[224] = array(0, 0.9836516298538770, 0.9824718601823890, 0.9818302180625380, 0.9823735101626480);
|
||||
$OverheadMultiplierByBitrate[256] = array(0, 0.9845863022094920, 0.9837229411967540, 0.9824521662210830, 0.9828645172100790);
|
||||
$OverheadMultiplierByBitrate[320] = array(0, 0.9849565280263180, 0.9837683142805110, 0.9822885275960400, 0.9824424382727190);
|
||||
$OverheadMultiplierByBitrate[384] = array(0, 0.9856094774357600, 0.9844573394432720, 0.9825970399837330, 0.9824673808303890);
|
||||
|
||||
$BitrateToUseMin = 32;
|
||||
$BitrateToUseMax = 32;
|
||||
$previousBitrate = 32;
|
||||
foreach ($OverheadMultiplierByBitrate as $key => $value) {
|
||||
if ($AudioBitrate >= $previousBitrate) {
|
||||
$BitrateToUseMin = $previousBitrate;
|
||||
}
|
||||
if ($AudioBitrate < $key) {
|
||||
$BitrateToUseMax = $key;
|
||||
break;
|
||||
}
|
||||
$previousBitrate = $key;
|
||||
}
|
||||
$FactorA = ($BitrateToUseMax - $AudioBitrate) / ($BitrateToUseMax - $BitrateToUseMin);
|
||||
|
||||
$VideoBitrateLog10 = log10($VideoBitrate);
|
||||
$VideoFactorMin1 = $OverheadMultiplierByBitrate[$BitrateToUseMin][floor($VideoBitrateLog10)];
|
||||
$VideoFactorMin2 = $OverheadMultiplierByBitrate[$BitrateToUseMax][floor($VideoBitrateLog10)];
|
||||
$VideoFactorMax1 = $OverheadMultiplierByBitrate[$BitrateToUseMin][ceil($VideoBitrateLog10)];
|
||||
$VideoFactorMax2 = $OverheadMultiplierByBitrate[$BitrateToUseMax][ceil($VideoBitrateLog10)];
|
||||
$FactorV = $VideoBitrateLog10 - floor($VideoBitrateLog10);
|
||||
|
||||
$OverheadPercentage = $VideoFactorMin1 * $FactorA * $FactorV;
|
||||
$OverheadPercentage += $VideoFactorMin2 * (1 - $FactorA) * $FactorV;
|
||||
$OverheadPercentage += $VideoFactorMax1 * $FactorA * (1 - $FactorV);
|
||||
$OverheadPercentage += $VideoFactorMax2 * (1 - $FactorA) * (1 - $FactorV);
|
||||
|
||||
return $OverheadPercentage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $rawframerate
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function videoFramerateLookup($rawframerate) {
|
||||
$lookup = array(0, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60);
|
||||
return (float) (isset($lookup[$rawframerate]) ? $lookup[$rawframerate] : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $rawaspectratio
|
||||
* @param int $mpeg_version
|
||||
* @param int $width
|
||||
* @param int $height
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function videoAspectRatioLookup($rawaspectratio, $mpeg_version=1, $width=0, $height=0) {
|
||||
$lookup = array(
|
||||
1 => array(0, 1, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815, 1.0255, 1.0695, 1.0950, 1.1575, 1.2015, 0),
|
||||
2 => array(0, 1, 1.3333, 1.7778, 2.2100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
);
|
||||
$ratio = (float) (isset($lookup[$mpeg_version][$rawaspectratio]) ? $lookup[$mpeg_version][$rawaspectratio] : 0);
|
||||
if ($mpeg_version == 2 && $ratio != 1 && $width != 0) {
|
||||
// Calculate pixel aspect ratio from MPEG-2 display aspect ratio
|
||||
$ratio = $ratio * $height / $width;
|
||||
}
|
||||
return $ratio;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $rawaspectratio
|
||||
* @param int $mpeg_version
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function videoAspectRatioTextLookup($rawaspectratio, $mpeg_version=1) {
|
||||
$lookup = array(
|
||||
1 => array('forbidden', 'square pixels', '0.6735', '16:9, 625 line, PAL', '0.7615', '0.8055', '16:9, 525 line, NTSC', '0.8935', '4:3, 625 line, PAL, CCIR601', '0.9815', '1.0255', '1.0695', '4:3, 525 line, NTSC, CCIR601', '1.1575', '1.2015', 'reserved'),
|
||||
2 => array('forbidden', 'square pixels', '4:3', '16:9', '2.21:1', 'reserved', 'reserved', 'reserved', 'reserved', 'reserved', 'reserved', 'reserved', 'reserved', 'reserved', 'reserved', 'reserved'), // http://dvd.sourceforge.net/dvdinfo/mpeghdrs.html
|
||||
);
|
||||
return (isset($lookup[$mpeg_version][$rawaspectratio]) ? $lookup[$mpeg_version][$rawaspectratio] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $video_format
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function videoFormatTextLookup($video_format) {
|
||||
// ISO/IEC 13818-2, section 6.3.6, Table 6-6. Meaning of video_format
|
||||
$lookup = array('component', 'PAL', 'NTSC', 'SECAM', 'MAC', 'Unspecified video format', 'reserved(6)', 'reserved(7)');
|
||||
return (isset($lookup[$video_format]) ? $lookup[$video_format] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $scalable_mode
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function scalableModeTextLookup($scalable_mode) {
|
||||
// ISO/IEC 13818-2, section 6.3.8, Table 6-10. Definition of scalable_mode
|
||||
$lookup = array('data partitioning', 'spatial scalability', 'SNR scalability', 'temporal scalability');
|
||||
return (isset($lookup[$scalable_mode]) ? $lookup[$scalable_mode] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $picture_structure
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function pictureStructureTextLookup($picture_structure) {
|
||||
// ISO/IEC 13818-2, section 6.3.11, Table 6-14 Meaning of picture_structure
|
||||
$lookup = array('reserved', 'Top Field', 'Bottom Field', 'Frame picture');
|
||||
return (isset($lookup[$picture_structure]) ? $lookup[$picture_structure] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $chroma_format
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function chromaFormatTextLookup($chroma_format) {
|
||||
// ISO/IEC 13818-2, section 6.3.11, Table 6-14 Meaning of picture_structure
|
||||
$lookup = array('reserved', '4:2:0', '4:2:2', '4:4:4');
|
||||
return (isset($lookup[$chroma_format]) ? $lookup[$chroma_format] : '');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,243 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.nsv.php //
|
||||
// module for analyzing Nullsoft NSV files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
class getid3_nsv extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$NSVheader = $this->fread(4);
|
||||
|
||||
switch ($NSVheader) {
|
||||
case 'NSVs':
|
||||
if ($this->getNSVsHeaderFilepointer(0)) {
|
||||
$info['fileformat'] = 'nsv';
|
||||
$info['audio']['dataformat'] = 'nsv';
|
||||
$info['video']['dataformat'] = 'nsv';
|
||||
$info['audio']['lossless'] = false;
|
||||
$info['video']['lossless'] = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NSVf':
|
||||
if ($this->getNSVfHeaderFilepointer(0)) {
|
||||
$info['fileformat'] = 'nsv';
|
||||
$info['audio']['dataformat'] = 'nsv';
|
||||
$info['video']['dataformat'] = 'nsv';
|
||||
$info['audio']['lossless'] = false;
|
||||
$info['video']['lossless'] = false;
|
||||
$this->getNSVsHeaderFilepointer($info['nsv']['NSVf']['header_length']);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->error('Expecting "NSVs" or "NSVf" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($NSVheader).'"');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($info['nsv']['NSVf'])) {
|
||||
$this->warning('NSVf header not present - cannot calculate playtime or bitrate');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $fileoffset
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getNSVsHeaderFilepointer($fileoffset) {
|
||||
$info = &$this->getid3->info;
|
||||
$this->fseek($fileoffset);
|
||||
$NSVsheader = $this->fread(28);
|
||||
$offset = 0;
|
||||
|
||||
$info['nsv']['NSVs']['identifier'] = substr($NSVsheader, $offset, 4);
|
||||
$offset += 4;
|
||||
|
||||
if ($info['nsv']['NSVs']['identifier'] != 'NSVs') {
|
||||
$this->error('expected "NSVs" at offset ('.$fileoffset.'), found "'.$info['nsv']['NSVs']['identifier'].'" instead');
|
||||
unset($info['nsv']['NSVs']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['nsv']['NSVs']['offset'] = $fileoffset;
|
||||
|
||||
$info['nsv']['NSVs']['video_codec'] = substr($NSVsheader, $offset, 4);
|
||||
$offset += 4;
|
||||
$info['nsv']['NSVs']['audio_codec'] = substr($NSVsheader, $offset, 4);
|
||||
$offset += 4;
|
||||
$info['nsv']['NSVs']['resolution_x'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$info['nsv']['NSVs']['resolution_y'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 2));
|
||||
$offset += 2;
|
||||
|
||||
$info['nsv']['NSVs']['framerate_index'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
//$info['nsv']['NSVs']['unknown1b'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
//$info['nsv']['NSVs']['unknown1c'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
//$info['nsv']['NSVs']['unknown1d'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
//$info['nsv']['NSVs']['unknown2a'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
//$info['nsv']['NSVs']['unknown2b'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
//$info['nsv']['NSVs']['unknown2c'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
//$info['nsv']['NSVs']['unknown2d'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
|
||||
switch ($info['nsv']['NSVs']['audio_codec']) {
|
||||
case 'PCM ':
|
||||
$info['nsv']['NSVs']['bits_channel'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
$info['nsv']['NSVs']['channels'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
|
||||
$offset += 1;
|
||||
$info['nsv']['NSVs']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 2));
|
||||
$offset += 2;
|
||||
|
||||
$info['audio']['sample_rate'] = $info['nsv']['NSVs']['sample_rate'];
|
||||
break;
|
||||
|
||||
case 'MP3 ':
|
||||
case 'NONE':
|
||||
default:
|
||||
//$info['nsv']['NSVs']['unknown3'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 4));
|
||||
$offset += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
$info['video']['resolution_x'] = $info['nsv']['NSVs']['resolution_x'];
|
||||
$info['video']['resolution_y'] = $info['nsv']['NSVs']['resolution_y'];
|
||||
$info['nsv']['NSVs']['frame_rate'] = $this->NSVframerateLookup($info['nsv']['NSVs']['framerate_index']);
|
||||
$info['video']['frame_rate'] = $info['nsv']['NSVs']['frame_rate'];
|
||||
$info['video']['bits_per_sample'] = 24;
|
||||
$info['video']['pixel_aspect_ratio'] = (float) 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $fileoffset
|
||||
* @param bool $getTOCoffsets
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getNSVfHeaderFilepointer($fileoffset, $getTOCoffsets=false) {
|
||||
$info = &$this->getid3->info;
|
||||
$this->fseek($fileoffset);
|
||||
$NSVfheader = $this->fread(28);
|
||||
$offset = 0;
|
||||
|
||||
$info['nsv']['NSVf']['identifier'] = substr($NSVfheader, $offset, 4);
|
||||
$offset += 4;
|
||||
|
||||
if ($info['nsv']['NSVf']['identifier'] != 'NSVf') {
|
||||
$this->error('expected "NSVf" at offset ('.$fileoffset.'), found "'.$info['nsv']['NSVf']['identifier'].'" instead');
|
||||
unset($info['nsv']['NSVf']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['nsv']['NSVs']['offset'] = $fileoffset;
|
||||
|
||||
$info['nsv']['NSVf']['header_length'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$info['nsv']['NSVf']['file_size'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
if ($info['nsv']['NSVf']['file_size'] > $info['avdataend']) {
|
||||
$this->warning('truncated file - NSVf header indicates '.$info['nsv']['NSVf']['file_size'].' bytes, file actually '.$info['avdataend'].' bytes');
|
||||
}
|
||||
|
||||
$info['nsv']['NSVf']['playtime_ms'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$info['nsv']['NSVf']['meta_size'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$info['nsv']['NSVf']['TOC_entries_1'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$info['nsv']['NSVf']['TOC_entries_2'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
if ($info['nsv']['NSVf']['playtime_ms'] == 0) {
|
||||
$this->error('Corrupt NSV file: NSVf.playtime_ms == zero');
|
||||
return false;
|
||||
}
|
||||
|
||||
$NSVfheader .= $this->fread($info['nsv']['NSVf']['meta_size'] + (4 * $info['nsv']['NSVf']['TOC_entries_1']) + (4 * $info['nsv']['NSVf']['TOC_entries_2']));
|
||||
$NSVfheaderlength = strlen($NSVfheader);
|
||||
$info['nsv']['NSVf']['metadata'] = substr($NSVfheader, $offset, $info['nsv']['NSVf']['meta_size']);
|
||||
$offset += $info['nsv']['NSVf']['meta_size'];
|
||||
|
||||
if ($getTOCoffsets) {
|
||||
$TOCcounter = 0;
|
||||
while ($TOCcounter < $info['nsv']['NSVf']['TOC_entries_1']) {
|
||||
if ($TOCcounter < $info['nsv']['NSVf']['TOC_entries_1']) {
|
||||
$info['nsv']['NSVf']['TOC_1'][$TOCcounter] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$TOCcounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trim($info['nsv']['NSVf']['metadata']) != '') {
|
||||
$info['nsv']['NSVf']['metadata'] = str_replace('`', "\x01", $info['nsv']['NSVf']['metadata']);
|
||||
$CommentPairArray = explode("\x01".' ', $info['nsv']['NSVf']['metadata']);
|
||||
foreach ($CommentPairArray as $CommentPair) {
|
||||
if (strstr($CommentPair, '='."\x01")) {
|
||||
list($key, $value) = explode('='."\x01", $CommentPair, 2);
|
||||
$info['nsv']['comments'][strtolower($key)][] = trim(str_replace("\x01", '', $value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$info['playtime_seconds'] = $info['nsv']['NSVf']['playtime_ms'] / 1000;
|
||||
$info['bitrate'] = ($info['nsv']['NSVf']['file_size'] * 8) / $info['playtime_seconds'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $framerateindex
|
||||
*
|
||||
* @return float|false
|
||||
*/
|
||||
public static function NSVframerateLookup($framerateindex) {
|
||||
if ($framerateindex <= 127) {
|
||||
return (float) $framerateindex;
|
||||
}
|
||||
static $NSVframerateLookup = array();
|
||||
if (empty($NSVframerateLookup)) {
|
||||
$NSVframerateLookup[129] = 29.970;
|
||||
$NSVframerateLookup[131] = 23.976;
|
||||
$NSVframerateLookup[133] = 14.985;
|
||||
$NSVframerateLookup[197] = 59.940;
|
||||
$NSVframerateLookup[199] = 47.952;
|
||||
}
|
||||
return (isset($NSVframerateLookup[$framerateindex]) ? $NSVframerateLookup[$framerateindex] : false);
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,10 +1,11 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio-video.real.php //
|
||||
|
@ -13,69 +14,76 @@
|
|||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
|
||||
|
||||
class getid3_real
|
||||
class getid3_real extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
function getid3_real(&$fd, &$ThisFileInfo) {
|
||||
$ThisFileInfo['fileformat'] = 'real';
|
||||
$ThisFileInfo['bitrate'] = 0;
|
||||
$ThisFileInfo['playtime_seconds'] = 0;
|
||||
$info['fileformat'] = 'real';
|
||||
$info['bitrate'] = 0;
|
||||
$info['playtime_seconds'] = 0;
|
||||
|
||||
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$ChunkCounter = 0;
|
||||
while (ftell($fd) < $ThisFileInfo['avdataend']) {
|
||||
$ChunkData = fread($fd, 8);
|
||||
while ($this->ftell() < $info['avdataend']) {
|
||||
$ChunkData = $this->fread(8);
|
||||
$ChunkName = substr($ChunkData, 0, 4);
|
||||
$ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, 4, 4));
|
||||
|
||||
if ($ChunkName == '.ra'."\xFD") {
|
||||
$ChunkData .= fread($fd, $ChunkSize - 8);
|
||||
if ($this->ParseOldRAheader(substr($ChunkData, 0, 128), $ThisFileInfo['real']['old_ra_header'])) {
|
||||
$ThisFileInfo['audio']['dataformat'] = 'real';
|
||||
$ThisFileInfo['audio']['lossless'] = false;
|
||||
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['real']['old_ra_header']['sample_rate'];
|
||||
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['real']['old_ra_header']['bits_per_sample'];
|
||||
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['real']['old_ra_header']['channels'];
|
||||
$ChunkData .= $this->fread($ChunkSize - 8);
|
||||
if ($this->ParseOldRAheader(substr($ChunkData, 0, 128), $info['real']['old_ra_header'])) {
|
||||
$info['audio']['dataformat'] = 'real';
|
||||
$info['audio']['lossless'] = false;
|
||||
$info['audio']['sample_rate'] = $info['real']['old_ra_header']['sample_rate'];
|
||||
$info['audio']['bits_per_sample'] = $info['real']['old_ra_header']['bits_per_sample'];
|
||||
$info['audio']['channels'] = $info['real']['old_ra_header']['channels'];
|
||||
|
||||
$ThisFileInfo['playtime_seconds'] = 60 * ($ThisFileInfo['real']['old_ra_header']['audio_bytes'] / $ThisFileInfo['real']['old_ra_header']['bytes_per_minute']);
|
||||
$ThisFileInfo['audio']['bitrate'] = 8 * ($ThisFileInfo['real']['old_ra_header']['audio_bytes'] / $ThisFileInfo['playtime_seconds']);
|
||||
$ThisFileInfo['audio']['codec'] = $this->RealAudioCodecFourCClookup($ThisFileInfo['real']['old_ra_header']['fourcc'], $ThisFileInfo['audio']['bitrate']);
|
||||
$info['playtime_seconds'] = 60 * ($info['real']['old_ra_header']['audio_bytes'] / $info['real']['old_ra_header']['bytes_per_minute']);
|
||||
$info['audio']['bitrate'] = 8 * ($info['real']['old_ra_header']['audio_bytes'] / $info['playtime_seconds']);
|
||||
$info['audio']['codec'] = $this->RealAudioCodecFourCClookup($info['real']['old_ra_header']['fourcc'], $info['audio']['bitrate']);
|
||||
|
||||
foreach ($ThisFileInfo['real']['old_ra_header']['comments'] as $key => $valuearray) {
|
||||
foreach ($info['real']['old_ra_header']['comments'] as $key => $valuearray) {
|
||||
if (strlen(trim($valuearray[0])) > 0) {
|
||||
$ThisFileInfo['real']['comments'][$key][] = trim($valuearray[0]);
|
||||
$info['real']['comments'][$key][] = trim($valuearray[0]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
$ThisFileInfo['error'][] = 'There was a problem parsing this RealAudio file. Please submit it for analysis to info@getid3.org';
|
||||
unset($ThisFileInfo['bitrate']);
|
||||
unset($ThisFileInfo['playtime_seconds']);
|
||||
$this->error('There was a problem parsing this RealAudio file. Please submit it for analysis to info@getid3.org');
|
||||
unset($info['bitrate']);
|
||||
unset($info['playtime_seconds']);
|
||||
return false;
|
||||
}
|
||||
|
||||
// shortcut
|
||||
$ThisFileInfo['real']['chunks'][$ChunkCounter] = array();
|
||||
$thisfile_real_chunks_currentchunk = &$ThisFileInfo['real']['chunks'][$ChunkCounter];
|
||||
$info['real']['chunks'][$ChunkCounter] = array();
|
||||
$thisfile_real_chunks_currentchunk = &$info['real']['chunks'][$ChunkCounter];
|
||||
|
||||
$thisfile_real_chunks_currentchunk['name'] = $ChunkName;
|
||||
$thisfile_real_chunks_currentchunk['offset'] = ftell($fd) - 8;
|
||||
$thisfile_real_chunks_currentchunk['offset'] = $this->ftell() - 8;
|
||||
$thisfile_real_chunks_currentchunk['length'] = $ChunkSize;
|
||||
if (($thisfile_real_chunks_currentchunk['offset'] + $thisfile_real_chunks_currentchunk['length']) > $ThisFileInfo['avdataend']) {
|
||||
$ThisFileInfo['warning'][] = 'Chunk "'.$thisfile_real_chunks_currentchunk['name'].'" at offset '.$thisfile_real_chunks_currentchunk['offset'].' claims to be '.$thisfile_real_chunks_currentchunk['length'].' bytes long, which is beyond end of file';
|
||||
if (($thisfile_real_chunks_currentchunk['offset'] + $thisfile_real_chunks_currentchunk['length']) > $info['avdataend']) {
|
||||
$this->warning('Chunk "'.$thisfile_real_chunks_currentchunk['name'].'" at offset '.$thisfile_real_chunks_currentchunk['offset'].' claims to be '.$thisfile_real_chunks_currentchunk['length'].' bytes long, which is beyond end of file');
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($ChunkSize > (GETID3_FREAD_BUFFER_SIZE + 8)) {
|
||||
if ($ChunkSize > ($this->getid3->fread_buffer_size() + 8)) {
|
||||
|
||||
$ChunkData .= fread($fd, GETID3_FREAD_BUFFER_SIZE - 8);
|
||||
fseek($fd, $thisfile_real_chunks_currentchunk['offset'] + $ChunkSize, SEEK_SET);
|
||||
$ChunkData .= $this->fread($this->getid3->fread_buffer_size() - 8);
|
||||
$this->fseek($thisfile_real_chunks_currentchunk['offset'] + $ChunkSize);
|
||||
|
||||
} elseif(($ChunkSize - 8) > 0) {
|
||||
|
||||
$ChunkData .= fread($fd, $ChunkSize - 8);
|
||||
$ChunkData .= $this->fread($ChunkSize - 8);
|
||||
|
||||
}
|
||||
$offset = 8;
|
||||
|
@ -95,7 +103,7 @@ class getid3_real
|
|||
break;
|
||||
|
||||
default:
|
||||
//$ThisFileInfo['warning'][] = 'Expected .RMF-object_version to be "0", actual value is "'.$thisfile_real_chunks_currentchunk['object_version'].'" (should not be a problem)';
|
||||
//$this->warning('Expected .RMF-object_version to be "0", actual value is "'.$thisfile_real_chunks_currentchunk['object_version'].'" (should not be a problem)');
|
||||
break;
|
||||
|
||||
}
|
||||
|
@ -128,9 +136,9 @@ class getid3_real
|
|||
$offset += 2;
|
||||
$thisfile_real_chunks_currentchunk['flags_raw'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
|
||||
$offset += 2;
|
||||
$ThisFileInfo['playtime_seconds'] = $thisfile_real_chunks_currentchunk['duration'] / 1000;
|
||||
$info['playtime_seconds'] = $thisfile_real_chunks_currentchunk['duration'] / 1000;
|
||||
if ($thisfile_real_chunks_currentchunk['duration'] > 0) {
|
||||
$ThisFileInfo['bitrate'] += $thisfile_real_chunks_currentchunk['avg_bit_rate'];
|
||||
$info['bitrate'] += $thisfile_real_chunks_currentchunk['avg_bit_rate'];
|
||||
}
|
||||
$thisfile_real_chunks_currentchunk['flags']['save_enabled'] = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0001);
|
||||
$thisfile_real_chunks_currentchunk['flags']['perfect_play'] = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0002);
|
||||
|
@ -200,26 +208,27 @@ class getid3_real
|
|||
//$thisfile_real_chunks_currentchunk_videoinfo['unknown8'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 34, 2));
|
||||
//$thisfile_real_chunks_currentchunk_videoinfo['unknown9'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 36, 2));
|
||||
|
||||
$thisfile_real_chunks_currentchunk_videoinfo['codec'] = getid3_riff::RIFFfourccLookup($thisfile_real_chunks_currentchunk_videoinfo['fourcc2']);
|
||||
$thisfile_real_chunks_currentchunk_videoinfo['codec'] = getid3_riff::fourccLookup($thisfile_real_chunks_currentchunk_videoinfo['fourcc2']);
|
||||
|
||||
$ThisFileInfo['video']['resolution_x'] = $thisfile_real_chunks_currentchunk_videoinfo['width'];
|
||||
$ThisFileInfo['video']['resolution_y'] = $thisfile_real_chunks_currentchunk_videoinfo['height'];
|
||||
$ThisFileInfo['video']['frame_rate'] = (float) $thisfile_real_chunks_currentchunk_videoinfo['frames_per_second'];
|
||||
$ThisFileInfo['video']['codec'] = $thisfile_real_chunks_currentchunk_videoinfo['codec'];
|
||||
$ThisFileInfo['video']['bits_per_sample'] = $thisfile_real_chunks_currentchunk_videoinfo['bits_per_sample'];
|
||||
$info['video']['resolution_x'] = $thisfile_real_chunks_currentchunk_videoinfo['width'];
|
||||
$info['video']['resolution_y'] = $thisfile_real_chunks_currentchunk_videoinfo['height'];
|
||||
$info['video']['frame_rate'] = (float) $thisfile_real_chunks_currentchunk_videoinfo['frames_per_second'];
|
||||
$info['video']['codec'] = $thisfile_real_chunks_currentchunk_videoinfo['codec'];
|
||||
$info['video']['bits_per_sample'] = $thisfile_real_chunks_currentchunk_videoinfo['bits_per_sample'];
|
||||
break;
|
||||
|
||||
case 'audio/x-pn-realaudio':
|
||||
case 'audio/x-pn-multirate-realaudio':
|
||||
$this->ParseOldRAheader($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk['parsed_audio_data']);
|
||||
$this->ParseOldRAheader($thisfile_real_chunks_currentchunk_typespecificdata, $parsedAudioData);
|
||||
$thisfile_real_chunks_currentchunk['parsed_audio_data'] = &$parsedAudioData;
|
||||
|
||||
$ThisFileInfo['audio']['sample_rate'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['sample_rate'];
|
||||
$ThisFileInfo['audio']['bits_per_sample'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['bits_per_sample'];
|
||||
$ThisFileInfo['audio']['channels'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['channels'];
|
||||
if (!empty($ThisFileInfo['audio']['dataformat'])) {
|
||||
foreach ($ThisFileInfo['audio'] as $key => $value) {
|
||||
$info['audio']['sample_rate'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['sample_rate'];
|
||||
$info['audio']['bits_per_sample'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['bits_per_sample'];
|
||||
$info['audio']['channels'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['channels'];
|
||||
if (!empty($info['audio']['dataformat'])) {
|
||||
foreach ($info['audio'] as $key => $value) {
|
||||
if ($key != 'streams') {
|
||||
$ThisFileInfo['audio']['streams'][$thisfile_real_chunks_currentchunk['stream_number']][$key] = $value;
|
||||
$info['audio']['streams'][$thisfile_real_chunks_currentchunk['stream_number']][$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -255,36 +264,36 @@ class getid3_real
|
|||
}
|
||||
|
||||
|
||||
if (empty($ThisFileInfo['playtime_seconds'])) {
|
||||
$ThisFileInfo['playtime_seconds'] = max($ThisFileInfo['playtime_seconds'], ($thisfile_real_chunks_currentchunk['duration'] + $thisfile_real_chunks_currentchunk['start_time']) / 1000);
|
||||
if (empty($info['playtime_seconds'])) {
|
||||
$info['playtime_seconds'] = max($info['playtime_seconds'], ($thisfile_real_chunks_currentchunk['duration'] + $thisfile_real_chunks_currentchunk['start_time']) / 1000);
|
||||
}
|
||||
if ($thisfile_real_chunks_currentchunk['duration'] > 0) {
|
||||
switch ($thisfile_real_chunks_currentchunk['mime_type']) {
|
||||
case 'audio/x-pn-realaudio':
|
||||
case 'audio/x-pn-multirate-realaudio':
|
||||
$ThisFileInfo['audio']['bitrate'] = (isset($ThisFileInfo['audio']['bitrate']) ? $ThisFileInfo['audio']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate'];
|
||||
$ThisFileInfo['audio']['codec'] = $this->RealAudioCodecFourCClookup($thisfile_real_chunks_currentchunk['parsed_audio_data']['fourcc'], $ThisFileInfo['audio']['bitrate']);
|
||||
$ThisFileInfo['audio']['dataformat'] = 'real';
|
||||
$ThisFileInfo['audio']['lossless'] = false;
|
||||
$info['audio']['bitrate'] = (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate'];
|
||||
$info['audio']['codec'] = $this->RealAudioCodecFourCClookup($thisfile_real_chunks_currentchunk['parsed_audio_data']['fourcc'], $info['audio']['bitrate']);
|
||||
$info['audio']['dataformat'] = 'real';
|
||||
$info['audio']['lossless'] = false;
|
||||
break;
|
||||
|
||||
case 'video/x-pn-realvideo':
|
||||
case 'video/x-pn-multirate-realvideo':
|
||||
$ThisFileInfo['video']['bitrate'] = (isset($ThisFileInfo['video']['bitrate']) ? $ThisFileInfo['video']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate'];
|
||||
$ThisFileInfo['video']['bitrate_mode'] = 'cbr';
|
||||
$ThisFileInfo['video']['dataformat'] = 'real';
|
||||
$ThisFileInfo['video']['lossless'] = false;
|
||||
$ThisFileInfo['video']['pixel_aspect_ratio'] = (float) 1;
|
||||
$info['video']['bitrate'] = (isset($info['video']['bitrate']) ? $info['video']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate'];
|
||||
$info['video']['bitrate_mode'] = 'cbr';
|
||||
$info['video']['dataformat'] = 'real';
|
||||
$info['video']['lossless'] = false;
|
||||
$info['video']['pixel_aspect_ratio'] = (float) 1;
|
||||
break;
|
||||
|
||||
case 'audio/x-ralf-mpeg4-generic':
|
||||
$ThisFileInfo['audio']['bitrate'] = (isset($ThisFileInfo['audio']['bitrate']) ? $ThisFileInfo['audio']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate'];
|
||||
$ThisFileInfo['audio']['codec'] = 'RealAudio Lossless';
|
||||
$ThisFileInfo['audio']['dataformat'] = 'real';
|
||||
$ThisFileInfo['audio']['lossless'] = true;
|
||||
$info['audio']['bitrate'] = (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate'];
|
||||
$info['audio']['codec'] = 'RealAudio Lossless';
|
||||
$info['audio']['dataformat'] = 'real';
|
||||
$info['audio']['lossless'] = true;
|
||||
break;
|
||||
}
|
||||
$ThisFileInfo['bitrate'] = (isset($ThisFileInfo['video']['bitrate']) ? $ThisFileInfo['video']['bitrate'] : 0) + (isset($ThisFileInfo['audio']['bitrate']) ? $ThisFileInfo['audio']['bitrate'] : 0);
|
||||
$info['bitrate'] = (isset($info['video']['bitrate']) ? $info['video']['bitrate'] : 0) + (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -317,7 +326,7 @@ class getid3_real
|
|||
$commentkeystocopy = array('title'=>'title', 'artist'=>'artist', 'copyright'=>'copyright', 'comment'=>'comment');
|
||||
foreach ($commentkeystocopy as $key => $val) {
|
||||
if ($thisfile_real_chunks_currentchunk[$key]) {
|
||||
$ThisFileInfo['real']['comments'][$val][] = trim($thisfile_real_chunks_currentchunk[$key]);
|
||||
$info['real']['comments'][$val][] = trim($thisfile_real_chunks_currentchunk[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -345,30 +354,35 @@ class getid3_real
|
|||
break 2;
|
||||
} else {
|
||||
// non-last index chunk, seek to next index chunk (skipping actual index data)
|
||||
fseek($fd, $thisfile_real_chunks_currentchunk['next_index_header'], SEEK_SET);
|
||||
$this->fseek($thisfile_real_chunks_currentchunk['next_index_header']);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$ThisFileInfo['warning'][] = 'Unhandled RealMedia chunk "'.$ChunkName.'" at offset '.$thisfile_real_chunks_currentchunk['offset'];
|
||||
$this->warning('Unhandled RealMedia chunk "'.$ChunkName.'" at offset '.$thisfile_real_chunks_currentchunk['offset']);
|
||||
break;
|
||||
}
|
||||
$ChunkCounter++;
|
||||
}
|
||||
|
||||
if (!empty($ThisFileInfo['audio']['streams'])) {
|
||||
$ThisFileInfo['audio']['bitrate'] = 0;
|
||||
foreach ($ThisFileInfo['audio']['streams'] as $key => $valuearray) {
|
||||
$ThisFileInfo['audio']['bitrate'] += $valuearray['bitrate'];
|
||||
if (!empty($info['audio']['streams'])) {
|
||||
$info['audio']['bitrate'] = 0;
|
||||
foreach ($info['audio']['streams'] as $key => $valuearray) {
|
||||
$info['audio']['bitrate'] += $valuearray['bitrate'];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function ParseOldRAheader($OldRAheaderData, &$ParsedArray) {
|
||||
/**
|
||||
* @param string $OldRAheaderData
|
||||
* @param array $ParsedArray
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ParseOldRAheader($OldRAheaderData, &$ParsedArray) {
|
||||
// http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html
|
||||
|
||||
$ParsedArray = array();
|
||||
|
@ -473,8 +487,9 @@ class getid3_real
|
|||
$ParsedArray['fourcc'] = $ParsedArray['fourcc3'];
|
||||
|
||||
}
|
||||
/** @var string[]|false[] $value */
|
||||
foreach ($ParsedArray['comments'] as $key => $value) {
|
||||
if ($ParsedArray['comments'][$key][0] === false) {
|
||||
if ($value[0] === false) {
|
||||
$ParsedArray['comments'][$key][0] = '';
|
||||
}
|
||||
}
|
||||
|
@ -482,7 +497,13 @@ class getid3_real
|
|||
return true;
|
||||
}
|
||||
|
||||
function RealAudioCodecFourCClookup($fourcc, $bitrate) {
|
||||
/**
|
||||
* @param string $fourcc
|
||||
* @param int $bitrate
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function RealAudioCodecFourCClookup($fourcc, $bitrate) {
|
||||
static $RealAudioCodecFourCClookup = array();
|
||||
if (empty($RealAudioCodecFourCClookup)) {
|
||||
// http://www.its.msstate.edu/net/real/reports/config/tags.stats
|
||||
|
@ -523,6 +544,3 @@ class getid3_real
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio-video.swf.php //
|
||||
// module for analyzing Shockwave Flash files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
class getid3_swf extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* return all parsed tags if true, otherwise do not return tags not parsed by getID3
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $ReturnAllTagData = false;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'swf';
|
||||
$info['video']['dataformat'] = 'swf';
|
||||
|
||||
// http://www.openswf.org/spec/SWFfileformat.html
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
||||
$SWFfileData = $this->fread($info['avdataend'] - $info['avdataoffset']); // 8 + 2 + 2 + max(9) bytes NOT including Frame_Size RECT data
|
||||
|
||||
$info['swf']['header']['signature'] = substr($SWFfileData, 0, 3);
|
||||
switch ($info['swf']['header']['signature']) {
|
||||
case 'FWS':
|
||||
$info['swf']['header']['compressed'] = false;
|
||||
break;
|
||||
|
||||
case 'CWS':
|
||||
$info['swf']['header']['compressed'] = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->error('Expecting "FWS" or "CWS" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['swf']['header']['signature']).'"');
|
||||
unset($info['swf']);
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
$info['swf']['header']['version'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 3, 1));
|
||||
$info['swf']['header']['length'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 4, 4));
|
||||
|
||||
if ($info['swf']['header']['compressed']) {
|
||||
$SWFHead = substr($SWFfileData, 0, 8);
|
||||
$SWFfileData = substr($SWFfileData, 8);
|
||||
if ($decompressed = @gzuncompress($SWFfileData)) {
|
||||
$SWFfileData = $SWFHead.$decompressed;
|
||||
} else {
|
||||
$this->error('Error decompressing compressed SWF data ('.strlen($SWFfileData).' bytes compressed, should be '.($info['swf']['header']['length'] - 8).' bytes uncompressed)');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$FrameSizeBitsPerValue = (ord(substr($SWFfileData, 8, 1)) & 0xF8) >> 3;
|
||||
$FrameSizeDataLength = ceil((5 + (4 * $FrameSizeBitsPerValue)) / 8);
|
||||
$FrameSizeDataString = str_pad(decbin(ord(substr($SWFfileData, 8, 1)) & 0x07), 3, '0', STR_PAD_LEFT);
|
||||
for ($i = 1; $i < $FrameSizeDataLength; $i++) {
|
||||
$FrameSizeDataString .= str_pad(decbin(ord(substr($SWFfileData, 8 + $i, 1))), 8, '0', STR_PAD_LEFT);
|
||||
}
|
||||
list($X1, $X2, $Y1, $Y2) = explode("\n", wordwrap($FrameSizeDataString, $FrameSizeBitsPerValue, "\n", 1));
|
||||
$info['swf']['header']['frame_width'] = getid3_lib::Bin2Dec($X2);
|
||||
$info['swf']['header']['frame_height'] = getid3_lib::Bin2Dec($Y2);
|
||||
|
||||
// http://www-lehre.informatik.uni-osnabrueck.de/~fbstark/diplom/docs/swf/Flash_Uncovered.htm
|
||||
// Next in the header is the frame rate, which is kind of weird.
|
||||
// It is supposed to be stored as a 16bit integer, but the first byte
|
||||
// (or last depending on how you look at it) is completely ignored.
|
||||
// Example: 0x000C -> 0x0C -> 12 So the frame rate is 12 fps.
|
||||
|
||||
// Byte at (8 + $FrameSizeDataLength) is always zero and ignored
|
||||
$info['swf']['header']['frame_rate'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 9 + $FrameSizeDataLength, 1));
|
||||
$info['swf']['header']['frame_count'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 10 + $FrameSizeDataLength, 2));
|
||||
|
||||
$info['video']['frame_rate'] = $info['swf']['header']['frame_rate'];
|
||||
$info['video']['resolution_x'] = intval(round($info['swf']['header']['frame_width'] / 20));
|
||||
$info['video']['resolution_y'] = intval(round($info['swf']['header']['frame_height'] / 20));
|
||||
$info['video']['pixel_aspect_ratio'] = (float) 1;
|
||||
|
||||
if (($info['swf']['header']['frame_count'] > 0) && ($info['swf']['header']['frame_rate'] > 0)) {
|
||||
$info['playtime_seconds'] = $info['swf']['header']['frame_count'] / $info['swf']['header']['frame_rate'];
|
||||
}
|
||||
//echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'<br>';
|
||||
|
||||
|
||||
// SWF tags
|
||||
|
||||
$CurrentOffset = 12 + $FrameSizeDataLength;
|
||||
$SWFdataLength = strlen($SWFfileData);
|
||||
|
||||
while ($CurrentOffset < $SWFdataLength) {
|
||||
//echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'<br>';
|
||||
|
||||
$TagIDTagLength = getid3_lib::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 2));
|
||||
$TagID = ($TagIDTagLength & 0xFFFC) >> 6;
|
||||
$TagLength = ($TagIDTagLength & 0x003F);
|
||||
$CurrentOffset += 2;
|
||||
if ($TagLength == 0x3F) {
|
||||
$TagLength = getid3_lib::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 4));
|
||||
$CurrentOffset += 4;
|
||||
}
|
||||
|
||||
$TagData = array();
|
||||
$TagData['offset'] = $CurrentOffset;
|
||||
$TagData['size'] = $TagLength;
|
||||
$TagData['id'] = $TagID;
|
||||
$TagData['data'] = substr($SWFfileData, $CurrentOffset, $TagLength);
|
||||
switch ($TagID) {
|
||||
case 0: // end of movie
|
||||
break 2;
|
||||
|
||||
case 9: // Set background color
|
||||
//$info['swf']['tags'][] = $TagData;
|
||||
$info['swf']['bgcolor'] = strtoupper(str_pad(dechex(getid3_lib::BigEndian2Int($TagData['data'])), 6, '0', STR_PAD_LEFT));
|
||||
break;
|
||||
|
||||
default:
|
||||
if ($this->ReturnAllTagData) {
|
||||
$info['swf']['tags'][] = $TagData;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$CurrentOffset += $TagLength;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio-video.ts.php //
|
||||
// module for analyzing MPEG Transport Stream (.ts) files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
class getid3_ts extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$TSheader = $this->fread(19);
|
||||
$magic = "\x47";
|
||||
if (substr($TSheader, 0, 1) != $magic) {
|
||||
$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($TSheader, 0, 1)).' instead.');
|
||||
return false;
|
||||
}
|
||||
$info['fileformat'] = 'ts';
|
||||
|
||||
// http://en.wikipedia.org/wiki/.ts
|
||||
|
||||
$offset = 0;
|
||||
$info['ts']['packet']['sync'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 1)); $offset += 1;
|
||||
$pid_flags_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 2)); $offset += 2;
|
||||
$SAC_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 1)); $offset += 1;
|
||||
$info['ts']['packet']['flags']['transport_error_indicator'] = (bool) ($pid_flags_raw & 0x8000); // Set by demodulator if can't correct errors in the stream, to tell the demultiplexer that the packet has an uncorrectable error
|
||||
$info['ts']['packet']['flags']['payload_unit_start_indicator'] = (bool) ($pid_flags_raw & 0x4000); // 1 means start of PES data or PSI otherwise zero only.
|
||||
$info['ts']['packet']['flags']['transport_high_priority'] = (bool) ($pid_flags_raw & 0x2000); // 1 means higher priority than other packets with the same PID.
|
||||
$info['ts']['packet']['packet_id'] = ($pid_flags_raw & 0x1FFF) >> 0;
|
||||
|
||||
$info['ts']['packet']['raw']['scrambling_control'] = ($SAC_raw & 0xC0) >> 6;
|
||||
$info['ts']['packet']['flags']['adaption_field_exists'] = (bool) ($SAC_raw & 0x20);
|
||||
$info['ts']['packet']['flags']['payload_exists'] = (bool) ($SAC_raw & 0x10);
|
||||
$info['ts']['packet']['continuity_counter'] = ($SAC_raw & 0x0F) >> 0; // Incremented only when a payload is present
|
||||
$info['ts']['packet']['scrambling_control'] = $this->TSscramblingControlLookup($info['ts']['packet']['raw']['scrambling_control']);
|
||||
|
||||
if ($info['ts']['packet']['flags']['adaption_field_exists']) {
|
||||
$AdaptionField_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 2)); $offset += 2;
|
||||
$info['ts']['packet']['adaption']['field_length'] = ($AdaptionField_raw & 0xFF00) >> 8; // Number of bytes in the adaptation field immediately following this byte
|
||||
$info['ts']['packet']['adaption']['flags']['discontinuity'] = (bool) ($AdaptionField_raw & 0x0080); // Set to 1 if current TS packet is in a discontinuity state with respect to either the continuity counter or the program clock reference
|
||||
$info['ts']['packet']['adaption']['flags']['random_access'] = (bool) ($AdaptionField_raw & 0x0040); // Set to 1 if the PES packet in this TS packet starts a video/audio sequence
|
||||
$info['ts']['packet']['adaption']['flags']['high_priority'] = (bool) ($AdaptionField_raw & 0x0020); // 1 = higher priority
|
||||
$info['ts']['packet']['adaption']['flags']['pcr'] = (bool) ($AdaptionField_raw & 0x0010); // 1 means adaptation field does contain a PCR field
|
||||
$info['ts']['packet']['adaption']['flags']['opcr'] = (bool) ($AdaptionField_raw & 0x0008); // 1 means adaptation field does contain an OPCR field
|
||||
$info['ts']['packet']['adaption']['flags']['splice_point'] = (bool) ($AdaptionField_raw & 0x0004); // 1 means presence of splice countdown field in adaptation field
|
||||
$info['ts']['packet']['adaption']['flags']['private_data'] = (bool) ($AdaptionField_raw & 0x0002); // 1 means presence of private data bytes in adaptation field
|
||||
$info['ts']['packet']['adaption']['flags']['extension'] = (bool) ($AdaptionField_raw & 0x0001); // 1 means presence of adaptation field extension
|
||||
if ($info['ts']['packet']['adaption']['flags']['pcr']) {
|
||||
$info['ts']['packet']['adaption']['raw']['pcr'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 6)); $offset += 6;
|
||||
}
|
||||
if ($info['ts']['packet']['adaption']['flags']['opcr']) {
|
||||
$info['ts']['packet']['adaption']['raw']['opcr'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 6)); $offset += 6;
|
||||
}
|
||||
}
|
||||
|
||||
$this->error('MPEG Transport Stream (.ts) parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $raw
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function TSscramblingControlLookup($raw) {
|
||||
$TSscramblingControlLookup = array(0x00=>'not scrambled', 0x01=>'reserved', 0x02=>'scrambled, even key', 0x03=>'scrambled, odd key');
|
||||
return (isset($TSscramblingControlLookup[$raw]) ? $TSscramblingControlLookup[$raw] : 'invalid');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.wtv.php //
|
||||
// module for analyzing WTV (Windows Recorded TV Show) //
|
||||
// audio-video files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
class getid3_wtv extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'wtv';
|
||||
$info['video']['dataformat'] = 'wtv';
|
||||
|
||||
$this->error('WTV (Windows Recorded TV Show) files not properly processed by this version of getID3() ['.$this->getid3->version().']');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.aa.php //
|
||||
// module for analyzing Audible Audiobook files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
class getid3_aa extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$AAheader = $this->fread(8);
|
||||
|
||||
$magic = "\x57\x90\x75\x36";
|
||||
if (substr($AAheader, 4, 4) != $magic) {
|
||||
$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AAheader, 4, 4)).'"');
|
||||
return false;
|
||||
}
|
||||
|
||||
// shortcut
|
||||
$info['aa'] = array();
|
||||
$thisfile_aa = &$info['aa'];
|
||||
|
||||
$info['fileformat'] = 'aa';
|
||||
$info['audio']['dataformat'] = 'aa';
|
||||
$this->error('Audible Audiobook (.aa) parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
|
||||
return false;
|
||||
$info['audio']['bitrate_mode'] = 'cbr'; // is it?
|
||||
$thisfile_aa['encoding'] = 'ISO-8859-1';
|
||||
|
||||
$thisfile_aa['filesize'] = getid3_lib::BigEndian2Int(substr($AAheader, 0, 4));
|
||||
if ($thisfile_aa['filesize'] > ($info['avdataend'] - $info['avdataoffset'])) {
|
||||
$this->warning('Possible truncated file - expecting "'.$thisfile_aa['filesize'].'" bytes of data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"');
|
||||
}
|
||||
|
||||
$info['audio']['bits_per_sample'] = 16; // is it?
|
||||
$info['audio']['sample_rate'] = $thisfile_aa['sample_rate'];
|
||||
$info['audio']['channels'] = $thisfile_aa['channels'];
|
||||
|
||||
//$info['playtime_seconds'] = 0;
|
||||
//$info['audio']['bitrate'] = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,541 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.aac.php //
|
||||
// module for analyzing AAC Audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
class getid3_aac extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
$this->fseek($info['avdataoffset']);
|
||||
if ($this->fread(4) == 'ADIF') {
|
||||
$this->getAACADIFheaderFilepointer();
|
||||
} else {
|
||||
$this->getAACADTSheaderFilepointer();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getAACADIFheaderFilepointer() {
|
||||
$info = &$this->getid3->info;
|
||||
$info['fileformat'] = 'aac';
|
||||
$info['audio']['dataformat'] = 'aac';
|
||||
$info['audio']['lossless'] = false;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$AACheader = $this->fread(1024);
|
||||
$offset = 0;
|
||||
|
||||
if (substr($AACheader, 0, 4) == 'ADIF') {
|
||||
|
||||
// http://faac.sourceforge.net/wiki/index.php?page=ADIF
|
||||
|
||||
// http://libmpeg.org/mpeg4/doc/w2203tfs.pdf
|
||||
// adif_header() {
|
||||
// adif_id 32
|
||||
// copyright_id_present 1
|
||||
// if( copyright_id_present )
|
||||
// copyright_id 72
|
||||
// original_copy 1
|
||||
// home 1
|
||||
// bitstream_type 1
|
||||
// bitrate 23
|
||||
// num_program_config_elements 4
|
||||
// for (i = 0; i < num_program_config_elements + 1; i++ ) {
|
||||
// if( bitstream_type == '0' )
|
||||
// adif_buffer_fullness 20
|
||||
// program_config_element()
|
||||
// }
|
||||
// }
|
||||
|
||||
$AACheaderBitstream = getid3_lib::BigEndian2Bin($AACheader);
|
||||
$bitoffset = 0;
|
||||
|
||||
$info['aac']['header_type'] = 'ADIF';
|
||||
$bitoffset += 32;
|
||||
$info['aac']['header']['mpeg_version'] = 4;
|
||||
|
||||
$info['aac']['header']['copyright'] = substr($AACheaderBitstream, $bitoffset, 1) == '1';
|
||||
$bitoffset += 1;
|
||||
if ($info['aac']['header']['copyright']) {
|
||||
$info['aac']['header']['copyright_id'] = getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 72));
|
||||
$bitoffset += 72;
|
||||
}
|
||||
$info['aac']['header']['original_copy'] = substr($AACheaderBitstream, $bitoffset, 1) == '1';
|
||||
$bitoffset += 1;
|
||||
$info['aac']['header']['home'] = substr($AACheaderBitstream, $bitoffset, 1) == '1';
|
||||
$bitoffset += 1;
|
||||
$info['aac']['header']['is_vbr'] = substr($AACheaderBitstream, $bitoffset, 1) == '1';
|
||||
$bitoffset += 1;
|
||||
if ($info['aac']['header']['is_vbr']) {
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
$info['aac']['header']['bitrate_max'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23));
|
||||
$bitoffset += 23;
|
||||
} else {
|
||||
$info['audio']['bitrate_mode'] = 'cbr';
|
||||
$info['aac']['header']['bitrate'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23));
|
||||
$bitoffset += 23;
|
||||
$info['audio']['bitrate'] = $info['aac']['header']['bitrate'];
|
||||
}
|
||||
if ($info['audio']['bitrate'] == 0) {
|
||||
$this->error('Corrupt AAC file: bitrate_audio == zero');
|
||||
return false;
|
||||
}
|
||||
$info['aac']['header']['num_program_configs'] = 1 + getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
|
||||
for ($i = 0; $i < $info['aac']['header']['num_program_configs']; $i++) {
|
||||
// http://www.audiocoding.com/wiki/index.php?page=program_config_element
|
||||
|
||||
// buffer_fullness 20
|
||||
|
||||
// element_instance_tag 4
|
||||
// object_type 2
|
||||
// sampling_frequency_index 4
|
||||
// num_front_channel_elements 4
|
||||
// num_side_channel_elements 4
|
||||
// num_back_channel_elements 4
|
||||
// num_lfe_channel_elements 2
|
||||
// num_assoc_data_elements 3
|
||||
// num_valid_cc_elements 4
|
||||
// mono_mixdown_present 1
|
||||
// mono_mixdown_element_number 4 if mono_mixdown_present == 1
|
||||
// stereo_mixdown_present 1
|
||||
// stereo_mixdown_element_number 4 if stereo_mixdown_present == 1
|
||||
// matrix_mixdown_idx_present 1
|
||||
// matrix_mixdown_idx 2 if matrix_mixdown_idx_present == 1
|
||||
// pseudo_surround_enable 1 if matrix_mixdown_idx_present == 1
|
||||
// for (i = 0; i < num_front_channel_elements; i++) {
|
||||
// front_element_is_cpe[i] 1
|
||||
// front_element_tag_select[i] 4
|
||||
// }
|
||||
// for (i = 0; i < num_side_channel_elements; i++) {
|
||||
// side_element_is_cpe[i] 1
|
||||
// side_element_tag_select[i] 4
|
||||
// }
|
||||
// for (i = 0; i < num_back_channel_elements; i++) {
|
||||
// back_element_is_cpe[i] 1
|
||||
// back_element_tag_select[i] 4
|
||||
// }
|
||||
// for (i = 0; i < num_lfe_channel_elements; i++) {
|
||||
// lfe_element_tag_select[i] 4
|
||||
// }
|
||||
// for (i = 0; i < num_assoc_data_elements; i++) {
|
||||
// assoc_data_element_tag_select[i] 4
|
||||
// }
|
||||
// for (i = 0; i < num_valid_cc_elements; i++) {
|
||||
// cc_element_is_ind_sw[i] 1
|
||||
// valid_cc_element_tag_select[i] 4
|
||||
// }
|
||||
// byte_alignment() VAR
|
||||
// comment_field_bytes 8
|
||||
// for (i = 0; i < comment_field_bytes; i++) {
|
||||
// comment_field_data[i] 8
|
||||
// }
|
||||
|
||||
if (!$info['aac']['header']['is_vbr']) {
|
||||
$info['aac']['program_configs'][$i]['buffer_fullness'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 20));
|
||||
$bitoffset += 20;
|
||||
}
|
||||
$info['aac']['program_configs'][$i]['element_instance_tag'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
$info['aac']['program_configs'][$i]['object_type'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
|
||||
$bitoffset += 2;
|
||||
$info['aac']['program_configs'][$i]['sampling_frequency_index'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
$info['aac']['program_configs'][$i]['num_front_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
$info['aac']['program_configs'][$i]['num_side_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
$info['aac']['program_configs'][$i]['num_back_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
$info['aac']['program_configs'][$i]['num_lfe_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
|
||||
$bitoffset += 2;
|
||||
$info['aac']['program_configs'][$i]['num_assoc_data_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 3));
|
||||
$bitoffset += 3;
|
||||
$info['aac']['program_configs'][$i]['num_valid_cc_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
$info['aac']['program_configs'][$i]['mono_mixdown_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
if ($info['aac']['program_configs'][$i]['mono_mixdown_present']) {
|
||||
$info['aac']['program_configs'][$i]['mono_mixdown_element_number'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
}
|
||||
$info['aac']['program_configs'][$i]['stereo_mixdown_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
if ($info['aac']['program_configs'][$i]['stereo_mixdown_present']) {
|
||||
$info['aac']['program_configs'][$i]['stereo_mixdown_element_number'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
}
|
||||
$info['aac']['program_configs'][$i]['matrix_mixdown_idx_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
if ($info['aac']['program_configs'][$i]['matrix_mixdown_idx_present']) {
|
||||
$info['aac']['program_configs'][$i]['matrix_mixdown_idx'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
|
||||
$bitoffset += 2;
|
||||
$info['aac']['program_configs'][$i]['pseudo_surround_enable'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
}
|
||||
for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_front_channel_elements']; $j++) {
|
||||
$info['aac']['program_configs'][$i]['front_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
$info['aac']['program_configs'][$i]['front_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
}
|
||||
for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_side_channel_elements']; $j++) {
|
||||
$info['aac']['program_configs'][$i]['side_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
$info['aac']['program_configs'][$i]['side_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
}
|
||||
for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_back_channel_elements']; $j++) {
|
||||
$info['aac']['program_configs'][$i]['back_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
$info['aac']['program_configs'][$i]['back_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
}
|
||||
for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_lfe_channel_elements']; $j++) {
|
||||
$info['aac']['program_configs'][$i]['lfe_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
}
|
||||
for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_assoc_data_elements']; $j++) {
|
||||
$info['aac']['program_configs'][$i]['assoc_data_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
}
|
||||
for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_valid_cc_elements']; $j++) {
|
||||
$info['aac']['program_configs'][$i]['cc_element_is_ind_sw'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
|
||||
$bitoffset += 1;
|
||||
$info['aac']['program_configs'][$i]['valid_cc_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
$bitoffset += 4;
|
||||
}
|
||||
|
||||
$bitoffset = ceil($bitoffset / 8) * 8;
|
||||
|
||||
$info['aac']['program_configs'][$i]['comment_field_bytes'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 8));
|
||||
$bitoffset += 8;
|
||||
$info['aac']['program_configs'][$i]['comment_field'] = getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 8 * $info['aac']['program_configs'][$i]['comment_field_bytes']));
|
||||
$bitoffset += 8 * $info['aac']['program_configs'][$i]['comment_field_bytes'];
|
||||
|
||||
|
||||
$info['aac']['header']['profile'] = self::AACprofileLookup($info['aac']['program_configs'][$i]['object_type'], $info['aac']['header']['mpeg_version']);
|
||||
$info['aac']['program_configs'][$i]['sampling_frequency'] = self::AACsampleRateLookup($info['aac']['program_configs'][$i]['sampling_frequency_index']);
|
||||
$info['audio']['sample_rate'] = $info['aac']['program_configs'][$i]['sampling_frequency'];
|
||||
$info['audio']['channels'] = self::AACchannelCountCalculate($info['aac']['program_configs'][$i]);
|
||||
if ($info['aac']['program_configs'][$i]['comment_field']) {
|
||||
$info['aac']['comments'][] = $info['aac']['program_configs'][$i]['comment_field'];
|
||||
}
|
||||
}
|
||||
$info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate'];
|
||||
|
||||
$info['audio']['encoder_options'] = $info['aac']['header_type'].' '.$info['aac']['header']['profile'];
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
unset($info['fileformat']);
|
||||
unset($info['aac']);
|
||||
$this->error('AAC-ADIF synch not found at offset '.$info['avdataoffset'].' (expected "ADIF", found "'.substr($AACheader, 0, 4).'" instead)');
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $MaxFramesToScan
|
||||
* @param bool $ReturnExtendedInfo
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getAACADTSheaderFilepointer($MaxFramesToScan=1000000, $ReturnExtendedInfo=false) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// based loosely on code from AACfile by Jurgen Faul <jfaulØgmx.de>
|
||||
// http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html
|
||||
|
||||
|
||||
// http://faac.sourceforge.net/wiki/index.php?page=ADTS // dead link
|
||||
// http://wiki.multimedia.cx/index.php?title=ADTS
|
||||
|
||||
// * ADTS Fixed Header: these don't change from frame to frame
|
||||
// syncword 12 always: '111111111111'
|
||||
// ID 1 0: MPEG-4, 1: MPEG-2
|
||||
// MPEG layer 2 If you send AAC in MPEG-TS, set to 0
|
||||
// protection_absent 1 0: CRC present; 1: no CRC
|
||||
// profile 2 0: AAC Main; 1: AAC LC (Low Complexity); 2: AAC SSR (Scalable Sample Rate); 3: AAC LTP (Long Term Prediction)
|
||||
// sampling_frequency_index 4 15 not allowed
|
||||
// private_bit 1 usually 0
|
||||
// channel_configuration 3
|
||||
// original/copy 1 0: original; 1: copy
|
||||
// home 1 usually 0
|
||||
// emphasis 2 only if ID == 0 (ie MPEG-4) // not present in some documentation?
|
||||
|
||||
// * ADTS Variable Header: these can change from frame to frame
|
||||
// copyright_identification_bit 1
|
||||
// copyright_identification_start 1
|
||||
// aac_frame_length 13 length of the frame including header (in bytes)
|
||||
// adts_buffer_fullness 11 0x7FF indicates VBR
|
||||
// no_raw_data_blocks_in_frame 2
|
||||
|
||||
// * ADTS Error check
|
||||
// crc_check 16 only if protection_absent == 0
|
||||
|
||||
$byteoffset = $info['avdataoffset'];
|
||||
$framenumber = 0;
|
||||
|
||||
// Init bit pattern array
|
||||
static $decbin = array();
|
||||
|
||||
// Populate $bindec
|
||||
for ($i = 0; $i < 256; $i++) {
|
||||
$decbin[chr($i)] = str_pad(decbin($i), 8, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
// used to calculate bitrate below
|
||||
$BitrateCache = array();
|
||||
|
||||
|
||||
while (true) {
|
||||
// breaks out when end-of-file encountered, or invalid data found,
|
||||
// or MaxFramesToScan frames have been scanned
|
||||
|
||||
if (!getid3_lib::intValueSupported($byteoffset)) {
|
||||
$this->warning('Unable to parse AAC file beyond '.$this->ftell().' (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)');
|
||||
return false;
|
||||
}
|
||||
$this->fseek($byteoffset);
|
||||
|
||||
// First get substring
|
||||
$substring = $this->fread(9); // header is 7 bytes (or 9 if CRC is present)
|
||||
$substringlength = strlen($substring);
|
||||
if ($substringlength != 9) {
|
||||
$this->error('Failed to read 7 bytes at offset '.($this->ftell() - $substringlength).' (only read '.$substringlength.' bytes)');
|
||||
return false;
|
||||
}
|
||||
// this would be easier with 64-bit math, but split it up to allow for 32-bit:
|
||||
$header1 = getid3_lib::BigEndian2Int(substr($substring, 0, 2));
|
||||
$header2 = getid3_lib::BigEndian2Int(substr($substring, 2, 4));
|
||||
$header3 = getid3_lib::BigEndian2Int(substr($substring, 6, 1));
|
||||
|
||||
$info['aac']['header']['raw']['syncword'] = ($header1 & 0xFFF0) >> 4;
|
||||
if ($info['aac']['header']['raw']['syncword'] != 0x0FFF) {
|
||||
$this->error('Synch pattern (0x0FFF) not found at offset '.($this->ftell() - $substringlength).' (found 0x0'.strtoupper(dechex($info['aac']['header']['raw']['syncword'])).' instead)');
|
||||
//if ($info['fileformat'] == 'aac') {
|
||||
// return true;
|
||||
//}
|
||||
unset($info['aac']);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Gather info for first frame only - this takes time to do 1000 times!
|
||||
if ($framenumber == 0) {
|
||||
$info['aac']['header_type'] = 'ADTS';
|
||||
$info['fileformat'] = 'aac';
|
||||
$info['audio']['dataformat'] = 'aac';
|
||||
|
||||
$info['aac']['header']['raw']['mpeg_version'] = ($header1 & 0x0008) >> 3;
|
||||
$info['aac']['header']['raw']['mpeg_layer'] = ($header1 & 0x0006) >> 1;
|
||||
$info['aac']['header']['raw']['protection_absent'] = ($header1 & 0x0001) >> 0;
|
||||
|
||||
$info['aac']['header']['raw']['profile_code'] = ($header2 & 0xC0000000) >> 30;
|
||||
$info['aac']['header']['raw']['sample_rate_code'] = ($header2 & 0x3C000000) >> 26;
|
||||
$info['aac']['header']['raw']['private_stream'] = ($header2 & 0x02000000) >> 25;
|
||||
$info['aac']['header']['raw']['channels_code'] = ($header2 & 0x01C00000) >> 22;
|
||||
$info['aac']['header']['raw']['original'] = ($header2 & 0x00200000) >> 21;
|
||||
$info['aac']['header']['raw']['home'] = ($header2 & 0x00100000) >> 20;
|
||||
$info['aac']['header']['raw']['copyright_stream'] = ($header2 & 0x00080000) >> 19;
|
||||
$info['aac']['header']['raw']['copyright_start'] = ($header2 & 0x00040000) >> 18;
|
||||
$info['aac']['header']['raw']['frame_length'] = ($header2 & 0x0003FFE0) >> 5;
|
||||
|
||||
$info['aac']['header']['mpeg_version'] = ($info['aac']['header']['raw']['mpeg_version'] ? 2 : 4);
|
||||
$info['aac']['header']['crc_present'] = ($info['aac']['header']['raw']['protection_absent'] ? false: true);
|
||||
$info['aac']['header']['profile'] = self::AACprofileLookup($info['aac']['header']['raw']['profile_code'], $info['aac']['header']['mpeg_version']);
|
||||
$info['aac']['header']['sample_frequency'] = self::AACsampleRateLookup($info['aac']['header']['raw']['sample_rate_code']);
|
||||
$info['aac']['header']['private'] = (bool) $info['aac']['header']['raw']['private_stream'];
|
||||
$info['aac']['header']['original'] = (bool) $info['aac']['header']['raw']['original'];
|
||||
$info['aac']['header']['home'] = (bool) $info['aac']['header']['raw']['home'];
|
||||
$info['aac']['header']['channels'] = (($info['aac']['header']['raw']['channels_code'] == 7) ? 8 : $info['aac']['header']['raw']['channels_code']);
|
||||
if ($ReturnExtendedInfo) {
|
||||
$info['aac'][$framenumber]['copyright_id_bit'] = (bool) $info['aac']['header']['raw']['copyright_stream'];
|
||||
$info['aac'][$framenumber]['copyright_id_start'] = (bool) $info['aac']['header']['raw']['copyright_start'];
|
||||
}
|
||||
|
||||
if ($info['aac']['header']['raw']['mpeg_layer'] != 0) {
|
||||
$this->warning('Layer error - expected "0", found "'.$info['aac']['header']['raw']['mpeg_layer'].'" instead');
|
||||
}
|
||||
if ($info['aac']['header']['sample_frequency'] == 0) {
|
||||
$this->error('Corrupt AAC file: sample_frequency == zero');
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['audio']['sample_rate'] = $info['aac']['header']['sample_frequency'];
|
||||
$info['audio']['channels'] = $info['aac']['header']['channels'];
|
||||
}
|
||||
|
||||
$FrameLength = ($header2 & 0x0003FFE0) >> 5;
|
||||
|
||||
if (!isset($BitrateCache[$FrameLength])) {
|
||||
$BitrateCache[$FrameLength] = ($info['aac']['header']['sample_frequency'] / 1024) * $FrameLength * 8;
|
||||
}
|
||||
getid3_lib::safe_inc($info['aac']['bitrate_distribution'][(string)$BitrateCache[$FrameLength]], 1);
|
||||
|
||||
$info['aac'][$framenumber]['aac_frame_length'] = $FrameLength;
|
||||
|
||||
$info['aac'][$framenumber]['adts_buffer_fullness'] = (($header2 & 0x0000001F) << 6) & (($header3 & 0xFC) >> 2);
|
||||
if ($info['aac'][$framenumber]['adts_buffer_fullness'] == 0x07FF) {
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
} else {
|
||||
$info['audio']['bitrate_mode'] = 'cbr';
|
||||
}
|
||||
$info['aac'][$framenumber]['num_raw_data_blocks'] = (($header3 & 0x03) >> 0);
|
||||
|
||||
if ($info['aac']['header']['crc_present']) {
|
||||
//$info['aac'][$framenumber]['crc'] = getid3_lib::BigEndian2Int(substr($substring, 7, 2);
|
||||
}
|
||||
|
||||
if (!$ReturnExtendedInfo) {
|
||||
unset($info['aac'][$framenumber]);
|
||||
}
|
||||
|
||||
/*
|
||||
$rounded_precision = 5000;
|
||||
$info['aac']['bitrate_distribution_rounded'] = array();
|
||||
foreach ($info['aac']['bitrate_distribution'] as $bitrate => $count) {
|
||||
$rounded_bitrate = round($bitrate / $rounded_precision) * $rounded_precision;
|
||||
getid3_lib::safe_inc($info['aac']['bitrate_distribution_rounded'][$rounded_bitrate], $count);
|
||||
}
|
||||
ksort($info['aac']['bitrate_distribution_rounded']);
|
||||
*/
|
||||
|
||||
$byteoffset += $FrameLength;
|
||||
if ((++$framenumber < $MaxFramesToScan) && (($byteoffset + 10) < $info['avdataend'])) {
|
||||
|
||||
// keep scanning
|
||||
|
||||
} else {
|
||||
|
||||
$info['aac']['frames'] = $framenumber;
|
||||
$info['playtime_seconds'] = ($info['avdataend'] / $byteoffset) * (($framenumber * 1024) / $info['aac']['header']['sample_frequency']); // (1 / % of file scanned) * (samples / (samples/sec)) = seconds
|
||||
if ($info['playtime_seconds'] == 0) {
|
||||
$this->error('Corrupt AAC file: playtime_seconds == zero');
|
||||
return false;
|
||||
}
|
||||
$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
ksort($info['aac']['bitrate_distribution']);
|
||||
|
||||
$info['audio']['encoder_options'] = $info['aac']['header_type'].' '.$info['aac']['header']['profile'];
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
// should never get here.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $samplerateid
|
||||
*
|
||||
* @return int|string
|
||||
*/
|
||||
public static function AACsampleRateLookup($samplerateid) {
|
||||
static $AACsampleRateLookup = array();
|
||||
if (empty($AACsampleRateLookup)) {
|
||||
$AACsampleRateLookup[0] = 96000;
|
||||
$AACsampleRateLookup[1] = 88200;
|
||||
$AACsampleRateLookup[2] = 64000;
|
||||
$AACsampleRateLookup[3] = 48000;
|
||||
$AACsampleRateLookup[4] = 44100;
|
||||
$AACsampleRateLookup[5] = 32000;
|
||||
$AACsampleRateLookup[6] = 24000;
|
||||
$AACsampleRateLookup[7] = 22050;
|
||||
$AACsampleRateLookup[8] = 16000;
|
||||
$AACsampleRateLookup[9] = 12000;
|
||||
$AACsampleRateLookup[10] = 11025;
|
||||
$AACsampleRateLookup[11] = 8000;
|
||||
$AACsampleRateLookup[12] = 0;
|
||||
$AACsampleRateLookup[13] = 0;
|
||||
$AACsampleRateLookup[14] = 0;
|
||||
$AACsampleRateLookup[15] = 0;
|
||||
}
|
||||
return (isset($AACsampleRateLookup[$samplerateid]) ? $AACsampleRateLookup[$samplerateid] : 'invalid');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $profileid
|
||||
* @param int $mpegversion
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function AACprofileLookup($profileid, $mpegversion) {
|
||||
static $AACprofileLookup = array();
|
||||
if (empty($AACprofileLookup)) {
|
||||
$AACprofileLookup[2][0] = 'Main profile';
|
||||
$AACprofileLookup[2][1] = 'Low Complexity profile (LC)';
|
||||
$AACprofileLookup[2][2] = 'Scalable Sample Rate profile (SSR)';
|
||||
$AACprofileLookup[2][3] = '(reserved)';
|
||||
$AACprofileLookup[4][0] = 'AAC_MAIN';
|
||||
$AACprofileLookup[4][1] = 'AAC_LC';
|
||||
$AACprofileLookup[4][2] = 'AAC_SSR';
|
||||
$AACprofileLookup[4][3] = 'AAC_LTP';
|
||||
}
|
||||
return (isset($AACprofileLookup[$mpegversion][$profileid]) ? $AACprofileLookup[$mpegversion][$profileid] : 'invalid');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $program_configs
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function AACchannelCountCalculate($program_configs) {
|
||||
$channels = 0;
|
||||
for ($i = 0; $i < $program_configs['num_front_channel_elements']; $i++) {
|
||||
$channels++;
|
||||
if ($program_configs['front_element_is_cpe'][$i]) {
|
||||
// each front element is channel pair (CPE = Channel Pair Element)
|
||||
$channels++;
|
||||
}
|
||||
}
|
||||
for ($i = 0; $i < $program_configs['num_side_channel_elements']; $i++) {
|
||||
$channels++;
|
||||
if ($program_configs['side_element_is_cpe'][$i]) {
|
||||
// each side element is channel pair (CPE = Channel Pair Element)
|
||||
$channels++;
|
||||
}
|
||||
}
|
||||
for ($i = 0; $i < $program_configs['num_back_channel_elements']; $i++) {
|
||||
$channels++;
|
||||
if ($program_configs['back_element_is_cpe'][$i]) {
|
||||
// each back element is channel pair (CPE = Channel Pair Element)
|
||||
$channels++;
|
||||
}
|
||||
}
|
||||
for ($i = 0; $i < $program_configs['num_lfe_channel_elements']; $i++) {
|
||||
$channels++;
|
||||
}
|
||||
return $channels;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,823 @@
|
|||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at https://github.com/JamesHeinrich/getID3 //
|
||||
// or https://www.getid3.org //
|
||||
// or http://getid3.sourceforge.net //
|
||||
// see readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.ac3.php //
|
||||
// module for analyzing AC-3 (aka Dolby Digital) audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
|
||||
exit;
|
||||
}
|
||||
|
||||
class getid3_ac3 extends getid3_handler
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $AC3header = array();
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $BSIoffset = 0;
|
||||
|
||||
const syncword = 0x0B77;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
///AH
|
||||
$info['ac3']['raw']['bsi'] = array();
|
||||
$thisfile_ac3 = &$info['ac3'];
|
||||
$thisfile_ac3_raw = &$thisfile_ac3['raw'];
|
||||
$thisfile_ac3_raw_bsi = &$thisfile_ac3_raw['bsi'];
|
||||
|
||||
|
||||
// http://www.atsc.org/standards/a_52a.pdf
|
||||
|
||||
$info['fileformat'] = 'ac3';
|
||||
|
||||
// An AC-3 serial coded audio bit stream is made up of a sequence of synchronization frames
|
||||
// Each synchronization frame contains 6 coded audio blocks (AB), each of which represent 256
|
||||
// new audio samples per channel. A synchronization information (SI) header at the beginning
|
||||
// of each frame contains information needed to acquire and maintain synchronization. A
|
||||
// bit stream information (BSI) header follows SI, and contains parameters describing the coded
|
||||
// audio service. The coded audio blocks may be followed by an auxiliary data (Aux) field. At the
|
||||
// end of each frame is an error check field that includes a CRC word for error detection. An
|
||||
// additional CRC word is located in the SI header, the use of which, by a decoder, is optional.
|
||||
//
|
||||
// syncinfo() | bsi() | AB0 | AB1 | AB2 | AB3 | AB4 | AB5 | Aux | CRC
|
||||
|
||||
// syncinfo() {
|
||||
// syncword 16
|
||||
// crc1 16
|
||||
// fscod 2
|
||||
// frmsizecod 6
|
||||
// } /* end of syncinfo */
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$tempAC3header = $this->fread(100); // should be enough to cover all data, there are some variable-length fields...?
|
||||
$this->AC3header['syncinfo'] = getid3_lib::BigEndian2Int(substr($tempAC3header, 0, 2));
|
||||
$this->AC3header['bsi'] = getid3_lib::BigEndian2Bin(substr($tempAC3header, 2));
|
||||
$thisfile_ac3_raw_bsi['bsid'] = (getid3_lib::LittleEndian2Int(substr($tempAC3header, 5, 1)) & 0xF8) >> 3; // AC3 and E-AC3 put the "bsid" version identifier in the same place, but unfortnately the 4 bytes between the syncword and the version identifier are interpreted differently, so grab it here so the following code structure can make sense
|
||||
unset($tempAC3header);
|
||||
|
||||
if ($this->AC3header['syncinfo'] !== self::syncword) {
|
||||
if (!$this->isDependencyFor('matroska')) {
|
||||
unset($info['fileformat'], $info['ac3']);
|
||||
return $this->error('Expecting "'.dechex(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.dechex($this->AC3header['syncinfo']).'"');
|
||||
}
|
||||
}
|
||||
|
||||
$info['audio']['dataformat'] = 'ac3';
|
||||
$info['audio']['bitrate_mode'] = 'cbr';
|
||||
$info['audio']['lossless'] = false;
|
||||
|
||||
if ($thisfile_ac3_raw_bsi['bsid'] <= 8) {
|
||||
|
||||
$thisfile_ac3_raw_bsi['crc1'] = getid3_lib::Bin2Dec($this->readHeaderBSI(16));
|
||||
$thisfile_ac3_raw_bsi['fscod'] = $this->readHeaderBSI(2); // 5.4.1.3
|
||||
$thisfile_ac3_raw_bsi['frmsizecod'] = $this->readHeaderBSI(6); // 5.4.1.4
|
||||
if ($thisfile_ac3_raw_bsi['frmsizecod'] > 37) { // binary: 100101 - see Table 5.18 Frame Size Code Table (1 word = 16 bits)
|
||||
$this->warning('Unexpected ac3.bsi.frmsizecod value: '.$thisfile_ac3_raw_bsi['frmsizecod'].', bitrate not set correctly');
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5); // we already know this from pre-parsing the version identifier, but re-read it to let the bitstream flow as intended
|
||||
$thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3);
|
||||
$thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3);
|
||||
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] & 0x01) {
|
||||
// If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream.
|
||||
$thisfile_ac3_raw_bsi['cmixlev'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3['center_mix_level'] = self::centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']);
|
||||
}
|
||||
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) {
|
||||
// If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream.
|
||||
$thisfile_ac3_raw_bsi['surmixlev'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3['surround_mix_level'] = self::surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']);
|
||||
}
|
||||
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] == 0x02) {
|
||||
// When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround.
|
||||
$thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3['dolby_surround_mode'] = self::dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['lfeon'] = (bool) $this->readHeaderBSI(1);
|
||||
|
||||
// This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31.
|
||||
// The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
|
||||
$thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5); // 5.4.2.8 dialnorm: Dialogue Normalization, 5 Bits
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['compr'] = (bool) $this->readHeaderBSI(1); // 5.4.2.9 compre: Compression Gain Word Exists, 1 Bit
|
||||
if ($thisfile_ac3_raw_bsi['flags']['compr']) {
|
||||
$thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8); // 5.4.2.10 compr: Compression Gain Word, 8 Bits
|
||||
$thisfile_ac3['heavy_compression'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr']);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['langcod'] = (bool) $this->readHeaderBSI(1); // 5.4.2.11 langcode: Language Code Exists, 1 Bit
|
||||
if ($thisfile_ac3_raw_bsi['flags']['langcod']) {
|
||||
$thisfile_ac3_raw_bsi['langcod'] = $this->readHeaderBSI(8); // 5.4.2.12 langcod: Language Code, 8 Bits
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['audprodinfo'] = (bool) $this->readHeaderBSI(1); // 5.4.2.13 audprodie: Audio Production Information Exists, 1 Bit
|
||||
if ($thisfile_ac3_raw_bsi['flags']['audprodinfo']) {
|
||||
$thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5); // 5.4.2.14 mixlevel: Mixing Level, 5 Bits
|
||||
$thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2); // 5.4.2.15 roomtyp: Room Type, 2 Bits
|
||||
|
||||
$thisfile_ac3['mixing_level'] = (80 + $thisfile_ac3_raw_bsi['mixlevel']).'dB';
|
||||
$thisfile_ac3['room_type'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp']);
|
||||
}
|
||||
|
||||
|
||||
$thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5); // 5.4.2.16 dialnorm2: Dialogue Normalization, ch2, 5 Bits
|
||||
$thisfile_ac3['dialogue_normalization2'] = '-'.$thisfile_ac3_raw_bsi['dialnorm2'].'dB'; // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31. The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['compr2'] = (bool) $this->readHeaderBSI(1); // 5.4.2.17 compr2e: Compression Gain Word Exists, ch2, 1 Bit
|
||||
if ($thisfile_ac3_raw_bsi['flags']['compr2']) {
|
||||
$thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8); // 5.4.2.18 compr2: Compression Gain Word, ch2, 8 Bits
|
||||
$thisfile_ac3['heavy_compression2'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr2']);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['langcod2'] = (bool) $this->readHeaderBSI(1); // 5.4.2.19 langcod2e: Language Code Exists, ch2, 1 Bit
|
||||
if ($thisfile_ac3_raw_bsi['flags']['langcod2']) {
|
||||
$thisfile_ac3_raw_bsi['langcod2'] = $this->readHeaderBSI(8); // 5.4.2.20 langcod2: Language Code, ch2, 8 Bits
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['audprodinfo2'] = (bool) $this->readHeaderBSI(1); // 5.4.2.21 audprodi2e: Audio Production Information Exists, ch2, 1 Bit
|
||||
if ($thisfile_ac3_raw_bsi['flags']['audprodinfo2']) {
|
||||
$thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5); // 5.4.2.22 mixlevel2: Mixing Level, ch2, 5 Bits
|
||||
$thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2); // 5.4.2.23 roomtyp2: Room Type, ch2, 2 Bits
|
||||
|
||||
$thisfile_ac3['mixing_level2'] = (80 + $thisfile_ac3_raw_bsi['mixlevel2']).'dB';
|
||||
$thisfile_ac3['room_type2'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp2']);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['copyright'] = (bool) $this->readHeaderBSI(1); // 5.4.2.24 copyrightb: Copyright Bit, 1 Bit
|
||||
|
||||
$thisfile_ac3_raw_bsi['original'] = (bool) $this->readHeaderBSI(1); // 5.4.2.25 origbs: Original Bit Stream, 1 Bit
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['timecod1'] = $this->readHeaderBSI(2); // 5.4.2.26 timecod1e, timcode2e: Time Code (first and second) Halves Exist, 2 Bits
|
||||
if ($thisfile_ac3_raw_bsi['flags']['timecod1'] & 0x01) {
|
||||
$thisfile_ac3_raw_bsi['timecod1'] = $this->readHeaderBSI(14); // 5.4.2.27 timecod1: Time code first half, 14 bits
|
||||
$thisfile_ac3['timecode1'] = 0;
|
||||
$thisfile_ac3['timecode1'] += (($thisfile_ac3_raw_bsi['timecod1'] & 0x3E00) >> 9) * 3600; // The first 5 bits of this 14-bit field represent the time in hours, with valid values of 0<>23
|
||||
$thisfile_ac3['timecode1'] += (($thisfile_ac3_raw_bsi['timecod1'] & 0x01F8) >> 3) * 60; // The next 6 bits represent the time in minutes, with valid values of 0<>59
|
||||
$thisfile_ac3['timecode1'] += (($thisfile_ac3_raw_bsi['timecod1'] & 0x0003) >> 0) * 8; // The final 3 bits represents the time in 8 second increments, with valid values of 0<>7 (representing 0, 8, 16, ... 56 seconds)
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['flags']['timecod1'] & 0x02) {
|
||||
$thisfile_ac3_raw_bsi['timecod2'] = $this->readHeaderBSI(14); // 5.4.2.28 timecod2: Time code second half, 14 bits
|
||||
$thisfile_ac3['timecode2'] = 0;
|
||||
$thisfile_ac3['timecode2'] += (($thisfile_ac3_raw_bsi['timecod2'] & 0x3800) >> 11) * 1; // The first 3 bits of this 14-bit field represent the time in seconds, with valid values from 0<>7 (representing 0-7 seconds)
|
||||
$thisfile_ac3['timecode2'] += (($thisfile_ac3_raw_bsi['timecod2'] & 0x07C0) >> 6) * (1 / 30); // The next 5 bits represents the time in frames, with valid values from 0<>29 (one frame = 1/30th of a second)
|
||||
$thisfile_ac3['timecode2'] += (($thisfile_ac3_raw_bsi['timecod2'] & 0x003F) >> 0) * ((1 / 30) / 60); // The final 6 bits represents fractions of 1/64 of a frame, with valid values from 0<>63
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['addbsi'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['addbsi']) {
|
||||
$thisfile_ac3_raw_bsi['addbsi_length'] = $this->readHeaderBSI(6) + 1; // This 6-bit code, which exists only if addbside is a 1, indicates the length in bytes of additional bit stream information. The valid range of addbsil is 0<>63, indicating 1<>64 additional bytes, respectively.
|
||||
|
||||
$this->AC3header['bsi'] .= getid3_lib::BigEndian2Bin($this->fread($thisfile_ac3_raw_bsi['addbsi_length']));
|
||||
|
||||
$thisfile_ac3_raw_bsi['addbsi_data'] = substr($this->AC3header['bsi'], $this->BSIoffset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8);
|
||||
$this->BSIoffset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8;
|
||||
}
|
||||
|
||||
|
||||
} elseif ($thisfile_ac3_raw_bsi['bsid'] <= 16) { // E-AC3
|
||||
|
||||
|
||||
$this->error('E-AC3 parsing is incomplete and experimental in this version of getID3 ('.$this->getid3->version().'). Notably the bitrate calculations are wrong -- value might (or not) be correct, but it is not calculated correctly. Email info@getid3.org if you know how to calculate EAC3 bitrate correctly.');
|
||||
$info['audio']['dataformat'] = 'eac3';
|
||||
|
||||
$thisfile_ac3_raw_bsi['strmtyp'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3_raw_bsi['substreamid'] = $this->readHeaderBSI(3);
|
||||
$thisfile_ac3_raw_bsi['frmsiz'] = $this->readHeaderBSI(11);
|
||||
$thisfile_ac3_raw_bsi['fscod'] = $this->readHeaderBSI(2);
|
||||
if ($thisfile_ac3_raw_bsi['fscod'] == 3) {
|
||||
$thisfile_ac3_raw_bsi['fscod2'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3_raw_bsi['numblkscod'] = 3; // six blocks per syncframe
|
||||
} else {
|
||||
$thisfile_ac3_raw_bsi['numblkscod'] = $this->readHeaderBSI(2);
|
||||
}
|
||||
$thisfile_ac3['bsi']['blocks_per_sync_frame'] = self::blocksPerSyncFrame($thisfile_ac3_raw_bsi['numblkscod']);
|
||||
$thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3);
|
||||
$thisfile_ac3_raw_bsi['flags']['lfeon'] = (bool) $this->readHeaderBSI(1);
|
||||
$thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5); // we already know this from pre-parsing the version identifier, but re-read it to let the bitstream flow as intended
|
||||
$thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5);
|
||||
$thisfile_ac3_raw_bsi['flags']['compr'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['compr']) {
|
||||
$thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] == 0) { // if 1+1 mode (dual mono, so some items need a second value)
|
||||
$thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5);
|
||||
$thisfile_ac3_raw_bsi['flags']['compr2'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['compr2']) {
|
||||
$thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8);
|
||||
}
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['strmtyp'] == 1) { // if dependent stream
|
||||
$thisfile_ac3_raw_bsi['flags']['chanmap'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['chanmap']) {
|
||||
$thisfile_ac3_raw_bsi['chanmap'] = $this->readHeaderBSI(8);
|
||||
}
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['mixmdat'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['mixmdat']) { // Mixing metadata
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] > 2) { // if more than 2 channels
|
||||
$thisfile_ac3_raw_bsi['dmixmod'] = $this->readHeaderBSI(2);
|
||||
}
|
||||
if (($thisfile_ac3_raw_bsi['acmod'] & 0x01) && ($thisfile_ac3_raw_bsi['acmod'] > 2)) { // if three front channels exist
|
||||
$thisfile_ac3_raw_bsi['ltrtcmixlev'] = $this->readHeaderBSI(3);
|
||||
$thisfile_ac3_raw_bsi['lorocmixlev'] = $this->readHeaderBSI(3);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) { // if a surround channel exists
|
||||
$thisfile_ac3_raw_bsi['ltrtsurmixlev'] = $this->readHeaderBSI(3);
|
||||
$thisfile_ac3_raw_bsi['lorosurmixlev'] = $this->readHeaderBSI(3);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['flags']['lfeon']) { // if the LFE channel exists
|
||||
$thisfile_ac3_raw_bsi['flags']['lfemixlevcod'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['lfemixlevcod']) {
|
||||
$thisfile_ac3_raw_bsi['lfemixlevcod'] = $this->readHeaderBSI(5);
|
||||
}
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['strmtyp'] == 0) { // if independent stream
|
||||
$thisfile_ac3_raw_bsi['flags']['pgmscl'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['pgmscl']) {
|
||||
$thisfile_ac3_raw_bsi['pgmscl'] = $this->readHeaderBSI(6);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] == 0) { // if 1+1 mode (dual mono, so some items need a second value)
|
||||
$thisfile_ac3_raw_bsi['flags']['pgmscl2'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['pgmscl2']) {
|
||||
$thisfile_ac3_raw_bsi['pgmscl2'] = $this->readHeaderBSI(6);
|
||||
}
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmscl'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmscl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmscl'] = $this->readHeaderBSI(6);
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['mixdef'] = $this->readHeaderBSI(2);
|
||||
if ($thisfile_ac3_raw_bsi['mixdef'] == 1) { // mixing option 2
|
||||
$thisfile_ac3_raw_bsi['premixcmpsel'] = (bool) $this->readHeaderBSI(1);
|
||||
$thisfile_ac3_raw_bsi['drcsrc'] = (bool) $this->readHeaderBSI(1);
|
||||
$thisfile_ac3_raw_bsi['premixcmpscl'] = $this->readHeaderBSI(3);
|
||||
} elseif ($thisfile_ac3_raw_bsi['mixdef'] == 2) { // mixing option 3
|
||||
$thisfile_ac3_raw_bsi['mixdata'] = $this->readHeaderBSI(12);
|
||||
} elseif ($thisfile_ac3_raw_bsi['mixdef'] == 3) { // mixing option 4
|
||||
$mixdefbitsread = 0;
|
||||
$thisfile_ac3_raw_bsi['mixdeflen'] = $this->readHeaderBSI(5); $mixdefbitsread += 5;
|
||||
$thisfile_ac3_raw_bsi['flags']['mixdata2'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['mixdata2']) {
|
||||
$thisfile_ac3_raw_bsi['premixcmpsel'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
$thisfile_ac3_raw_bsi['drcsrc'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
$thisfile_ac3_raw_bsi['premixcmpscl'] = $this->readHeaderBSI(3); $mixdefbitsread += 3;
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmlscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmlscl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmlscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmcscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmcscl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmcscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmrscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmrscl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmrscl'] = $this->readHeaderBSI(4);
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmlsscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmlsscl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmlsscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmrsscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmrsscl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmrsscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmlfescl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmlfescl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmlfescl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['dmixscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['dmixscl']) {
|
||||
$thisfile_ac3_raw_bsi['dmixscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['addch'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['addch']) {
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmaux1scl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmaux1scl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmaux1scl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmaux2scl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmaux2scl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmaux2scl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['mixdata3'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['mixdata3']) {
|
||||
$thisfile_ac3_raw_bsi['spchdat'] = $this->readHeaderBSI(5); $mixdefbitsread += 5;
|
||||
$thisfile_ac3_raw_bsi['flags']['addspchdat'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['addspchdat']) {
|
||||
$thisfile_ac3_raw_bsi['spchdat1'] = $this->readHeaderBSI(5); $mixdefbitsread += 5;
|
||||
$thisfile_ac3_raw_bsi['spchan1att'] = $this->readHeaderBSI(2); $mixdefbitsread += 2;
|
||||
$thisfile_ac3_raw_bsi['flags']['addspchdat1'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['addspchdat1']) {
|
||||
$thisfile_ac3_raw_bsi['spchdat2'] = $this->readHeaderBSI(5); $mixdefbitsread += 5;
|
||||
$thisfile_ac3_raw_bsi['spchan2att'] = $this->readHeaderBSI(3); $mixdefbitsread += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
$mixdata_bits = (8 * ($thisfile_ac3_raw_bsi['mixdeflen'] + 2)) - $mixdefbitsread;
|
||||
$mixdata_fill = (($mixdata_bits % 8) ? 8 - ($mixdata_bits % 8) : 0);
|
||||
$thisfile_ac3_raw_bsi['mixdata'] = $this->readHeaderBSI($mixdata_bits);
|
||||
$thisfile_ac3_raw_bsi['mixdatafill'] = $this->readHeaderBSI($mixdata_fill);
|
||||
unset($mixdefbitsread, $mixdata_bits, $mixdata_fill);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] < 2) { // if mono or dual mono source
|
||||
$thisfile_ac3_raw_bsi['flags']['paninfo'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['paninfo']) {
|
||||
$thisfile_ac3_raw_bsi['panmean'] = $this->readHeaderBSI(8);
|
||||
$thisfile_ac3_raw_bsi['paninfo'] = $this->readHeaderBSI(6);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] == 0) { // if 1+1 mode (dual mono, so some items need a second value)
|
||||
$thisfile_ac3_raw_bsi['flags']['paninfo2'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['paninfo2']) {
|
||||
$thisfile_ac3_raw_bsi['panmean2'] = $this->readHeaderBSI(8);
|
||||
$thisfile_ac3_raw_bsi['paninfo2'] = $this->readHeaderBSI(6);
|
||||
}
|
||||
}
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['frmmixcfginfo'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['frmmixcfginfo']) { // mixing configuration information
|
||||
if ($thisfile_ac3_raw_bsi['numblkscod'] == 0) {
|
||||
$thisfile_ac3_raw_bsi['blkmixcfginfo'][0] = $this->readHeaderBSI(5);
|
||||
} else {
|
||||
for ($blk = 0; $blk < $thisfile_ac3_raw_bsi['numblkscod']; $blk++) {
|
||||
$thisfile_ac3_raw_bsi['flags']['blkmixcfginfo'.$blk] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['blkmixcfginfo'.$blk]) { // mixing configuration information
|
||||
$thisfile_ac3_raw_bsi['blkmixcfginfo'][$blk] = $this->readHeaderBSI(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['infomdat'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['infomdat']) { // Informational metadata
|
||||
$thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3);
|
||||
$thisfile_ac3_raw_bsi['flags']['copyrightb'] = (bool) $this->readHeaderBSI(1);
|
||||
$thisfile_ac3_raw_bsi['flags']['origbs'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] == 2) { // if in 2/0 mode
|
||||
$thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3_raw_bsi['dheadphonmod'] = $this->readHeaderBSI(2);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] >= 6) { // if both surround channels exist
|
||||
$thisfile_ac3_raw_bsi['dsurexmod'] = $this->readHeaderBSI(2);
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['audprodi'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['audprodi']) {
|
||||
$thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5);
|
||||
$thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3_raw_bsi['flags']['adconvtyp'] = (bool) $this->readHeaderBSI(1);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] == 0) { // if 1+1 mode (dual mono, so some items need a second value)
|
||||
$thisfile_ac3_raw_bsi['flags']['audprodi2'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['audprodi2']) {
|
||||
$thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5);
|
||||
$thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3_raw_bsi['flags']['adconvtyp2'] = (bool) $this->readHeaderBSI(1);
|
||||
}
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['fscod'] < 3) { // if not half sample rate
|
||||
$thisfile_ac3_raw_bsi['flags']['sourcefscod'] = (bool) $this->readHeaderBSI(1);
|
||||
}
|
||||
}
|
||||
if (($thisfile_ac3_raw_bsi['strmtyp'] == 0) && ($thisfile_ac3_raw_bsi['numblkscod'] != 3)) { // if both surround channels exist
|
||||
$thisfile_ac3_raw_bsi['flags']['convsync'] = (bool) $this->readHeaderBSI(1);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['strmtyp'] == 2) { // if bit stream converted from AC-3
|
||||
if ($thisfile_ac3_raw_bsi['numblkscod'] != 3) { // 6 blocks per syncframe
|
||||
$thisfile_ac3_raw_bsi['flags']['blkid'] = 1;
|
||||
} else {
|
||||
$thisfile_ac3_raw_bsi['flags']['blkid'] = (bool) $this->readHeaderBSI(1);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['flags']['blkid']) {
|
||||
$thisfile_ac3_raw_bsi['frmsizecod'] = $this->readHeaderBSI(6);
|
||||
}
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['addbsi'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['addbsi']) {
|
||||
$thisfile_ac3_raw_bsi['addbsil'] = $this->readHeaderBSI(6);
|
||||
$thisfile_ac3_raw_bsi['addbsi'] = $this->readHeaderBSI(($thisfile_ac3_raw_bsi['addbsil'] + 1) * 8);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$this->error('Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 16. Please submit a support ticket with a sample file.');
|
||||
unset($info['ac3']);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
if (isset($thisfile_ac3_raw_bsi['fscod2'])) {
|
||||
$thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup2($thisfile_ac3_raw_bsi['fscod2']);
|
||||
} else {
|
||||
$thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup($thisfile_ac3_raw_bsi['fscod']);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['fscod'] <= 3) {
|
||||
$info['audio']['sample_rate'] = $thisfile_ac3['sample_rate'];
|
||||
} else {
|
||||
$this->warning('Unexpected ac3.bsi.fscod value: '.$thisfile_ac3_raw_bsi['fscod']);
|
||||
}
|
||||
if (isset($thisfile_ac3_raw_bsi['frmsizecod'])) {
|
||||
$thisfile_ac3['frame_length'] = self::frameSizeLookup($thisfile_ac3_raw_bsi['frmsizecod'], $thisfile_ac3_raw_bsi['fscod']);
|
||||
$thisfile_ac3['bitrate'] = self::bitrateLookup($thisfile_ac3_raw_bsi['frmsizecod']);
|
||||
} elseif (!empty($thisfile_ac3_raw_bsi['frmsiz'])) {
|
||||
// this isn't right, but it's (usually) close, roughly 5% less than it should be.
|
||||
// but WHERE is the actual bitrate value stored in EAC3?? email info@getid3.org if you know!
|
||||
$thisfile_ac3['bitrate'] = ($thisfile_ac3_raw_bsi['frmsiz'] + 1) * 16 * 30; // The frmsiz field shall contain a value one less than the overall size of the coded syncframe in 16-bit words. That is, this field may assume a value ranging from 0 to 2047, and these values correspond to syncframe sizes ranging from 1 to 2048.
|
||||
// kludge-fix to make it approximately the expected value, still not "right":
|
||||
$thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16000;
|
||||
}
|
||||
$info['audio']['bitrate'] = $thisfile_ac3['bitrate'];
|
||||
|
||||
if (isset($thisfile_ac3_raw_bsi['bsmod']) && isset($thisfile_ac3_raw_bsi['acmod'])) {
|
||||
$thisfile_ac3['service_type'] = self::serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']);
|
||||
}
|
||||
$ac3_coding_mode = self::audioCodingModeLookup($thisfile_ac3_raw_bsi['acmod']);
|
||||
foreach($ac3_coding_mode as $key => $value) {
|
||||
$thisfile_ac3[$key] = $value;
|
||||
}
|
||||
switch ($thisfile_ac3_raw_bsi['acmod']) {
|
||||
case 0:
|
||||
case 1:
|
||||
$info['audio']['channelmode'] = 'mono';
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
$info['audio']['channelmode'] = 'stereo';
|
||||
break;
|
||||
default:
|
||||
$info['audio']['channelmode'] = 'surround';
|
||||
break;
|
||||
}
|
||||
$info['audio']['channels'] = $thisfile_ac3['num_channels'];
|
||||
|
||||
$thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['flags']['lfeon'];
|
||||
if ($thisfile_ac3_raw_bsi['flags']['lfeon']) {
|
||||
$info['audio']['channels'] .= '.1';
|
||||
}
|
||||
|
||||
$thisfile_ac3['channels_enabled'] = self::channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['flags']['lfeon']);
|
||||
$thisfile_ac3['dialogue_normalization'] = '-'.$thisfile_ac3_raw_bsi['dialnorm'].'dB';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $length
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function readHeaderBSI($length) {
|
||||
$data = substr($this->AC3header['bsi'], $this->BSIoffset, $length);
|
||||
$this->BSIoffset += $length;
|
||||
|
||||
return bindec($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $fscod
|
||||
*
|
||||
* @return int|string|false
|
||||
*/
|
||||
public static function sampleRateCodeLookup($fscod) {
|
||||
static $sampleRateCodeLookup = array(
|
||||
0 => 48000,
|
||||
1 => 44100,
|
||||
2 => 32000,
|
||||
3 => 'reserved' // If the reserved code is indicated, the decoder should not attempt to decode audio and should mute.
|
||||
);
|
||||
return (isset($sampleRateCodeLookup[$fscod]) ? $sampleRateCodeLookup[$fscod] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $fscod2
|
||||
*
|
||||
* @return int|string|false
|
||||
*/
|
||||
public static function sampleRateCodeLookup2($fscod2) {
|
||||
static $sampleRateCodeLookup2 = array(
|
||||
0 => 24000,
|
||||
1 => 22050,
|
||||
2 => 16000,
|
||||
3 => 'reserved' // If the reserved code is indicated, the decoder should not attempt to decode audio and should mute.
|
||||
);
|
||||
return (isset($sampleRateCodeLookup2[$fscod2]) ? $sampleRateCodeLookup2[$fscod2] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $bsmod
|
||||
* @param int $acmod
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function serviceTypeLookup($bsmod, $acmod) {
|
||||
static $serviceTypeLookup = array();
|
||||
if (empty($serviceTypeLookup)) {
|
||||
for ($i = 0; $i <= 7; $i++) {
|
||||
$serviceTypeLookup[0][$i] = 'main audio service: complete main (CM)';
|
||||
$serviceTypeLookup[1][$i] = 'main audio service: music and effects (ME)';
|
||||
$serviceTypeLookup[2][$i] = 'associated service: visually impaired (VI)';
|
||||
$serviceTypeLookup[3][$i] = 'associated service: hearing impaired (HI)';
|
||||
$serviceTypeLookup[4][$i] = 'associated service: dialogue (D)';
|
||||
$serviceTypeLookup[5][$i] = 'associated service: commentary (C)';
|
||||
$serviceTypeLookup[6][$i] = 'associated service: emergency (E)';
|
||||
}
|
||||
|
||||
$serviceTypeLookup[7][1] = 'associated service: voice over (VO)';
|
||||
for ($i = 2; $i <= 7; $i++) {
|
||||
$serviceTypeLookup[7][$i] = 'main audio service: karaoke';
|
||||
}
|
||||
}
|
||||
return (isset($serviceTypeLookup[$bsmod][$acmod]) ? $serviceTypeLookup[$bsmod][$acmod] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $acmod
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public static function audioCodingModeLookup($acmod) {
|
||||
// array(channel configuration, # channels (not incl LFE), channel order)
|
||||
static $audioCodingModeLookup = array (
|
||||
0 => array('channel_config'=>'1+1', 'num_channels'=>2, 'channel_order'=>'Ch1,Ch2'),
|
||||
1 => array('channel_config'=>'1/0', 'num_channels'=>1, 'channel_order'=>'C'),
|
||||
2 => array('channel_config'=>'2/0', 'num_channels'=>2, 'channel_order'=>'L,R'),
|
||||
3 => array('channel_config'=>'3/0', 'num_channels'=>3, 'channel_order'=>'L,C,R'),
|
||||
4 => array('channel_config'=>'2/1', 'num_channels'=>3, 'channel_order'=>'L,R,S'),
|
||||
5 => array('channel_config'=>'3/1', 'num_channels'=>4, 'channel_order'=>'L,C,R,S'),
|
||||
6 => array('channel_config'=>'2/2', 'num_channels'=>4, 'channel_order'=>'L,R,SL,SR'),
|
||||
7 => array('channel_config'=>'3/2', 'num_channels'=>5, 'channel_order'=>'L,C,R,SL,SR'),
|
||||
);
|
||||
return (isset($audioCodingModeLookup[$acmod]) ? $audioCodingModeLookup[$acmod] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $cmixlev
|
||||
*
|
||||
* @return int|float|string|false
|
||||
*/
|
||||
public static function centerMixLevelLookup($cmixlev) {
|
||||
static $centerMixLevelLookup;
|
||||
if (empty($centerMixLevelLookup)) {
|
||||
$centerMixLevelLookup = array(
|
||||
0 => pow(2, -3.0 / 6), // 0.707 (-3.0 dB)
|
||||
1 => pow(2, -4.5 / 6), // 0.595 (-4.5 dB)
|
||||
2 => pow(2, -6.0 / 6), // 0.500 (-6.0 dB)
|
||||
3 => 'reserved'
|
||||
);
|
||||
}
|
||||
return (isset($centerMixLevelLookup[$cmixlev]) ? $centerMixLevelLookup[$cmixlev] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $surmixlev
|
||||
*
|
||||
* @return int|float|string|false
|
||||
*/
|
||||
public static function surroundMixLevelLookup($surmixlev) {
|
||||
static $surroundMixLevelLookup;
|
||||
if (empty($surroundMixLevelLookup)) {
|
||||
$surroundMixLevelLookup = array(
|
||||
0 => pow(2, -3.0 / 6),
|
||||
1 => pow(2, -6.0 / 6),
|
||||
2 => 0,
|
||||
3 => 'reserved'
|
||||
);
|
||||
}
|
||||
return (isset($surroundMixLevelLookup[$surmixlev]) ? $surroundMixLevelLookup[$surmixlev] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $dsurmod
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function dolbySurroundModeLookup($dsurmod) {
|
||||
static $dolbySurroundModeLookup = array(
|
||||
0 => 'not indicated',
|
||||
1 => 'Not Dolby Surround encoded',
|
||||
2 => 'Dolby Surround encoded',
|
||||
3 => 'reserved'
|
||||
);
|
||||
return (isset($dolbySurroundModeLookup[$dsurmod]) ? $dolbySurroundModeLookup[$dsurmod] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $acmod
|
||||
* @param bool $lfeon
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function channelsEnabledLookup($acmod, $lfeon) {
|
||||
$lookup = array(
|
||||
'ch1'=>($acmod == 0),
|
||||
'ch2'=>($acmod == 0),
|
||||
'left'=>($acmod > 1),
|
||||
'right'=>($acmod > 1),
|
||||
'center'=>(bool) ($acmod & 0x01),
|
||||
'surround_mono'=>false,
|
||||
'surround_left'=>false,
|
||||
'surround_right'=>false,
|
||||
'lfe'=>$lfeon);
|
||||
switch ($acmod) {
|
||||
case 4:
|
||||
case 5:
|
||||
$lookup['surround_mono'] = true;
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
$lookup['surround_left'] = true;
|
||||
$lookup['surround_right'] = true;
|
||||
break;
|
||||
}
|
||||
return $lookup;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $compre
|
||||
*
|
||||
* @return float|int
|
||||
*/
|
||||
public static function heavyCompression($compre) {
|
||||
// The first four bits indicate gain changes in 6.02dB increments which can be
|
||||
// implemented with an arithmetic shift operation. The following four bits
|
||||
// indicate linear gain changes, and require a 5-bit multiply.
|
||||
// We will represent the two 4-bit fields of compr as follows:
|
||||
// X0 X1 X2 X3 . Y4 Y5 Y6 Y7
|
||||
// The meaning of the X values is most simply described by considering X to represent a 4-bit
|
||||
// signed integer with values from -8 to +7. The gain indicated by X is then (X + 1) * 6.02 dB. The
|
||||
// following table shows this in detail.
|
||||
|
||||
// Meaning of 4 msb of compr
|
||||
// 7 +48.16 dB
|
||||
// 6 +42.14 dB
|
||||
// 5 +36.12 dB
|
||||
// 4 +30.10 dB
|
||||
// 3 +24.08 dB
|
||||
// 2 +18.06 dB
|
||||
// 1 +12.04 dB
|
||||
// 0 +6.02 dB
|
||||
// -1 0 dB
|
||||
// -2 -6.02 dB
|
||||
// -3 -12.04 dB
|
||||
// -4 -18.06 dB
|
||||
// -5 -24.08 dB
|
||||
// -6 -30.10 dB
|
||||
// -7 -36.12 dB
|
||||
// -8 -42.14 dB
|
||||
|
||||
$fourbit = str_pad(decbin(($compre & 0xF0) >> 4), 4, '0', STR_PAD_LEFT);
|
||||
if ($fourbit[0] == '1') {
|
||||
$log_gain = -8 + bindec(substr($fourbit, 1));
|
||||
} else {
|
||||
$log_gain = bindec(substr($fourbit, 1));
|
||||
}
|
||||
$log_gain = ($log_gain + 1) * getid3_lib::RGADamplitude2dB(2);
|
||||
|
||||
// The value of Y is a linear representation of a gain change of up to -6 dB. Y is considered to
|
||||
// be an unsigned fractional integer, with a leading value of 1, or: 0.1 Y4 Y5 Y6 Y7 (base 2). Y can
|
||||
// represent values between 0.111112 (or 31/32) and 0.100002 (or 1/2). Thus, Y can represent gain
|
||||
// changes from -0.28 dB to -6.02 dB.
|
||||
|
||||
$lin_gain = (16 + ($compre & 0x0F)) / 32;
|
||||
|
||||
// The combination of X and Y values allows compr to indicate gain changes from
|
||||
// 48.16 - 0.28 = +47.89 dB, to
|
||||
// -42.14 - 6.02 = -48.16 dB.
|
||||
|
||||
return $log_gain - $lin_gain;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $roomtyp
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function roomTypeLookup($roomtyp) {
|
||||
static $roomTypeLookup = array(
|
||||
0 => 'not indicated',
|
||||
1 => 'large room, X curve monitor',
|
||||
2 => 'small room, flat monitor',
|
||||
3 => 'reserved'
|
||||
);
|
||||
return (isset($roomTypeLookup[$roomtyp]) ? $roomTypeLookup[$roomtyp] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $frmsizecod
|
||||
* @param int $fscod
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public static function frameSizeLookup($frmsizecod, $fscod) {
|
||||
// LSB is whether padding is used or not
|
||||
$padding = (bool) ($frmsizecod & 0x01);
|
||||
$framesizeid = ($frmsizecod & 0x3E) >> 1;
|
||||
|
||||
static $frameSizeLookup = array();
|
||||
if (empty($frameSizeLookup)) {
|
||||
$frameSizeLookup = array (
|
||||
0 => array( 128, 138, 192), // 32 kbps
|
||||
1 => array( 160, 174, 240), // 40 kbps
|
||||
2 => array( 192, 208, 288), // 48 kbps
|
||||
3 => array( 224, 242, 336), // 56 kbps
|
||||
4 => array( 256, 278, 384), // 64 kbps
|
||||
5 => array( 320, 348, 480), // 80 kbps
|
||||
6 => array( 384, 416, 576), // 96 kbps
|
||||
7 => array( 448, 486, 672), // 112 kbps
|
||||
8 => array( 512, 556, 768), // 128 kbps
|
||||
9 => array( 640, 696, 960), // 160 kbps
|
||||
10 => array( 768, 834, 1152), // 192 kbps
|
||||
11 => array( 896, 974, 1344), // 224 kbps
|
||||
12 => array(1024, 1114, 1536), // 256 kbps
|
||||
13 => array(1280, 1392, 1920), // 320 kbps
|
||||
14 => array(1536, 1670, 2304), // 384 kbps
|
||||
15 => array(1792, 1950, 2688), // 448 kbps
|
||||
16 => array(2048, 2228, 3072), // 512 kbps
|
||||
17 => array(2304, 2506, 3456), // 576 kbps
|
||||
18 => array(2560, 2786, 3840) // 640 kbps
|
||||
);
|
||||
}
|
||||
$paddingBytes = 0;
|
||||
if (($fscod == 1) && $padding) {
|
||||
// frame lengths are padded by 1 word (16 bits) at 44100
|
||||
// (fscode==1) means 44100Hz (see sampleRateCodeLookup)
|
||||
$paddingBytes = 2;
|
||||
}
|
||||
return (isset($frameSizeLookup[$framesizeid][$fscod]) ? $frameSizeLookup[$framesizeid][$fscod] + $paddingBytes : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $frmsizecod
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public static function bitrateLookup($frmsizecod) {
|
||||
// LSB is whether padding is used or not
|
||||
$padding = (bool) ($frmsizecod & 0x01);
|
||||
$framesizeid = ($frmsizecod & 0x3E) >> 1;
|
||||
|
||||
static $bitrateLookup = array(
|
||||
0 => 32000,
|
||||
1 => 40000,
|
||||
2 => 48000,
|
||||
3 => 56000,
|
||||
4 => 64000,
|
||||
5 => 80000,
|
||||
6 => 96000,
|
||||
7 => 112000,
|
||||
8 => 128000,
|
||||
9 => 160000,
|
||||
10 => 192000,
|
||||
11 => 224000,
|
||||
12 => 256000,
|
||||
13 => 320000,
|
||||
14 => 384000,
|
||||
15 => 448000,
|
||||
16 => 512000,
|
||||
17 => 576000,
|
||||
18 => 640000,
|
||||
);
|
||||
return (isset($bitrateLookup[$framesizeid]) ? $bitrateLookup[$framesizeid] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $numblkscod
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public static function blocksPerSyncFrame($numblkscod) {
|
||||
static $blocksPerSyncFrameLookup = array(
|
||||
0 => 1,
|
||||
1 => 2,
|
||||
2 => 3,
|
||||
3 => 6,
|
||||
);
|
||||
return (isset($blocksPerSyncFrameLookup[$numblkscod]) ? $blocksPerSyncFrameLookup[$numblkscod] : false);
|
||||
}
|
||||
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue