merge
This commit is contained in:
commit
843d7fae24
36
.htaccess
36
.htaccess
@ -12,7 +12,7 @@
|
||||
</FilesMatch>
|
||||
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine on
|
||||
RewriteEngine On
|
||||
|
||||
# rather than link to images/ha/hash and have an ugly filename,
|
||||
# we link to images/hash/tags.ext; mod_rewrite splits things so
|
||||
@ -25,12 +25,6 @@
|
||||
RewriteRule ^(.*)$ index.php?q=$1&%{QUERY_STRING} [L]
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_php5.c>
|
||||
php_flag register_globals 0
|
||||
php_flag magic_quotes_gpc 0
|
||||
php_flag magic_quotes_runtime 0
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_expires.c>
|
||||
ExpiresActive On
|
||||
<FilesMatch "([0-9a-f]{32}|\.(gif|jpe?g|png|css|js))$">
|
||||
@ -43,19 +37,31 @@
|
||||
#ExpiresByType text/plain "now"
|
||||
</IfModule>
|
||||
|
||||
<ifmodule mod_deflate.c>
|
||||
<IfModule mod_deflate.c>
|
||||
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
|
||||
AddOutputFilterByType DEFLATE application/x-javascript application/javascript
|
||||
</ifmodule>
|
||||
</IfModule>
|
||||
|
||||
AddType audio/mp4 f4a f4b m4a
|
||||
AddType audio/ogg oga ogg opus
|
||||
#EXT: handle_pixel
|
||||
AddType image/jpeg jpg jpeg
|
||||
AddType image/bmp bmp
|
||||
AddType image/svg+xml svg svgz
|
||||
AddType image/gif gif
|
||||
AddType image/png png
|
||||
|
||||
#EXT: handle_ico
|
||||
AddType image/x-icon ico ani cur
|
||||
AddType image/webp webp
|
||||
|
||||
#EXT: handle_flash
|
||||
AddType application/x-shockwave-flash swf
|
||||
|
||||
#EXT: handle_mp3
|
||||
AddType audio/mpeg mp3
|
||||
|
||||
#EXT: handle_svg
|
||||
AddType image/svg+xml svg svgz
|
||||
|
||||
#EXT: handle_video
|
||||
AddType video/x-flv flv
|
||||
AddType video/mp4 f4v f4p m4v mp4
|
||||
AddType audio/mp4 f4a f4b m4a
|
||||
AddType video/ogg ogv
|
||||
AddType video/webm webm
|
||||
AddType video/x-flv flv
|
24
.travis.yml
24
.travis.yml
@ -1,9 +1,8 @@
|
||||
language: php
|
||||
php:
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- 7.1
|
||||
|
||||
sudo: false
|
||||
|
||||
@ -26,19 +25,24 @@ before_install:
|
||||
|
||||
install:
|
||||
- mkdir -p data/config
|
||||
- if [[ "$DB" == "pgsql" ]]; then psql -c "SELECT set_config('log_statement', 'all', false);" -U postgres; fi
|
||||
- if [[ "$DB" == "pgsql" ]]; then psql -c "CREATE DATABASE shimmie;" -U postgres; fi
|
||||
- if [[ "$DB" == "pgsql" ]]; then echo '<?php define("DATABASE_DSN", "pgsql:user=postgres;password=;host=;dbname=shimmie");' > data/config/auto_install.conf.php ; fi
|
||||
- if [[ "$DB" == "mysql" ]]; then mysql -e "SET GLOBAL general_log = 'ON';" -uroot; fi
|
||||
- if [[ "$DB" == "mysql" ]]; then mysql -e "CREATE DATABASE shimmie;" -uroot; fi
|
||||
- if [[ "$DB" == "mysql" ]]; then echo '<?php define("DATABASE_DSN", "mysql:user=root;password=;host=localhost;dbname=shimmie");' > data/config/auto_install.conf.php ; fi
|
||||
- |
|
||||
if [[ "$DB" == "pgsql" ]]; then
|
||||
psql -c "SELECT set_config('log_statement', 'all', false);" -U postgres ;
|
||||
psql -c "CREATE DATABASE shimmie;" -U postgres ;
|
||||
echo '<?php define("DATABASE_DSN", "pgsql:user=postgres;password=;host=;dbname=shimmie");' > data/config/auto_install.conf.php ;
|
||||
fi
|
||||
- |
|
||||
if [[ "$DB" == "mysql" ]]; then
|
||||
mysql -e "SET GLOBAL general_log = 'ON';" -uroot ;
|
||||
mysql -e "CREATE DATABASE shimmie;" -uroot ;
|
||||
echo '<?php define("DATABASE_DSN", "mysql:user=root;password=;host=localhost;dbname=shimmie");' > data/config/auto_install.conf.php ;
|
||||
fi
|
||||
- if [[ "$DB" == "sqlite" ]]; then echo '<?php define("DATABASE_DSN", "sqlite:shimmie.sqlite");' > data/config/auto_install.conf.php ; fi
|
||||
- composer global require "fxp/composer-asset-plugin:~1.1" --no-plugins
|
||||
- composer install
|
||||
- php install.php
|
||||
|
||||
script:
|
||||
- phpunit --configuration tests/phpunit.xml --coverage-clover=data/coverage.clover
|
||||
- vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-clover=data/coverage.clover
|
||||
|
||||
after_failure:
|
||||
- head -n 100 data/config/*
|
||||
|
@ -1,8 +1,8 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
@ -55,7 +55,7 @@ patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
@ -225,7 +225,7 @@ impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
@ -278,7 +278,7 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
@ -290,8 +290,8 @@ to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
{description}
|
||||
Copyright (C) {year} {fullname}
|
||||
|
||||
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
|
||||
@ -303,10 +303,9 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
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 the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
@ -330,11 +329,11 @@ necessary. Here is a sample; alter the names:
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
{signature of Ty Coon}, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
@ -29,7 +29,7 @@ check out one of the versioned branches.
|
||||
# Requirements
|
||||
|
||||
- MySQL/MariaDB 5.1+ (with experimental support for PostgreSQL 9+ and SQLite 3)
|
||||
- [Stable PHP](https://en.wikipedia.org/wiki/PHP#Release_history) (5.5 as of writing)
|
||||
- [Stable PHP](https://en.wikipedia.org/wiki/PHP#Release_history) (5.6+ as of writing)
|
||||
- GD or ImageMagick
|
||||
|
||||
# Installation
|
||||
@ -47,9 +47,8 @@ check out one of the versioned branches.
|
||||
1. Download shimmie via the "Download Zip" button on the [develop](https://github.com/shish/shimmie2/tree/develop) branch.
|
||||
2. Unzip shimmie into a folder on the web host
|
||||
3. Install [Composer](https://getcomposer.org/). (If you don't already have it)
|
||||
4. Run `composer global require "fxp/composer-asset-plugin:~1.1" --no-plugins`. (This is installed globally due to a known composer bug)
|
||||
5. Run `composer install` in the shimmie folder.
|
||||
6. Follow instructions noted in "Installation" starting from step 3.
|
||||
4. Run `composer install` in the shimmie folder.
|
||||
5. Follow instructions noted in "Installation" starting from step 3.
|
||||
|
||||
## Upgrade from 2.3.X
|
||||
|
||||
|
@ -4,36 +4,43 @@
|
||||
"minimum-stability" : "dev",
|
||||
|
||||
"repositories" : [
|
||||
{
|
||||
"type": "composer",
|
||||
"url": "https://asset-packagist.org"
|
||||
},
|
||||
{
|
||||
"type" : "package",
|
||||
"package" : {
|
||||
"name" : "ifixit/php-akismet",
|
||||
"version" : "1.0",
|
||||
"version" : "1.1",
|
||||
"source" : {
|
||||
"url" : "https://github.com/iFixit/php-akismet.git",
|
||||
"type" : "git",
|
||||
"reference" : "126b4b9182230678a585338be4cfca24c9129dc9"
|
||||
"reference" : "fd4ff50eb577457c1b7b887401663e91e77625ae"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
"require" : {
|
||||
"php" : ">=5.4.8",
|
||||
"php" : ">=5.6",
|
||||
|
||||
"flexihash/flexihash" : "^2.0.0",
|
||||
"ifixit/php-akismet" : "1.*",
|
||||
"google/recaptcha" : "~1.1",
|
||||
"dapphp/securimage" : "3.6.*",
|
||||
"ircmaxell/password-compat" : "1.0.4",
|
||||
|
||||
"bower-asset/jquery" : "1.12.3",
|
||||
"bower-asset/jquery-timeago" : "1.5.2",
|
||||
"bower-asset/tablesorter" : "2.0.5",
|
||||
"bower-asset/tablesorter" : "2.*",
|
||||
"bower-asset/mediaelement" : "2.21.1",
|
||||
"bower-asset/js-cookie" : "2.1.1"
|
||||
},
|
||||
|
||||
"require-dev" : {
|
||||
"phpunit/phpunit" : "5.*"
|
||||
},
|
||||
|
||||
"vendor-copy": {
|
||||
"vendor/bower-asset/jquery/dist/jquery.min.js" : "lib/vendor/js/jquery-1.12.3.min.js",
|
||||
"vendor/bower-asset/jquery/dist/jquery.min.map" : "lib/vendor/js/jquery-1.12.3.min.map",
|
||||
|
1349
composer.lock
generated
1349
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -263,11 +263,34 @@ class SQLite extends DBEngine {
|
||||
// }}}
|
||||
// {{{ cache engines
|
||||
interface CacheEngine {
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key);
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $val
|
||||
* @param integer $time
|
||||
* @return void
|
||||
*/
|
||||
public function set($key, $val, $time=0);
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function delete($key);
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public function get_hits();
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public function get_misses();
|
||||
}
|
||||
class NoCache implements CacheEngine {
|
||||
@ -319,7 +342,7 @@ class MemcacheCache implements CacheEngine {
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $val
|
||||
* @param int $time
|
||||
* @param integer $time
|
||||
*/
|
||||
public function set($key, $val, $time=0) {
|
||||
assert('!is_null($key)');
|
||||
@ -482,6 +505,10 @@ class Database {
|
||||
* @var null|PDO
|
||||
*/
|
||||
private $db = null;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
public $dbtime = 0.0;
|
||||
|
||||
/**
|
||||
@ -605,7 +632,7 @@ class Database {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @return boolean|null
|
||||
* @throws SCoreException
|
||||
*/
|
||||
public function commit() {
|
||||
@ -621,7 +648,7 @@ class Database {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @return boolean|null
|
||||
* @throws SCoreException
|
||||
*/
|
||||
public function rollback() {
|
||||
@ -662,6 +689,10 @@ class Database {
|
||||
return $this->engine->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|PDO $db
|
||||
* @param string $sql
|
||||
*/
|
||||
private function count_execs($db, $sql, $inputarray) {
|
||||
if ((defined('DEBUG_SQL') && DEBUG_SQL === true) || (!defined('DEBUG_SQL') && @$_GET['DEBUG_SQL'])) {
|
||||
$fp = @fopen("data/sql.log", "a");
|
||||
@ -893,35 +924,35 @@ class MockDatabase extends Database {
|
||||
/**
|
||||
* @param string $query
|
||||
* @param array $args
|
||||
* @return array|PDOStatement
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function get_all($query, $args=array()) {return $this->execute($query, $args);}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param array $args
|
||||
* @return mixed|null|PDOStatement
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function get_row($query, $args=array()) {return $this->execute($query, $args);}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param array $args
|
||||
* @return array|PDOStatement
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function get_col($query, $args=array()) {return $this->execute($query, $args);}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param array $args
|
||||
* @return array|PDOStatement
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function get_pairs($query, $args=array()) {return $this->execute($query, $args);}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param array $args
|
||||
* @return mixed|PDOStatement
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function get_one($query, $args=array()) {return $this->execute($query, $args);}
|
||||
|
||||
|
@ -92,6 +92,9 @@ abstract class Extension {
|
||||
$this->theme = $this->get_theme_object(get_called_class());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_live() {
|
||||
global $database;
|
||||
return (
|
||||
|
@ -59,9 +59,19 @@ class Image {
|
||||
/** @var string[]|null */
|
||||
public $tag_array;
|
||||
|
||||
public $owner_id, $owner_ip;
|
||||
/** @var int */
|
||||
public $owner_id;
|
||||
|
||||
/** @var string */
|
||||
public $owner_ip;
|
||||
|
||||
/** @var string */
|
||||
public $posted;
|
||||
|
||||
/** @var string */
|
||||
public $source;
|
||||
|
||||
/** @var boolean */
|
||||
public $locked;
|
||||
|
||||
/**
|
||||
@ -175,6 +185,10 @@ class Image {
|
||||
return $images;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $tags
|
||||
* @return boolean
|
||||
*/
|
||||
public static function validate_accel($tags) {
|
||||
$yays = 0;
|
||||
$nays = 0;
|
||||
@ -1196,7 +1210,7 @@ function move_upload_to_archive(DataUploadEvent $event) {
|
||||
* Add a directory full of images
|
||||
*
|
||||
* @param $base string
|
||||
* @return array
|
||||
* @return array|string[]
|
||||
*/
|
||||
function add_dir($base) {
|
||||
$results = array();
|
||||
@ -1236,7 +1250,7 @@ function add_image($tmpname, $filename, $tags) {
|
||||
$metadata = array();
|
||||
$metadata['filename'] = $pathinfo['basename'];
|
||||
$metadata['extension'] = $pathinfo['extension'];
|
||||
$metadata['tags'] = $tags;
|
||||
$metadata['tags'] = Tag::explode($tags);
|
||||
$metadata['source'] = null;
|
||||
$event = new DataUploadEvent($tmpname, $metadata);
|
||||
send_event($event);
|
||||
@ -1251,7 +1265,7 @@ function add_image($tmpname, $filename, $tags) {
|
||||
*
|
||||
* @param int $orig_width
|
||||
* @param int $orig_height
|
||||
* @return int[]
|
||||
* @return integer[]
|
||||
*/
|
||||
function get_thumbnail_size(/*int*/ $orig_width, /*int*/ $orig_height) {
|
||||
global $config;
|
||||
|
@ -36,12 +36,12 @@ _d("COMPILE_ELS", false); // boolean pre-build the list of event listeners
|
||||
_d("NICE_URLS", false); // boolean force niceurl mode
|
||||
_d("SEARCH_ACCEL", false); // boolean use search accelerator
|
||||
_d("WH_SPLITS", 1); // int how many levels of subfolders to put in the warehouse
|
||||
_d("VERSION", '2.5.5+'); // string shimmie version
|
||||
_d("VERSION", '2.6.0+'); // string shimmie version
|
||||
_d("TIMEZONE", null); // string timezone
|
||||
_d("CORE_EXTS", "bbcode,user,mail,upload,image,view,handle_pixel,ext_manager,setup,upgrade,handle_404,comment,tag_list,index,tag_edit,alias_editor"); // extensions to always enable
|
||||
_d("EXTRA_EXTS", ""); // string optional extra extensions
|
||||
_d("BASE_URL", null); // string force a specific base URL (default is auto-detect)
|
||||
|
||||
_d("MIN_PHP_VERSION", '5.6');// string minium supported PHP version
|
||||
|
||||
/*
|
||||
* Calculated settings - you should never need to change these
|
||||
|
@ -1,6 +1,10 @@
|
||||
<?php
|
||||
|
||||
/** @private */
|
||||
/**
|
||||
* @private
|
||||
* @param mixed $row
|
||||
* @return User
|
||||
*/
|
||||
function _new_user($row) {
|
||||
return new User($row);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ require_once "lib/context.php";
|
||||
/**
|
||||
* Make some data safe for printing into HTML
|
||||
*
|
||||
* @param $input
|
||||
* @param string $input
|
||||
* @return string
|
||||
*/
|
||||
function html_escape($input) {
|
||||
@ -18,7 +18,7 @@ function html_escape($input) {
|
||||
/**
|
||||
* Unescape data that was made safe for printing into HTML
|
||||
*
|
||||
* @param $input
|
||||
* @param string $input
|
||||
* @return string
|
||||
*/
|
||||
function html_unescape($input) {
|
||||
@ -28,7 +28,7 @@ function html_unescape($input) {
|
||||
/**
|
||||
* Make sure some data is safe to be used in integer context
|
||||
*
|
||||
* @param $input
|
||||
* @param string $input
|
||||
* @return int
|
||||
*/
|
||||
function int_escape($input) {
|
||||
@ -42,7 +42,7 @@ function int_escape($input) {
|
||||
/**
|
||||
* Make sure some data is safe to be used in URL context
|
||||
*
|
||||
* @param $input
|
||||
* @param string $input
|
||||
* @return string
|
||||
*/
|
||||
function url_escape($input) {
|
||||
@ -77,7 +77,7 @@ function url_escape($input) {
|
||||
/**
|
||||
* Make sure some data is safe to be used in SQL context
|
||||
*
|
||||
* @param $input
|
||||
* @param string $input
|
||||
* @return string
|
||||
*/
|
||||
function sql_escape($input) {
|
||||
@ -90,7 +90,7 @@ function sql_escape($input) {
|
||||
* Turn all manner of HTML / INI / JS / DB booleans into a PHP one
|
||||
*
|
||||
* @param mixed $input
|
||||
* @return bool
|
||||
* @return boolean
|
||||
*/
|
||||
function bool_escape($input) {
|
||||
/*
|
||||
@ -125,7 +125,7 @@ function bool_escape($input) {
|
||||
* Some functions require a callback function for escaping,
|
||||
* but we might not want to alter the data
|
||||
*
|
||||
* @param $input
|
||||
* @param string $input
|
||||
* @return string
|
||||
*/
|
||||
function no_escape($input) {
|
||||
@ -202,7 +202,7 @@ function truncate($string, $limit, $break=" ", $pad="...") {
|
||||
/**
|
||||
* Turn a human readable filesize into an integer, eg 1KB -> 1024
|
||||
*
|
||||
* @param $limit
|
||||
* @param string|integer $limit
|
||||
* @return int
|
||||
*/
|
||||
function parse_shorthand_int($limit) {
|
||||
@ -232,7 +232,7 @@ function parse_shorthand_int($limit) {
|
||||
/**
|
||||
* Turn an integer into a human readable filesize, eg 1024 -> 1KB
|
||||
*
|
||||
* @param $int
|
||||
* @param integer $int
|
||||
* @return string
|
||||
*/
|
||||
function to_shorthand_int($int) {
|
||||
@ -254,7 +254,7 @@ function to_shorthand_int($int) {
|
||||
/**
|
||||
* Turn a date into a time, a date, an "X minutes ago...", etc
|
||||
*
|
||||
* @param $date
|
||||
* @param string $date
|
||||
* @param bool $html
|
||||
* @return string
|
||||
*/
|
||||
@ -267,7 +267,7 @@ function autodate($date, $html=true) {
|
||||
/**
|
||||
* Check if a given string is a valid date-time. ( Format: yyyy-mm-dd hh:mm:ss )
|
||||
*
|
||||
* @param $dateTime
|
||||
* @param string $dateTime
|
||||
* @return bool
|
||||
*/
|
||||
function isValidDateTime($dateTime) {
|
||||
@ -283,7 +283,7 @@ function isValidDateTime($dateTime) {
|
||||
/**
|
||||
* Check if a given string is a valid date. ( Format: yyyy-mm-dd )
|
||||
*
|
||||
* @param $date
|
||||
* @param string $date
|
||||
* @return bool
|
||||
*/
|
||||
function isValidDate($date) {
|
||||
@ -297,6 +297,9 @@ function isValidDate($date) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $inputs
|
||||
*/
|
||||
function validate_input($inputs) {
|
||||
$outputs = array();
|
||||
|
||||
@ -391,8 +394,8 @@ function validate_input($inputs) {
|
||||
*
|
||||
* FIXME: also check that IP ban ext is installed
|
||||
*
|
||||
* @param $ip
|
||||
* @param $ban_reason
|
||||
* @param string $ip
|
||||
* @param string $ban_reason
|
||||
* @return string
|
||||
*/
|
||||
function show_ip($ip, $ban_reason) {
|
||||
@ -429,12 +432,6 @@ function endsWith(/*string*/ $haystack, /*string*/ $needle) {
|
||||
return (substr($haystack, $start) === $needle);
|
||||
}
|
||||
|
||||
if(!function_exists("mb_strlen")) { // D:
|
||||
function mb_strlen($str) {return strlen($str);}
|
||||
function mb_internal_encoding($enc) {}
|
||||
function mb_strtolower($str) {return strtolower($str);}
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
|
||||
* HTML Generation *
|
||||
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
@ -616,6 +613,7 @@ function zglob($pattern) {
|
||||
|
||||
/**
|
||||
* Gets contact link as mailto: or http:
|
||||
* @return string
|
||||
*/
|
||||
function contact_link() {
|
||||
global $config;
|
||||
@ -1024,6 +1022,11 @@ function transload($url, $mfile) {
|
||||
}
|
||||
|
||||
if (!function_exists('http_parse_headers')) { #http://www.php.net/manual/en/function.http-parse-headers.php#112917
|
||||
|
||||
/**
|
||||
* @param string $raw_headers
|
||||
* @return string[]
|
||||
*/
|
||||
function http_parse_headers ($raw_headers){
|
||||
$headers = array(); // $headers = [];
|
||||
|
||||
@ -1153,10 +1156,40 @@ function log_msg(/*string*/ $section, /*int*/ $priority, /*string*/ $message, $f
|
||||
}
|
||||
|
||||
// More shorthand ways of logging
|
||||
/**
|
||||
* @param string $section
|
||||
* @param string $message
|
||||
* @param bool|string $flash
|
||||
* @param array $args
|
||||
*/
|
||||
function log_debug( /*string*/ $section, /*string*/ $message, $flash=false, $args=array()) {log_msg($section, SCORE_LOG_DEBUG, $message, $flash, $args);}
|
||||
/**
|
||||
* @param string $section
|
||||
* @param string $message
|
||||
* @param bool|string $flash
|
||||
* @param array $args
|
||||
*/
|
||||
function log_info( /*string*/ $section, /*string*/ $message, $flash=false, $args=array()) {log_msg($section, SCORE_LOG_INFO, $message, $flash, $args);}
|
||||
/**
|
||||
* @param string $section
|
||||
* @param string $message
|
||||
* @param bool|string $flash
|
||||
* @param array $args
|
||||
*/
|
||||
function log_warning( /*string*/ $section, /*string*/ $message, $flash=false, $args=array()) {log_msg($section, SCORE_LOG_WARNING, $message, $flash, $args);}
|
||||
/**
|
||||
* @param string $section
|
||||
* @param string $message
|
||||
* @param bool|string $flash
|
||||
* @param array $args
|
||||
*/
|
||||
function log_error( /*string*/ $section, /*string*/ $message, $flash=false, $args=array()) {log_msg($section, SCORE_LOG_ERROR, $message, $flash, $args);}
|
||||
/**
|
||||
* @param string $section
|
||||
* @param string $message
|
||||
* @param bool|string $flash
|
||||
* @param array $args
|
||||
*/
|
||||
function log_critical(/*string*/ $section, /*string*/ $message, $flash=false, $args=array()) {log_msg($section, SCORE_LOG_CRITICAL, $message, $flash, $args);}
|
||||
|
||||
|
||||
@ -1187,8 +1220,8 @@ function get_request_id() {
|
||||
/**
|
||||
* Remove an item from an array
|
||||
*
|
||||
* @param $array
|
||||
* @param $to_remove
|
||||
* @param array $array
|
||||
* @param mixed $to_remove
|
||||
* @return array
|
||||
*/
|
||||
function array_remove($array, $to_remove) {
|
||||
@ -1207,8 +1240,8 @@ function array_remove($array, $to_remove) {
|
||||
*
|
||||
* Also removes duplicate values from the array.
|
||||
*
|
||||
* @param $array
|
||||
* @param $element
|
||||
* @param array $array
|
||||
* @param mixed $element
|
||||
* @return array
|
||||
*/
|
||||
function array_add($array, $element) {
|
||||
@ -1222,7 +1255,7 @@ function array_add($array, $element) {
|
||||
/**
|
||||
* Return the unique elements of an array, case insensitively
|
||||
*
|
||||
* @param $array
|
||||
* @param array $array
|
||||
* @return array
|
||||
*/
|
||||
function array_iunique($array) {
|
||||
@ -1246,8 +1279,8 @@ function array_iunique($array) {
|
||||
*
|
||||
* from http://uk.php.net/network
|
||||
*
|
||||
* @param $IP
|
||||
* @param $CIDR
|
||||
* @param string $IP
|
||||
* @param string $CIDR
|
||||
* @return bool
|
||||
*/
|
||||
function ip_in_range($IP, $CIDR) {
|
||||
@ -1386,7 +1419,10 @@ function list_files(/*string*/ $base, $_sub_dir="") {
|
||||
return $file_list;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function path_to_tags($path) {
|
||||
$matches = array();
|
||||
if(preg_match("/\d+ - (.*)\.([a-zA-Z]+)/", basename($path), $matches)) {
|
||||
@ -1596,15 +1632,18 @@ function score_assert_handler($file, $line, $code, $desc = null) {
|
||||
/** @privatesection */
|
||||
|
||||
function _version_check() {
|
||||
$min_version = "5.4.8";
|
||||
if(version_compare(PHP_VERSION, $min_version) == -1) {
|
||||
if(MIN_PHP_VERSION)
|
||||
{
|
||||
if(version_compare(phpversion(), MIN_PHP_VERSION, ">=") === FALSE) {
|
||||
print "
|
||||
Currently SCore Engine doesn't support versions of PHP lower than $min_version --
|
||||
if your web host is running an older version, they are dangerously out of
|
||||
Shimmie (SCore Engine) does not support versions of PHP lower than ".MIN_PHP_VERSION."
|
||||
(PHP reports that it is version ".phpversion().")
|
||||
If your web host is running an older version, they are dangerously out of
|
||||
date and you should plan on moving elsewhere.
|
||||
";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _sanitise_environment() {
|
||||
@ -1734,6 +1773,9 @@ function _get_user() {
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function _get_query() {
|
||||
return @$_POST["q"]?:@$_GET["q"];
|
||||
}
|
||||
|
@ -86,6 +86,12 @@ xanax
|
||||
$event->panel->add_block($sb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws if the comment contains banned words.
|
||||
* @param string $comment
|
||||
* @param CommentPostingException|SCoreException $ex
|
||||
* @throws CommentPostingException|SCoreException if the comment contains banned words.
|
||||
*/
|
||||
private function test_text($comment, $ex) {
|
||||
$comment = strtolower($comment);
|
||||
|
||||
@ -105,6 +111,9 @@ xanax
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function get_words() {
|
||||
global $config;
|
||||
$words = array();
|
||||
|
@ -73,7 +73,7 @@ class BulkAddCSV extends Extension {
|
||||
$metadata = array();
|
||||
$metadata['filename'] = $pathinfo['basename'];
|
||||
$metadata['extension'] = $pathinfo['extension'];
|
||||
$metadata['tags'] = $tags;
|
||||
$metadata['tags'] = Tag::explode($tags);
|
||||
$metadata['source'] = $source;
|
||||
$event = new DataUploadEvent($tmpname, $metadata);
|
||||
send_event($event);
|
||||
|
@ -10,14 +10,22 @@
|
||||
|
||||
$admin = loggedIn();
|
||||
|
||||
$log = 1;
|
||||
|
||||
if (isset($_GET['log']))
|
||||
{
|
||||
$log = $_GET['log'];
|
||||
}
|
||||
|
||||
if (isset($_POST['log']))
|
||||
{
|
||||
$log = $_POST['log'];
|
||||
}
|
||||
|
||||
if (!isset($log))
|
||||
if (filter_var($log, FILTER_VALIDATE_INT) === false)
|
||||
{
|
||||
$log = 1;
|
||||
}
|
||||
|
||||
$ys = ys($log);
|
||||
$posts = $ys->posts();
|
||||
|
@ -14,7 +14,7 @@ class Chatbox extends Extension {
|
||||
|
||||
// Adds header to enable chatbox
|
||||
$root = get_base_href();
|
||||
$yPath = make_http("") . "/ext/chatbox/";
|
||||
$yPath = make_http( $root . "/ext/chatbox/");
|
||||
$page->add_html_header("
|
||||
<script src=\"http://code.jquery.com/jquery-migrate-1.2.1.js\" type=\"text/javascript\"></script>
|
||||
<script src=\"$root/ext/chatbox/js/yshout.js\" type=\"text/javascript\"></script>
|
||||
@ -33,4 +33,3 @@ class Chatbox extends Extension {
|
||||
$page->add_block($chatblock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,10 @@
|
||||
global $yShout, $prefs;
|
||||
if ($yShout) return $yShout;
|
||||
|
||||
if ($log > $prefs['logs'] || $log < 0 || !is_numeric($log)) $log = 1;
|
||||
if (filter_var($log, FILTER_VALIDATE_INT, array("options" => array("min_range" => 0, "max_range" => $prefs['logs']))) === false)
|
||||
{
|
||||
$log = 1;
|
||||
}
|
||||
|
||||
$log = 'log.' . $log;
|
||||
return new YShout($log, loggedIn());
|
||||
|
@ -304,9 +304,14 @@ class CronUploader extends Extension {
|
||||
|
||||
/**
|
||||
* Generate the necessary DataUploadEvent for a given image and tags.
|
||||
*
|
||||
* @param string $tmpname
|
||||
* @param string $filename
|
||||
* @param string $tags
|
||||
*/
|
||||
private function add_image($tmpname, $filename, $tags) {
|
||||
assert ( file_exists ( $tmpname ) );
|
||||
assert('is_string($tags)');
|
||||
|
||||
$pathinfo = pathinfo ( $filename );
|
||||
if (! array_key_exists ( 'extension', $pathinfo )) {
|
||||
@ -315,7 +320,7 @@ class CronUploader extends Extension {
|
||||
$metadata = array();
|
||||
$metadata ['filename'] = $pathinfo ['basename'];
|
||||
$metadata ['extension'] = $pathinfo ['extension'];
|
||||
$metadata ['tags'] = ""; // = $tags; doesn't work when not logged in here
|
||||
$metadata ['tags'] = array(); // = $tags; doesn't work when not logged in here
|
||||
$metadata ['source'] = null;
|
||||
$event = new DataUploadEvent ( $tmpname, $metadata );
|
||||
send_event ( $event );
|
||||
@ -329,7 +334,7 @@ class CronUploader extends Extension {
|
||||
|
||||
// Set tags
|
||||
$img = Image::by_id($event->image_id);
|
||||
$img->set_tags($tags);
|
||||
$img->set_tags(Tag::explode($tags));
|
||||
}
|
||||
|
||||
private function generate_image_queue($base = "", $subdir = "") {
|
||||
|
@ -12,7 +12,10 @@
|
||||
* extensions and read their documentation
|
||||
*/
|
||||
|
||||
/** @private */
|
||||
/**
|
||||
* @private
|
||||
* @return int
|
||||
*/
|
||||
function __extman_extcmp(ExtensionInfo $a, ExtensionInfo $b) {
|
||||
return strcmp($a->name, $b->name);
|
||||
}
|
||||
@ -189,6 +192,9 @@ class ExtManager extends Extension {
|
||||
$this->write_config($extras);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $extras
|
||||
*/
|
||||
private function write_config($extras) {
|
||||
file_put_contents(
|
||||
"data/config/extensions.conf.php",
|
||||
|
@ -35,9 +35,11 @@ class ArchiveFileHandler extends Extension {
|
||||
exec($cmd);
|
||||
$results = add_dir($tmpdir);
|
||||
if(count($results) > 0) {
|
||||
// FIXME no theme?
|
||||
// Not all themes have the add_status() method, so need to check before calling.
|
||||
if (method_exists($this->theme, "add_status")) {
|
||||
$this->theme->add_status("Adding files", $results);
|
||||
}
|
||||
}
|
||||
deltree($tmpdir);
|
||||
$event->image_id = -2; // default -1 = upload wasn't handled
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ class FlashFileHandler extends DataHandlerExtension {
|
||||
$image->hash = $metadata['hash'];
|
||||
$image->filename = $metadata['filename'];
|
||||
$image->ext = $metadata['extension'];
|
||||
$image->tag_array = $metadata['tags'];
|
||||
$image->tag_array = is_array($metadata['tags']) ? $metadata['tags'] : Tag::explode($metadata['tags']);
|
||||
$image->source = $metadata['source'];
|
||||
|
||||
$info = getimagesize($filename);
|
||||
|
@ -67,7 +67,7 @@ class IcoFileHandler extends Extension {
|
||||
$image->hash = $metadata['hash'];
|
||||
$image->filename = $metadata['filename'];
|
||||
$image->ext = $metadata['extension'];
|
||||
$image->tag_array = $metadata['tags'];
|
||||
$image->tag_array = is_array($metadata['tags']) ? $metadata['tags'] : Tag::explode($metadata['tags']);
|
||||
$image->source = $metadata['source'];
|
||||
|
||||
return $image;
|
||||
|
75
ext/handle_mp3/lib/jsmediatags.min.js
vendored
Normal file
75
ext/handle_mp3/lib/jsmediatags.min.js
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
(function(v){"object"===typeof exports&&"undefined"!==typeof module?module.exports=v():"function"===typeof define&&define.amd?define([],v):("undefined"!==typeof window?window:"undefined"!==typeof global?global:"undefined"!==typeof self?self:this).jsmediatags=v()})(function(){return function f(h,m,k){function l(b,a){if(!m[b]){if(!h[b]){var e="function"==typeof require&&require;if(!a&&e)return e(b,!0);if(d)return d(b,!0);e=Error("Cannot find module '"+b+"'");throw e.code="MODULE_NOT_FOUND",e;}e=m[b]=
|
||||
{exports:{}};h[b][0].call(e.exports,function(a){var e=h[b][1][a];return l(e?e:a)},e,e.exports,f,h,m,k)}return m[b].exports}for(var d="function"==typeof require&&require,c=0;c<k.length;c++)l(k[c]);return l}({1:[function(f,h,m){},{}],2:[function(f,h,m){h.exports=XMLHttpRequest},{}],3:[function(f,h,m){function k(d,c){if("function"!==typeof c&&null!==c)throw new TypeError("Super expression must either be null or a function, not "+typeof c);d.prototype=Object.create(c&&c.prototype,{constructor:{value:d,
|
||||
enumerable:!1,writable:!0,configurable:!0}});c&&(Object.setPrototypeOf?Object.setPrototypeOf(d,c):d.__proto__=c)}var l=function(){function d(c,b){for(var a=0;a<b.length;a++){var e=b[a];e.enumerable=e.enumerable||!1;e.configurable=!0;"value"in e&&(e.writable=!0);Object.defineProperty(c,e.key,e)}}return function(c,b,a){b&&d(c.prototype,b);a&&d(c,a);return c}}();f=function(d){function c(b){if(!(this instanceof c))throw new TypeError("Cannot call a class as a function");var a;a=Object.getPrototypeOf(c).call(this);
|
||||
if(!this)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");a=!a||"object"!==typeof a&&"function"!==typeof a?this:a;a._array=b;a._size=b.length;a._isInitialized=!0;return a}k(c,d);l(c,[{key:"init",value:function(b){setTimeout(b.onSuccess,0)}},{key:"loadRange",value:function(b,a){setTimeout(a.onSuccess,0)}},{key:"getByteAt",value:function(b){return this._array[b]}}],[{key:"canReadFile",value:function(b){return Array.isArray(b)||"function"===typeof Buffer&&Buffer.isBuffer(b)}}]);
|
||||
return c}(f("./MediaFileReader"));h.exports=f},{"./MediaFileReader":10}],4:[function(f,h,m){function k(c,b){if("function"!==typeof b&&null!==b)throw new TypeError("Super expression must either be null or a function, not "+typeof b);c.prototype=Object.create(b&&b.prototype,{constructor:{value:c,enumerable:!1,writable:!0,configurable:!0}});b&&(Object.setPrototypeOf?Object.setPrototypeOf(c,b):c.__proto__=b)}var l=function(){function c(b,a){for(var e=0;e<a.length;e++){var g=a[e];g.enumerable=g.enumerable||
|
||||
!1;g.configurable=!0;"value"in g&&(g.writable=!0);Object.defineProperty(b,g.key,g)}}return function(b,a,e){a&&c(b.prototype,a);e&&c(b,e);return b}}(),d=f("./ChunkedFileData");f=function(c){function b(a){if(!(this instanceof b))throw new TypeError("Cannot call a class as a function");var e;e=Object.getPrototypeOf(b).call(this);if(!this)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");e=!e||"object"!==typeof e&&"function"!==typeof e?this:e;e._blob=a;e._fileData=
|
||||
new d;return e}k(b,c);l(b,[{key:"_init",value:function(a){this._size=this._blob.size;setTimeout(a.onSuccess,1)}},{key:"loadRange",value:function(a,b){var g=this,c=(this._blob.slice||this._blob.mozSlice||this._blob.webkitSlice).call(this._blob,a[0],a[1]+1),d=new FileReader;d.onloadend=function(c){c=new Uint8Array(d.result);g._fileData.addData(a[0],c);b.onSuccess()};d.onerror=d.onabort=function(a){if(b.onError)b.onError({type:"blob",info:d.error})};d.readAsArrayBuffer(c)}},{key:"getByteAt",value:function(a){return this._fileData.getByteAt(a)}}],
|
||||
[{key:"canReadFile",value:function(a){return"undefined"!==typeof Blob&&a instanceof Blob||"undefined"!==typeof File&&a instanceof File}}]);return b}(f("./MediaFileReader"));h.exports=f},{"./ChunkedFileData":5,"./MediaFileReader":10}],5:[function(f,h,m){var k=function(){function f(d,c){for(var b=0;b<c.length;b++){var a=c[b];a.enumerable=a.enumerable||!1;a.configurable=!0;"value"in a&&(a.writable=!0);Object.defineProperty(d,a.key,a)}}return function(d,c,b){c&&f(d.prototype,c);b&&f(d,b);return d}}();
|
||||
f=function(){function f(){if(!(this instanceof f))throw new TypeError("Cannot call a class as a function");this._fileData=[]}k(f,null,[{key:"NOT_FOUND",get:function(){return-1}}]);k(f,[{key:"addData",value:function(d,c){var b=d+c.length-1,a=this._getChunkRange(d,b);if(-1===a.startIx)this._fileData.splice(a.insertIx||0,0,{offset:d,data:c});else{var e=this._fileData[a.startIx],g=this._fileData[a.endIx],b=b<g.offset+g.data.length-1,p={offset:Math.min(d,e.offset),data:c};d>e.offset&&(e=this._sliceData(e.data,
|
||||
0,d-e.offset),p.data=this._concatData(e,c));b&&(e=this._sliceData(p.data,0,g.offset-p.offset),p.data=this._concatData(e,g.data));this._fileData.splice(a.startIx,a.endIx-a.startIx+1,p)}}},{key:"_concatData",value:function(d,c){if("undefined"!==typeof ArrayBuffer&&ArrayBuffer.isView(d)){var b=new d.constructor(d.length+c.length);b.set(d,0);b.set(c,d.length);return b}return d.concat(c)}},{key:"_sliceData",value:function(d,c,b){return d.slice?d.slice(c,b):d.subarray(c,b)}},{key:"_getChunkRange",value:function(d,
|
||||
c){for(var b=-1,a=-1,e=0,g=0;g<this._fileData.length;g++,e=g){var p=this._fileData[g].offset,q=p+this._fileData[g].data.length;if(c<p-1)break;if(d<=q+1&&c>=p-1){b=g;break}}if(-1===b)return{startIx:-1,endIx:-1,insertIx:e};for(g=b;g<this._fileData.length&&!(p=this._fileData[g].offset,q=p+this._fileData[g].data.length,c>=p-1&&(a=g),c<=q+1);g++);-1===a&&(a=b);return{startIx:b,endIx:a}}},{key:"hasDataRange",value:function(d,c){for(var b=0;b<this._fileData.length;b++){var a=this._fileData[b];if(c<a.offset)break;
|
||||
if(d>=a.offset&&c<a.offset+a.data.length)return!0}return!1}},{key:"getByteAt",value:function(d){for(var c,b=0;b<this._fileData.length;b++){var a=this._fileData[b].offset,e=a+this._fileData[b].data.length-1;if(d>=a&&d<=e){c=this._fileData[b];break}}if(c)return c.data[d-c.offset];throw Error("Offset "+d+" hasn't been loaded yet.");}}]);return f}();h.exports=f},{}],6:[function(f,h,m){function k(c,b){if("function"!==typeof b&&null!==b)throw new TypeError("Super expression must either be null or a function, not "+
|
||||
typeof b);c.prototype=Object.create(b&&b.prototype,{constructor:{value:c,enumerable:!1,writable:!0,configurable:!0}});b&&(Object.setPrototypeOf?Object.setPrototypeOf(c,b):c.__proto__=b)}var l=function(){function c(b,a){for(var e=0;e<a.length;e++){var g=a[e];g.enumerable=g.enumerable||!1;g.configurable=!0;"value"in g&&(g.writable=!0);Object.defineProperty(b,g.key,g)}}return function(b,a,e){a&&c(b.prototype,a);e&&c(b,e);return b}}();m=f("./MediaTagReader");f("./MediaFileReader");f=function(c){function b(){if(!(this instanceof
|
||||
b))throw new TypeError("Cannot call a class as a function");var a=Object.getPrototypeOf(b).apply(this,arguments);if(!this)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!a||"object"!==typeof a&&"function"!==typeof a?this:a}k(b,c);l(b,[{key:"_loadData",value:function(a,b){var g=a.getSize();a.loadRange([g-128,g-1],b)}},{key:"_parseData",value:function(a,b){var g=a.getSize()-128,c=a.getStringWithCharsetAt(g+3,30).toString(),q=a.getStringWithCharsetAt(g+33,
|
||||
30).toString(),r=a.getStringWithCharsetAt(g+63,30).toString(),f=a.getStringWithCharsetAt(g+93,4).toString(),u=a.getByteAt(g+97+28),n=a.getByteAt(g+97+29);if(0==u&&0!=n)var u="1.1",x=a.getStringWithCharsetAt(g+97,28).toString();else u="1.0",x=a.getStringWithCharsetAt(g+97,30).toString(),n=0;g=a.getByteAt(g+97+30);c={type:"ID3",version:u,tags:{title:c,artist:q,album:r,year:f,comment:x,genre:255>g?d[g]:""}};n&&(c.tags.track=n);return c}}],[{key:"getTagIdentifierByteRange",value:function(){return{offset:-128,
|
||||
length:128}}},{key:"canReadTagFormat",value:function(a){return"TAG"===String.fromCharCode.apply(String,a.slice(0,3))}}]);return b}(m);var d="Blues;Classic Rock;Country;Dance;Disco;Funk;Grunge;Hip-Hop;Jazz;Metal;New Age;Oldies;Other;Pop;R&B;Rap;Reggae;Rock;Techno;Industrial;Alternative;Ska;Death Metal;Pranks;Soundtrack;Euro-Techno;Ambient;Trip-Hop;Vocal;Jazz+Funk;Fusion;Trance;Classical;Instrumental;Acid;House;Game;Sound Clip;Gospel;Noise;AlternRock;Bass;Soul;Punk;Space;Meditative;Instrumental Pop;Instrumental Rock;Ethnic;Gothic;Darkwave;Techno-Industrial;Electronic;Pop-Folk;Eurodance;Dream;Southern Rock;Comedy;Cult;Gangsta;Top 40;Christian Rap;Pop/Funk;Jungle;Native American;Cabaret;New Wave;Psychadelic;Rave;Showtunes;Trailer;Lo-Fi;Tribal;Acid Punk;Acid Jazz;Polka;Retro;Musical;Rock & Roll;Hard Rock;Folk;Folk-Rock;National Folk;Swing;Fast Fusion;Bebob;Latin;Revival;Celtic;Bluegrass;Avantgarde;Gothic Rock;Progressive Rock;Psychedelic Rock;Symphonic Rock;Slow Rock;Big Band;Chorus;Easy Listening;Acoustic;Humour;Speech;Chanson;Opera;Chamber Music;Sonata;Symphony;Booty Bass;Primus;Porn Groove;Satire;Slow Jam;Club;Tango;Samba;Folklore;Ballad;Power Ballad;Rhythmic Soul;Freestyle;Duet;Punk Rock;Drum Solo;Acapella;Euro-House;Dance Hall".split(";");
|
||||
h.exports=f},{"./MediaFileReader":10,"./MediaTagReader":11}],7:[function(f,h,m){function k(b){var a;switch(b){case 0:a="iso-8859-1";break;case 1:a="utf-16";break;case 2:a="utf-16be";break;case 3:a="utf-8"}return a}function l(b,a,e,g){g=e.getStringWithCharsetAt(b+1,a-1,g);b=e.getStringWithCharsetAt(b+1+g.bytesReadCount,a-1-g.bytesReadCount);return{user_description:g.toString(),data:b.toString()}}f("./MediaFileReader");var d={APIC:function(b,a,e,g,p){p=p||"3";g=b;var d=k(e.getByteAt(b));switch(p){case "2":p=
|
||||
e.getStringAt(b+1,3);b+=4;break;case "3":case "4":p=e.getStringWithCharsetAt(b+1,a-1);b+=1+p.bytesReadCount;break;default:throw Error("Couldn't read ID3v2 major version.");}var r=e.getByteAt(b,1),r=c[r],d=e.getStringWithCharsetAt(b+1,a-(b-g)-1,d);b+=1+d.bytesReadCount;return{format:p.toString(),type:r,description:d.toString(),data:e.getBytesAt(b,g+a-b)}},COMM:function(b,a,e,g,c){var d=b,r=k(e.getByteAt(b));g=e.getStringAt(b+1,3);c=e.getStringWithCharsetAt(b+4,a-4,r);b+=4+c.bytesReadCount;b=e.getStringWithCharsetAt(b,
|
||||
d+a-b,r);return{language:g,short_description:c.toString(),text:b.toString()}}};d.COM=d.COMM;d.PIC=function(b,a,e,g,c){return d.APIC(b,a,e,g,"2")};d.PCNT=function(b,a,e,g,c){return e.getLongAt(b,!1)};d.CNT=d.PCNT;d["T*"]=function(b,a,e,g,c){g=k(e.getByteAt(b));return e.getStringWithCharsetAt(b+1,a-1,g).toString()};d.TXXX=function(b,a,e,g,c){g=k(e.getByteAt(b));return l(b,a,e,g)};d["W*"]=function(b,a,e,g,c){g=k(e.getByteAt(b));return void 0!==g?l(b,a,e,g):e.getStringWithCharsetAt(b,a,g).toString()};
|
||||
d.TCON=function(b,a,e,g){return d["T*"].apply(this,arguments).replace(/^\(\d+\)/,"")};d.TCO=d.TCON;d.USLT=function(b,a,e,g,c){var d=b,r=k(e.getByteAt(b));g=e.getStringAt(b+1,3);c=e.getStringWithCharsetAt(b+4,a-4,r);b+=4+c.bytesReadCount;b=e.getStringWithCharsetAt(b,d+a-b,r);return{language:g,descriptor:c.toString(),lyrics:b.toString()}};d.ULT=d.USLT;var c="Other;32x32 pixels 'file icon' (PNG only);Other file icon;Cover (front);Cover (back);Leaflet page;Media (e.g. label side of CD);Lead artist/lead performer/soloist;Artist/performer;Conductor;Band/Orchestra;Composer;Lyricist/text writer;Recording Location;During recording;During performance;Movie/video screen capture;A bright coloured fish;Illustration;Band/artist logotype;Publisher/Studio logotype".split(";");
|
||||
h.exports={getFrameReaderFunction:function(b){return b in d?d[b]:"T"===b[0]?d["T*"]:"W"===b[0]?d["W*"]:null}}},{"./MediaFileReader":10}],8:[function(f,h,m){function k(a,b){if("function"!==typeof b&&null!==b)throw new TypeError("Super expression must either be null or a function, not "+typeof b);a.prototype=Object.create(b&&b.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}});b&&(Object.setPrototypeOf?Object.setPrototypeOf(a,b):a.__proto__=b)}var l=function(){function a(b,
|
||||
e){for(var c=0;c<e.length;c++){var d=e[c];d.enumerable=d.enumerable||!1;d.configurable=!0;"value"in d&&(d.writable=!0);Object.defineProperty(b,d.key,d)}}return function(b,c,d){c&&a(b.prototype,c);d&&a(b,d);return b}}();m=f("./MediaTagReader");f("./MediaFileReader");var d=f("./ArrayFileReader"),c=f("./ID3v2FrameReader");f=function(e){function g(){if(!(this instanceof g))throw new TypeError("Cannot call a class as a function");var a=Object.getPrototypeOf(g).apply(this,arguments);if(!this)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
||||
return!a||"object"!==typeof a&&"function"!==typeof a?this:a}k(g,e);l(g,[{key:"_loadData",value:function(a,b){a.loadRange([6,9],{onSuccess:function(){a.loadRange([0,10+a.getSynchsafeInteger32At(6)-1],b)},onError:b.onError})}},{key:"_parseData",value:function(b,e){var c=0,g=b.getByteAt(c+3);if(4<g)return{type:"ID3",version:">2.4",tags:{}};var d=b.getByteAt(c+4),n=b.isBitSetAt(c+5,7),f=b.isBitSetAt(c+5,6),l=b.isBitSetAt(c+5,5),t=b.getSynchsafeInteger32At(c+6),c=c+10;if(f)var k=b.getLongAt(c,!0),c=c+
|
||||
(k+4);var g={type:"ID3",version:"2."+g+"."+d,major:g,revision:d,flags:{unsynchronisation:n,extended_header:f,experimental_indicator:l,footer_present:!1},size:t,tags:{}},c=this._readFrames(c,t+10,b,g,e),h;for(h in a)a.hasOwnProperty(h)&&(t=this._getFrameData(c,a[h]))&&(g.tags[h]=t);for(var m in c)c.hasOwnProperty(m)&&(g.tags[m]=c[m]);return g}},{key:"_getUnsyncFileReader",value:function(a,b,c){a=a.getBytesAt(b,c);for(b=0;b<a.length-1;b++)255===a[b]&&0===a[b+1]&&a.splice(b+1,1);return new d(a)}},{key:"_readFrames",
|
||||
value:function(a,b,e,g,d){var n={};for(d&&(d=this._expandShortcutTags(d));a<b;){var f=this._readFrameHeader(e,a,g),l=f.id;if(!l)break;var t=f.flags,h=f.size,k=a+f.headerSize,m=e;a+=f.headerSize+f.size;if(!d||-1!==d.indexOf(l)){if(g.flags.unsynchronisation||t&&t.format.unsynchronisation)m=this._getUnsyncFileReader(m,k,h),k=0,h=m.getSize();t&&t.format.data_length_indicator&&(k+=4,h-=4);t=(f=c.getFrameReaderFunction(l))?f(k,h,m,t):null;k=this._getFrameDescription(l);h={id:l,size:h,description:k,data:t};
|
||||
l in n?(n[l].id&&(n[l]=[n[l]]),n[l].push(h)):n[l]=h}}return n}},{key:"_readFrameHeader",value:function(a,b,c){c=c.major;var e=null;switch(c){case 2:var g=a.getStringAt(b,3),d=a.getInteger24At(b+3,!0),f=6;break;case 3:g=a.getStringAt(b,4);d=a.getLongAt(b+4,!0);f=10;break;case 4:g=a.getStringAt(b,4),d=a.getSynchsafeInteger32At(b+4),f=10}if(g==String.fromCharCode(0,0,0)||g==String.fromCharCode(0,0,0,0))g="";g&&2<c&&(e=this._readFrameFlags(a,b+8));return{id:g||"",size:d||0,headerSize:f||0,flags:e}}},
|
||||
{key:"_readFrameFlags",value:function(a,b){return{message:{tag_alter_preservation:a.isBitSetAt(b,6),file_alter_preservation:a.isBitSetAt(b,5),read_only:a.isBitSetAt(b,4)},format:{grouping_identity:a.isBitSetAt(b+1,7),compression:a.isBitSetAt(b+1,3),encryption:a.isBitSetAt(b+1,2),unsynchronisation:a.isBitSetAt(b+1,1),data_length_indicator:a.isBitSetAt(b+1,0)}}}},{key:"_getFrameData",value:function(a,b){for(var c=0,e;e=b[c];c++)if(e in a)return a[e].data}},{key:"_getFrameDescription",value:function(a){return a in
|
||||
b?b[a]:"Unknown"}},{key:"getShortcuts",value:function(){return a}}],[{key:"getTagIdentifierByteRange",value:function(){return{offset:0,length:10}}},{key:"canReadTagFormat",value:function(a){return"ID3"===String.fromCharCode.apply(String,a.slice(0,3))}}]);return g}(m);var b={BUF:"Recommended buffer size",CNT:"Play counter",COM:"Comments",CRA:"Audio encryption",CRM:"Encrypted meta frame",ETC:"Event timing codes",EQU:"Equalization",GEO:"General encapsulated object",IPL:"Involved people list",LNK:"Linked information",
|
||||
MCI:"Music CD Identifier",MLL:"MPEG location lookup table",PIC:"Attached picture",POP:"Popularimeter",REV:"Reverb",RVA:"Relative volume adjustment",SLT:"Synchronized lyric/text",STC:"Synced tempo codes",TAL:"Album/Movie/Show title",TBP:"BPM (Beats Per Minute)",TCM:"Composer",TCO:"Content type",TCR:"Copyright message",TDA:"Date",TDY:"Playlist delay",TEN:"Encoded by",TFT:"File type",TIM:"Time",TKE:"Initial key",TLA:"Language(s)",TLE:"Length",TMT:"Media type",TOA:"Original artist(s)/performer(s)",TOF:"Original filename",
|
||||
TOL:"Original Lyricist(s)/text writer(s)",TOR:"Original release year",TOT:"Original album/Movie/Show title",TP1:"Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group",TP2:"Band/Orchestra/Accompaniment",TP3:"Conductor/Performer refinement",TP4:"Interpreted, remixed, or otherwise modified by",TPA:"Part of a set",TPB:"Publisher",TRC:"ISRC (International Standard Recording Code)",TRD:"Recording dates",TRK:"Track number/Position in set",TSI:"Size",TSS:"Software/hardware and settings used for encoding",
|
||||
TT1:"Content group description",TT2:"Title/Songname/Content description",TT3:"Subtitle/Description refinement",TXT:"Lyricist/text writer",TXX:"User defined text information frame",TYE:"Year",UFI:"Unique file identifier",ULT:"Unsychronized lyric/text transcription",WAF:"Official audio file webpage",WAR:"Official artist/performer webpage",WAS:"Official audio source webpage",WCM:"Commercial information",WCP:"Copyright/Legal information",WPB:"Publishers official webpage",WXX:"User defined URL link frame",
|
||||
AENC:"Audio encryption",APIC:"Attached picture",ASPI:"Audio seek point index",COMM:"Comments",COMR:"Commercial frame",ENCR:"Encryption method registration",EQU2:"Equalisation (2)",EQUA:"Equalization",ETCO:"Event timing codes",GEOB:"General encapsulated object",GRID:"Group identification registration",IPLS:"Involved people list",LINK:"Linked information",MCDI:"Music CD identifier",MLLT:"MPEG location lookup table",OWNE:"Ownership frame",PRIV:"Private frame",PCNT:"Play counter",POPM:"Popularimeter",
|
||||
POSS:"Position synchronisation frame",RBUF:"Recommended buffer size",RVA2:"Relative volume adjustment (2)",RVAD:"Relative volume adjustment",RVRB:"Reverb",SEEK:"Seek frame",SYLT:"Synchronized lyric/text",SYTC:"Synchronized tempo codes",TALB:"Album/Movie/Show title",TBPM:"BPM (beats per minute)",TCOM:"Composer",TCON:"Content type",TCOP:"Copyright message",TDAT:"Date",TDLY:"Playlist delay",TDRC:"Recording time",TDRL:"Release time",TDTG:"Tagging time",TENC:"Encoded by",TEXT:"Lyricist/Text writer",TFLT:"File type",
|
||||
TIME:"Time",TIPL:"Involved people list",TIT1:"Content group description",TIT2:"Title/songname/content description",TIT3:"Subtitle/Description refinement",TKEY:"Initial key",TLAN:"Language(s)",TLEN:"Length",TMCL:"Musician credits list",TMED:"Media type",TMOO:"Mood",TOAL:"Original album/movie/show title",TOFN:"Original filename",TOLY:"Original lyricist(s)/text writer(s)",TOPE:"Original artist(s)/performer(s)",TORY:"Original release year",TOWN:"File owner/licensee",TPE1:"Lead performer(s)/Soloist(s)",
|
||||
TPE2:"Band/orchestra/accompaniment",TPE3:"Conductor/performer refinement",TPE4:"Interpreted, remixed, or otherwise modified by",TPOS:"Part of a set",TPRO:"Produced notice",TPUB:"Publisher",TRCK:"Track number/Position in set",TRDA:"Recording dates",TRSN:"Internet radio station name",TRSO:"Internet radio station owner",TSOA:"Album sort order",TSOP:"Performer sort order",TSOT:"Title sort order",TSIZ:"Size",TSRC:"ISRC (international standard recording code)",TSSE:"Software/Hardware and settings used for encoding",
|
||||
TSST:"Set subtitle",TYER:"Year",TXXX:"User defined text information frame",UFID:"Unique file identifier",USER:"Terms of use",USLT:"Unsychronized lyric/text transcription",WCOM:"Commercial information",WCOP:"Copyright/Legal information",WOAF:"Official audio file webpage",WOAR:"Official artist/performer webpage",WOAS:"Official audio source webpage",WORS:"Official internet radio station homepage",WPAY:"Payment",WPUB:"Publishers official webpage",WXXX:"User defined URL link frame"},a={title:["TIT2","TT2"],
|
||||
artist:["TPE1","TP1"],album:["TALB","TAL"],year:["TYER","TYE"],comment:["COMM","COM"],track:["TRCK","TRK"],genre:["TCON","TCO"],picture:["APIC","PIC"],lyrics:["USLT","ULT"]};h.exports=f},{"./ArrayFileReader":3,"./ID3v2FrameReader":7,"./MediaFileReader":10,"./MediaTagReader":11}],9:[function(f,h,m){function k(a,b){if("function"!==typeof b&&null!==b)throw new TypeError("Super expression must either be null or a function, not "+typeof b);a.prototype=Object.create(b&&b.prototype,{constructor:{value:a,
|
||||
enumerable:!1,writable:!0,configurable:!0}});b&&(Object.setPrototypeOf?Object.setPrototypeOf(a,b):a.__proto__=b)}var l=function(){function a(a,b){for(var c=0;c<b.length;c++){var d=b[c];d.enumerable=d.enumerable||!1;d.configurable=!0;"value"in d&&(d.writable=!0);Object.defineProperty(a,d.key,d)}}return function(b,c,d){c&&a(b.prototype,c);d&&a(b,d);return b}}();m=f("./MediaTagReader");f("./MediaFileReader");f=function(a){function e(){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function");
|
||||
var a=Object.getPrototypeOf(e).apply(this,arguments);if(!this)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!a||"object"!==typeof a&&"function"!==typeof a?this:a}k(e,a);l(e,[{key:"_loadData",value:function(a,b){var c=this;a.loadRange([0,16],{onSuccess:function(){c._loadAtom(a,0,"",b)},onError:b.onError})}},{key:"_loadAtom",value:function(a,b,c,e){if(b>=a.getSize())e.onSuccess();else{var d=this,f=a.getLongAt(b,!0);if(0==f||isNaN(f))e.onSuccess();else{var n=
|
||||
a.getStringAt(b+4,4);if(this._isContainerAtom(n)){"meta"==n&&(b+=4);var l=(c?c+".":"")+n;"moov.udta.meta.ilst"===l?a.loadRange([b,b+f],e):a.loadRange([b+8,b+8+8],{onSuccess:function(){d._loadAtom(a,b+8,l,e)},onError:e.onError})}else a.loadRange([b+f,b+f+8],{onSuccess:function(){d._loadAtom(a,b+f,c,e)},onError:e.onError})}}}},{key:"_isContainerAtom",value:function(a){return 0<=["moov","udta","meta","ilst"].indexOf(a)}},{key:"_canReadAtom",value:function(a){return"----"!==a}},{key:"_parseData",value:function(a,
|
||||
c){var e={};c=this._expandShortcutTags(c);this._readAtom(e,a,0,a.getSize(),c);for(var d in b)if(b.hasOwnProperty(d)){var f=e[b[d]];f&&(e[d]="track"===d?f.data.track:f.data)}return{type:"MP4",ftyp:a.getStringAt(8,4),version:a.getLongAt(12,!0),tags:e}}},{key:"_readAtom",value:function(a,b,c,e,d,f,n){n=void 0===n?"":n+" ";for(var l=c;l<c+e;){var h=b.getLongAt(l,!0);if(0==h)break;var k=b.getStringAt(l+4,4);if(this._isContainerAtom(k)){"meta"==k&&(l+=4);this._readAtom(a,b,l+8,h-8,d,(f?f+".":"")+k,n);
|
||||
break}(!d||0<=d.indexOf(k))&&"moov.udta.meta.ilst"===f&&this._canReadAtom(k)&&(a[k]=this._readMetadataAtom(b,l));l+=h}}},{key:"_readMetadataAtom",value:function(a,b){var e=a.getLongAt(b,!0),f=a.getStringAt(b+4,4),l=a.getInteger24At(b+16+1,!0),l=d[l],k;if("trkn"==f)k={track:a.getByteAt(b+16+11),total:a.getByteAt(b+16+13)};else{var n=b+24,h=e-24;"covr"===f&&"uint8"===l&&(l="jpeg");switch(l){case "text":k=a.getStringWithCharsetAt(n,h,"utf-8").toString();break;case "uint8":k=a.getShortAt(n,!1);break;
|
||||
case "int":case "uint":k=("int"==l?1==h?a.getSByteAt:2==h?a.getSShortAt:4==h?a.getSLongAt:a.getLongAt:1==h?a.getByteAt:2==h?a.getShortAt:a.getLongAt).call(a,n+(8==h?4:0),!0);break;case "jpeg":case "png":k={format:"image/"+l,data:a.getBytesAt(n,h)}}}return{id:f,size:e,description:c[f]||"Unknown",data:k}}},{key:"getShortcuts",value:function(){return b}}],[{key:"getTagIdentifierByteRange",value:function(){return{offset:0,length:16}}},{key:"canReadTagFormat",value:function(a){return"ftyp"===String.fromCharCode.apply(String,
|
||||
a.slice(4,8))}}]);return e}(m);var d={0:"uint8",1:"text",13:"jpeg",14:"png",21:"int",22:"uint"},c={"\u00a9alb":"Album","\u00a9ART":"Artist",aART:"Album Artist","\u00a9day":"Release Date","\u00a9nam":"Title","\u00a9gen":"Genre",gnre:"Genre",trkn:"Track Number","\u00a9wrt":"Composer","\u00a9too":"Encoding Tool","\u00a9enc":"Encoded By",cprt:"Copyright",covr:"Cover Art","\u00a9grp":"Grouping",keyw:"Keywords","\u00a9lyr":"Lyrics","\u00a9cmt":"Comment",tmpo:"Tempo",cpil:"Compilation",disk:"Disc Number",
|
||||
tvsh:"TV Show Name",tven:"TV Episode ID",tvsn:"TV Season",tves:"TV Episode",tvnn:"TV Network",desc:"Description",ldes:"Long Description",sonm:"Sort Name",soar:"Sort Artist",soaa:"Sort Album",soco:"Sort Composer",sosn:"Sort Show",purd:"Purchase Date",pcst:"Podcast",purl:"Podcast URL",catg:"Category",hdvd:"HD Video",stik:"Media Type",rtng:"Content Rating",pgap:"Gapless Playback",apID:"Purchase Account",sfID:"Country Code",atID:"Artist ID",cnID:"Catalog ID",plID:"Collection ID",geID:"Genre ID","xid ":"Vendor Information",
|
||||
flvr:"Codec Flavor"},b={title:"\u00a9nam",artist:"\u00a9ART",album:"\u00a9alb",year:"\u00a9day",comment:"\u00a9cmt",track:"trkn",genre:"\u00a9gen",picture:"covr",lyrics:"\u00a9lyr"};h.exports=f},{"./MediaFileReader":10,"./MediaTagReader":11}],10:[function(f,h,m){var k=function(){function d(c,b){for(var a=0;a<b.length;a++){var e=b[a];e.enumerable=e.enumerable||!1;e.configurable=!0;"value"in e&&(e.writable=!0);Object.defineProperty(c,e.key,e)}}return function(c,b,a){b&&d(c.prototype,b);a&&d(c,a);return c}}(),
|
||||
l=f("./StringUtils");f=function(){function d(){if(!(this instanceof d))throw new TypeError("Cannot call a class as a function");this._isInitialized=!1;this._size=0}k(d,[{key:"init",value:function(c){var b=this;if(this._isInitialized)setTimeout(c.onSuccess,1);else return this._init({onSuccess:function(){b._isInitialized=!0;c.onSuccess()},onError:c.onError})}},{key:"_init",value:function(c){throw Error("Must implement init function");}},{key:"loadRange",value:function(c,b){throw Error("Must implement loadRange function");
|
||||
}},{key:"getSize",value:function(){if(!this._isInitialized)throw Error("init() must be called first.");return this._size}},{key:"getByteAt",value:function(c){throw Error("Must implement getByteAt function");}},{key:"getBytesAt",value:function(c,b){for(var a=Array(b),e=0;e<b;e++)a[e]=this.getByteAt(c+e);return a}},{key:"isBitSetAt",value:function(c,b){return 0!=(this.getByteAt(c)&1<<b)}},{key:"getSByteAt",value:function(c){c=this.getByteAt(c);return 127<c?c-256:c}},{key:"getShortAt",value:function(c,
|
||||
b){var a=b?(this.getByteAt(c)<<8)+this.getByteAt(c+1):(this.getByteAt(c+1)<<8)+this.getByteAt(c);0>a&&(a+=65536);return a}},{key:"getSShortAt",value:function(c,b){var a=this.getShortAt(c,b);return 32767<a?a-65536:a}},{key:"getLongAt",value:function(c,b){var a=this.getByteAt(c),e=this.getByteAt(c+1),d=this.getByteAt(c+2),f=this.getByteAt(c+3),a=b?(((a<<8)+e<<8)+d<<8)+f:(((f<<8)+d<<8)+e<<8)+a;0>a&&(a+=4294967296);return a}},{key:"getSLongAt",value:function(c,b){var a=this.getLongAt(c,b);return 2147483647<
|
||||
a?a-4294967296:a}},{key:"getInteger24At",value:function(c,b){var a=this.getByteAt(c),e=this.getByteAt(c+1),d=this.getByteAt(c+2),a=b?((a<<8)+e<<8)+d:((d<<8)+e<<8)+a;0>a&&(a+=16777216);return a}},{key:"getStringAt",value:function(c,b){for(var a=[],e=c,d=0;e<c+b;e++,d++)a[d]=String.fromCharCode(this.getByteAt(e));return a.join("")}},{key:"getStringWithCharsetAt",value:function(c,b,a){c=this.getBytesAt(c,b);switch((a||"").toLowerCase()){case "utf-16":case "utf-16le":case "utf-16be":a=l.readUTF16String(c,
|
||||
"utf-16be"===a);break;case "utf-8":a=l.readUTF8String(c);break;default:a=l.readNullTerminatedString(c)}return a}},{key:"getCharAt",value:function(c){return String.fromCharCode(this.getByteAt(c))}},{key:"getSynchsafeInteger32At",value:function(c){var b=this.getByteAt(c),a=this.getByteAt(c+1),e=this.getByteAt(c+2);return this.getByteAt(c+3)&127|(e&127)<<7|(a&127)<<14|(b&127)<<21}}],[{key:"canReadFile",value:function(c){throw Error("Must implement canReadFile function");}}]);return d}();h.exports=f},
|
||||
{"./StringUtils":12}],11:[function(f,h,m){var k=function(){function f(d,c){for(var b=0;b<c.length;b++){var a=c[b];a.enumerable=a.enumerable||!1;a.configurable=!0;"value"in a&&(a.writable=!0);Object.defineProperty(d,a.key,a)}}return function(d,c,b){c&&f(d.prototype,c);b&&f(d,b);return d}}();f("./MediaFileReader");f=function(){function f(d){if(!(this instanceof f))throw new TypeError("Cannot call a class as a function");this._mediaFileReader=d;this._tags=null}k(f,[{key:"setTagsToRead",value:function(d){this._tags=
|
||||
d;return this}},{key:"read",value:function(d){var c=this;this._mediaFileReader.init({onSuccess:function(){c._loadData(c._mediaFileReader,{onSuccess:function(){try{var b=c._parseData(c._mediaFileReader,c._tags)}catch(a){if(d.onError){d.onError({type:"parseData",info:a.message});return}}d.onSuccess(b)},onError:d.onError})},onError:d.onError})}},{key:"getShortcuts",value:function(){return{}}},{key:"_loadData",value:function(d,c){throw Error("Must implement _loadData function");}},{key:"_parseData",value:function(d,
|
||||
c){throw Error("Must implement _parseData function");}},{key:"_expandShortcutTags",value:function(d){if(!d)return null;for(var c=[],b=this.getShortcuts(),a=0,e;e=d[a];a++)c=c.concat(b[e]||[e]);return c}}],[{key:"getTagIdentifierByteRange",value:function(){throw Error("Must implement");}},{key:"canReadTagFormat",value:function(d){throw Error("Must implement");}}]);return f}();h.exports=f},{"./MediaFileReader":10}],12:[function(f,h,m){var k=function(){function d(c,b){for(var a=0;a<b.length;a++){var e=
|
||||
b[a];e.enumerable=e.enumerable||!1;e.configurable=!0;"value"in e&&(e.writable=!0);Object.defineProperty(c,e.key,e)}}return function(c,b,a){b&&d(c.prototype,b);a&&d(c,a);return c}}(),l=function(){function d(c,b){if(!(this instanceof d))throw new TypeError("Cannot call a class as a function");this._value=c;this.bytesReadCount=b;this.length=c.length}k(d,[{key:"toString",value:function(){return this._value}}]);return d}();h.exports={readUTF16String:function(d,c,b){var a=0,e=1,g=0;b=Math.min(b||d.length,
|
||||
d.length);254==d[0]&&255==d[1]?(c=!0,a=2):255==d[0]&&254==d[1]&&(c=!1,a=2);c&&(e=0,g=1);c=[];for(var f=0;a<b;f++){var h=d[a+e],k=(h<<8)+d[a+g],a=a+2;if(0==k)break;else 216>h||224<=h?c[f]=String.fromCharCode(k):(h=(d[a+e]<<8)+d[a+g],a+=2,c[f]=String.fromCharCode(k,h))}return new l(c.join(""),a)},readUTF8String:function(d,c){var b=0;c=Math.min(c||d.length,d.length);239==d[0]&&187==d[1]&&191==d[2]&&(b=3);for(var a=[],e=0;b<c;e++){var g=d[b++];if(0==g)break;else if(128>g)a[e]=String.fromCharCode(g);else if(194<=
|
||||
g&&224>g){var f=d[b++];a[e]=String.fromCharCode(((g&31)<<6)+(f&63))}else if(224<=g&&240>g){var f=d[b++],h=d[b++];a[e]=String.fromCharCode(((g&255)<<12)+((f&63)<<6)+(h&63))}else if(240<=g&&245>g){var f=d[b++],h=d[b++],k=d[b++],g=((g&7)<<18)+((f&63)<<12)+((h&63)<<6)+(k&63)-65536;a[e]=String.fromCharCode((g>>10)+55296,(g&1023)+56320)}}return new l(a.join(""),b)},readNullTerminatedString:function(d,c){var b=[];c=c||d.length;for(var a=0;a<c;){var e=d[a++];if(0==e)break;b[a-1]=String.fromCharCode(e)}return new l(b.join(""),
|
||||
a)}}},{}],13:[function(f,h,m){function k(c,b){if("function"!==typeof b&&null!==b)throw new TypeError("Super expression must either be null or a function, not "+typeof b);c.prototype=Object.create(b&&b.prototype,{constructor:{value:c,enumerable:!1,writable:!0,configurable:!0}});b&&(Object.setPrototypeOf?Object.setPrototypeOf(c,b):c.__proto__=b)}var l=function(){function c(b,a){for(var c=0;c<a.length;c++){var d=a[c];d.enumerable=d.enumerable||!1;d.configurable=!0;"value"in d&&(d.writable=!0);Object.defineProperty(b,
|
||||
d.key,d)}}return function(b,a,e){a&&c(b.prototype,a);e&&c(b,e);return b}}(),d=f("./ChunkedFileData");m=function(c){function b(a){if(!(this instanceof b))throw new TypeError("Cannot call a class as a function");var c;c=Object.getPrototypeOf(b).call(this);if(!this)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");c=!c||"object"!==typeof c&&"function"!==typeof c?this:c;c._url=a;c._fileData=new d;return c}k(b,c);l(b,[{key:"_init",value:function(a){b._config.avoidHeadRequests?
|
||||
this._fetchSizeWithGetRequest(a):this._fetchSizeWithHeadRequest(a)}},{key:"_fetchSizeWithHeadRequest",value:function(a){var b=this;this._makeXHRRequest("HEAD",null,{onSuccess:function(c){(c=b._parseContentLength(c))?(b._size=c,a.onSuccess()):b._fetchSizeWithGetRequest(a)},onError:a.onError})}},{key:"_fetchSizeWithGetRequest",value:function(a){var b=this,c=this._roundRangeToChunkMultiple([0,0]);this._makeXHRRequest("GET",c,{onSuccess:function(c){var d=b._parseContentRange(c);c=b._getXhrResponseContent(c);
|
||||
if(d){if(null==d.instanceLength){b._fetchEntireFile(a);return}b._size=d.instanceLength}else b._size=c.length;b._fileData.addData(0,c);a.onSuccess()},onError:a.onError})}},{key:"_fetchEntireFile",value:function(a){var b=this;this._makeXHRRequest("GET",null,{onSuccess:function(c){c=b._getXhrResponseContent(c);b._size=c.length;b._fileData.addData(0,c);a.onSuccess()},onError:a.onError})}},{key:"_getXhrResponseContent",value:function(a){return a.responseBody||a.responseText||""}},{key:"_parseContentLength",
|
||||
value:function(a){a=this._getResponseHeader(a,"Content-Length");return null==a?a:parseInt(a,10)}},{key:"_parseContentRange",value:function(a){if(a=this._getResponseHeader(a,"Content-Range")){var b=a.match(/bytes (\d+)-(\d+)\/(?:(\d+)|\*)/i);if(!b)throw Error("FIXME: Unknown Content-Range syntax: ",a);return{firstBytePosition:parseInt(b[1],10),lastBytePosition:parseInt(b[2],10),instanceLength:b[3]?parseInt(b[3],10):null}}return null}},{key:"loadRange",value:function(a,b){var c=this;c._fileData.hasDataRange(a[0],
|
||||
Math.min(c._size,a[1]))?setTimeout(b.onSuccess,1):(a=this._roundRangeToChunkMultiple(a),a[1]=Math.min(c._size,a[1]),this._makeXHRRequest("GET",a,{onSuccess:function(d){d=c._getXhrResponseContent(d);c._fileData.addData(a[0],d);b.onSuccess()},onError:b.onError}))}},{key:"_roundRangeToChunkMultiple",value:function(a){return[a[0],a[0]+1024*Math.ceil((a[1]-a[0]+1)/1024)-1]}},{key:"_makeXHRRequest",value:function(a,c,d){var f=this._createXHRObject(),h=function(){if(200===f.status||206===f.status)d.onSuccess(f);
|
||||
else if(d.onError)d.onError({type:"xhr",info:"Unexpected HTTP status "+f.status+".",xhr:f});f=null};"undefined"!==typeof f.onload?(f.onload=h,f.onerror=function(){if(d.onError)d.onError({type:"xhr",info:"Generic XHR error, check xhr object.",xhr:f})}):f.onreadystatechange=function(){4===f.readyState&&h()};b._config.timeoutInSec&&(f.timeout=1E3*b._config.timeoutInSec,f.ontimeout=function(){if(d.onError)d.onError({type:"xhr",info:"Timeout after "+f.timeout/1E3+"s. Use jsmediatags.Config.setXhrTimeout to override.",
|
||||
xhr:f})});f.open(a,this._url);f.overrideMimeType("text/plain; charset=x-user-defined");c&&this._setRequestHeader(f,"Range","bytes="+c[0]+"-"+c[1]);this._setRequestHeader(f,"If-Modified-Since","Sat, 01 Jan 1970 00:00:00 GMT");f.send(null)}},{key:"_setRequestHeader",value:function(a,c,d){0>b._config.disallowedXhrHeaders.indexOf(c.toLowerCase())&&a.setRequestHeader(c,d)}},{key:"_hasResponseHeader",value:function(a,b){var c=a.getAllResponseHeaders();if(!c)return!1;for(var c=c.split("\r\n"),d=[],f=0;f<
|
||||
c.length;f++)d[f]=c[f].split(":")[0].toLowerCase();return 0<=d.indexOf(b.toLowerCase())}},{key:"_getResponseHeader",value:function(a,b){return this._hasResponseHeader(a,b)?a.getResponseHeader(b):null}},{key:"getByteAt",value:function(a){return this._fileData.getByteAt(a).charCodeAt(0)&255}},{key:"_createXHRObject",value:function(){if("undefined"===typeof window)return new (f("xhr2").XMLHttpRequest);if(window.XMLHttpRequest)return new window.XMLHttpRequest;throw Error("XMLHttpRequest is not supported");
|
||||
}}],[{key:"canReadFile",value:function(a){return"string"===typeof a&&/^[a-z]+:\/\//i.test(a)}},{key:"setConfig",value:function(a){for(var b in a)a.hasOwnProperty(b)&&(this._config[b]=a[b]);a=this._config.disallowedXhrHeaders;for(b=0;b<a.length;b++)a[b]=a[b].toLowerCase()}}]);return b}(f("./MediaFileReader"));m._config={avoidHeadRequests:!1,disallowedXhrHeaders:[],timeoutInSec:30};h.exports=m},{"./ChunkedFileData":5,"./MediaFileReader":10,xhr2:2}],14:[function(f,h,m){function k(a,b){if(!(a instanceof
|
||||
b))throw new TypeError("Cannot call a class as a function");}function l(a,b){var c=0>a.offset&&(-a.offset>b||0<a.offset+a.length);return!(0<=a.offset&&a.offset+a.length>=b||c)}var d=function(){function a(b,c){for(var d=0;d<c.length;d++){var e=c[d];e.enumerable=e.enumerable||!1;e.configurable=!0;"value"in e&&(e.writable=!0);Object.defineProperty(b,e.key,e)}}return function(b,c,d){c&&a(b.prototype,c);d&&a(b,d);return b}}();f("./MediaFileReader");m=f("./NodeFileReader");var c=f("./XhrFileReader"),b=
|
||||
f("./BlobFileReader"),a=f("./ArrayFileReader");f("./MediaTagReader");var e=f("./ID3v1TagReader"),g=f("./ID3v2TagReader");f=f("./MP4TagReader");var p=[],q=[],r=function(){function a(b){k(this,a);this._file=b}d(a,[{key:"setTagsToRead",value:function(a){this._tagsToRead=a;return this}},{key:"setFileReader",value:function(a){this._fileReader=a;return this}},{key:"setTagReader",value:function(a){this._tagReader=a;return this}},{key:"read",value:function(a){var b=new (this._getFileReader())(this._file),
|
||||
c=this;b.init({onSuccess:function(){c._getTagReader(b,{onSuccess:function(d){(new d(b)).setTagsToRead(c._tagsToRead).read(a)},onError:a.onError})},onError:a.onError})}},{key:"_getFileReader",value:function(){return this._fileReader?this._fileReader:this._findFileReader()}},{key:"_findFileReader",value:function(){for(var a=0;a<p.length;a++)if(p[a].canReadFile(this._file))return p[a];throw Error("No suitable file reader found for ",this._file);}},{key:"_getTagReader",value:function(a,b){if(this._tagReader){var c=
|
||||
this._tagReader;setTimeout(function(){b.onSuccess(c)},1)}else this._findTagReader(a,b)}},{key:"_findTagReader",value:function(a,b){for(var c=[],d=[],e=a.getSize(),f=0;f<q.length;f++){var g=q[f].getTagIdentifierByteRange();l(g,e)&&(0<=g.offset&&g.offset<e/2||0>g.offset&&g.offset<-e/2?c.push(q[f]):d.push(q[f]))}var h=!1,f={onSuccess:function(){if(h){for(var c=0;c<q.length;c++){var d=q[c].getTagIdentifierByteRange();if(l(d,e)){try{var f=a.getBytesAt(0<=d.offset?d.offset:d.offset+e,d.length)}catch(g){if(b.onError){b.onError({type:"fileReader",
|
||||
info:g.message});return}}if(q[c].canReadTagFormat(f)){b.onSuccess(q[c]);return}}}if(b.onError)b.onError({type:"tagFormat",info:"No suitable tag reader found"})}else h=!0},onError:b.onError};this._loadTagIdentifierRanges(a,c,f);this._loadTagIdentifierRanges(a,d,f)}},{key:"_loadTagIdentifierRanges",value:function(a,b,c){if(0===b.length)setTimeout(c.onSuccess,1);else{for(var d=[Number.MAX_VALUE,0],e=a.getSize(),f=0;f<b.length;f++){var g=b[f].getTagIdentifierByteRange(),h=0<=g.offset?g.offset:g.offset+
|
||||
e,g=h+g.length-1;d[0]=Math.min(h,d[0]);d[1]=Math.max(g,d[1])}a.loadRange(d,c)}}}]);return a}(),w=function(){function a(){k(this,a)}d(a,null,[{key:"addFileReader",value:function(b){p.push(b);return a}},{key:"addTagReader",value:function(b){q.push(b);return a}},{key:"removeTagReader",value:function(b){b=q.indexOf(b);0<=b&&q.splice(b,1);return a}},{key:"EXPERIMENTAL_avoidHeadRequests",value:function(){c.setConfig({avoidHeadRequests:!0})}},{key:"setDisallowedXhrHeaders",value:function(a){c.setConfig({disallowedXhrHeaders:a})}},
|
||||
{key:"setXhrTimeoutInSec",value:function(a){c.setConfig({timeoutInSec:a})}}]);return a}();w.addFileReader(c).addFileReader(b).addFileReader(a).addTagReader(g).addTagReader(e).addTagReader(f);"undefined"!==typeof process&&w.addFileReader(m);h.exports={read:function(a,b){(new r(a)).read(b)},Reader:r,Config:w}},{"./ArrayFileReader":3,"./BlobFileReader":4,"./ID3v1TagReader":6,"./ID3v2TagReader":8,"./MP4TagReader":9,"./MediaFileReader":10,"./MediaTagReader":11,"./NodeFileReader":1,"./XhrFileReader":13}]},
|
||||
{},[14])(14)});
|
@ -30,32 +30,20 @@ class MP3FileHandler extends DataHandlerExtension {
|
||||
* @return Image|null
|
||||
*/
|
||||
protected function create_image_from_data($filename, $metadata) {
|
||||
global $config;
|
||||
|
||||
$image = new Image();
|
||||
|
||||
// FIXME: need more flash format specs :|
|
||||
$image->width = 0;
|
||||
$image->height = 0;
|
||||
//NOTE: No need to set width/height as we don't use it.
|
||||
$image->width = 1;
|
||||
$image->height = 1;
|
||||
|
||||
$image->filesize = $metadata['size'];
|
||||
$image->hash = $metadata['hash'];
|
||||
|
||||
//Cheat by using the filename to store artist/title if available
|
||||
require_once('lib/getid3/getid3/getid3.php');
|
||||
$getID3 = new getID3;
|
||||
$ThisFileInfo = $getID3->analyze($filename, TRUE);
|
||||
|
||||
if (isset($ThisFileInfo['tags']['id3v2']['artist'][0]) && isset($ThisFileInfo['tags']['id3v2']['title'][0])) {
|
||||
$image->filename = $ThisFileInfo['tags']['id3v2']['artist'][0]." - ".$ThisFileInfo['tags']['id3v2']['title'][0].".mp3";
|
||||
} else if (isset($ThisFileInfo['tags']['id3v1']['artist'][0]) && isset($ThisFileInfo['tags']['id3v1']['title'][0])) {
|
||||
$image->filename = $ThisFileInfo['tags']['id3v1']['artist'][0]." - ".$ThisFileInfo['tags']['id3v1']['title'][0].".mp3";
|
||||
} else {
|
||||
//Filename is renamed to "artist - title.mp3" when the user requests download by using the download attribute & jsmediatags.js
|
||||
$image->filename = $metadata['filename'];
|
||||
}
|
||||
|
||||
$image->ext = $metadata['extension'];
|
||||
$image->tag_array = $metadata['tags'];
|
||||
$image->tag_array = is_array($metadata['tags']) ? $metadata['tags'] : Tag::explode($metadata['tags']);
|
||||
$image->source = $metadata['source'];
|
||||
|
||||
return $image;
|
||||
@ -66,15 +54,15 @@ class MP3FileHandler extends DataHandlerExtension {
|
||||
* @return bool
|
||||
*/
|
||||
protected function check_contents($file) {
|
||||
$success = FALSE;
|
||||
|
||||
if (file_exists($file)) {
|
||||
require_once('lib/getid3/getid3/getid3.php');
|
||||
$getID3 = new getID3;
|
||||
$ThisFileInfo = $getID3->analyze($file, TRUE);
|
||||
if (isset($ThisFileInfo['fileformat']) && $ThisFileInfo['fileformat'] == "mp3") {
|
||||
return TRUE;
|
||||
$mimeType = mime_content_type($file);
|
||||
|
||||
$success = ($mimeType == 'audio/mpeg');
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
return $success;
|
||||
}
|
||||
}
|
||||
|
||||
|
14
ext/handle_mp3/style.css
Normal file
14
ext/handle_mp3/style.css
Normal file
@ -0,0 +1,14 @@
|
||||
.audio_image {
|
||||
min-width: 300px;
|
||||
width: 65%;
|
||||
}
|
||||
/* Hide download button as we use our own */
|
||||
audio::-internal-media-controls-download-button {
|
||||
display:none;
|
||||
}
|
||||
audio::-webkit-media-controls-enclosure {
|
||||
overflow:hidden;
|
||||
}
|
||||
audio::-webkit-media-controls-panel {
|
||||
width: calc(100% + 30px); /* Adjust as needed */
|
||||
}
|
@ -6,17 +6,35 @@ class MP3FileHandlerTheme extends Themelet {
|
||||
$ilink = $image->get_image_link();
|
||||
$fname = url_escape($image->filename); //Most of the time this will be the title/artist of the song.
|
||||
$html = "
|
||||
<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'
|
||||
codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0'
|
||||
width='400' height='15'>
|
||||
<param name='movie' value='$data_href/ext/handle_mp3/xspf_player_slim.swf?song_url=$ilink'/>
|
||||
<param name='quality' value='high' />
|
||||
<embed src='$data_href/ext/handle_mp3/xspf_player_slim.swf?song_url=$ilink&song_title=$fname' quality='high'
|
||||
pluginspage='http://www.macromedia.com/go/getflashplayer'
|
||||
width='400' height='15'
|
||||
type='application/x-shockwave-flash'></embed>
|
||||
</object>
|
||||
<p><a href='$ilink'>Download</a>";
|
||||
<audio controls class='shm-main-image audio_image' id='main_image' alt='main image'>
|
||||
<source src=\"$ilink\" type=\"audio/mpeg\">
|
||||
Your browser does not support the audio element.
|
||||
</audio>
|
||||
<p>Title: <span id='audio-title'>???</span> | Artist: <span id='audio-artist'>???</span></p>
|
||||
|
||||
<script>
|
||||
$('#main_image').prop('volume', 0.25);
|
||||
|
||||
var jsmediatags = window.jsmediatags;
|
||||
jsmediatags.read(location.origin+base_href+'$ilink', {
|
||||
onSuccess: function(tag) {
|
||||
var artist = tag.tags.artist,
|
||||
title = tag.tags.title;
|
||||
|
||||
$('#audio-title').text(title);
|
||||
$('#audio-artist').text(artist);
|
||||
|
||||
$('#audio-download').prop('download', (artist+' - '+title).substr(0, 250)+'.mp3');
|
||||
},
|
||||
onError: function(error) {
|
||||
console.log(error);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<p><a href='$ilink' id='audio-download'>Download</a>";
|
||||
|
||||
$page->add_html_header("<script src='{$data_href}/ext/handle_mp3/lib/jsmediatags.min.js' type='text/javascript'></script>");
|
||||
$page->add_block(new Block("Music", $html, "main", 10));
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
Copyright (c) 2005, Fabricio Zuardi
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
Binary file not shown.
@ -35,7 +35,7 @@ class PixelFileHandler extends DataHandlerExtension {
|
||||
$image->hash = $metadata['hash'];
|
||||
$image->filename = (($pos = strpos($metadata['filename'],'?')) !== false) ? substr($metadata['filename'],0,$pos) : $metadata['filename'];
|
||||
$image->ext = (($pos = strpos($metadata['extension'],'?')) !== false) ? substr($metadata['extension'],0,$pos) : $metadata['extension'];
|
||||
$image->tag_array = $metadata['tags'];
|
||||
$image->tag_array = is_array($metadata['tags']) ? $metadata['tags'] : Tag::explode($metadata['tags']);
|
||||
$image->source = $metadata['source'];
|
||||
|
||||
return $image;
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Name: Handle SVG
|
||||
* Author: Shish <webmaster@shishnet.org>
|
||||
* Link: http://code.shishnet.org/shimmie2/
|
||||
* Description: Handle SVG files. (No thumbnail is generated for SVG files)
|
||||
* Description: Handle static SVG files. (No thumbnail is generated for SVG files)
|
||||
*/
|
||||
|
||||
class SVGFileHandler extends Extension {
|
||||
@ -75,7 +75,7 @@ class SVGFileHandler extends Extension {
|
||||
$image->hash = $metadata['hash'];
|
||||
$image->filename = $metadata['filename'];
|
||||
$image->ext = $metadata['extension'];
|
||||
$image->tag_array = $metadata['tags'];
|
||||
$image->tag_array = is_array($metadata['tags']) ? $metadata['tags'] : Tag::explode($metadata['tags']);
|
||||
$image->source = $metadata['source'];
|
||||
|
||||
return $image;
|
||||
|
@ -5,9 +5,7 @@ class SVGFileHandlerTheme extends Themelet {
|
||||
$ilink = make_link("get_svg/{$image->id}/{$image->id}.svg");
|
||||
// $ilink = $image->get_image_link();
|
||||
$html = "
|
||||
<object data='$ilink' type='image/svg+xml' data-width='{$image->width}' data-height='{$image->height}' id='main_image' class='shm-main-image'>
|
||||
<embed src='$ilink' type='image/svg+xml' />
|
||||
</object>
|
||||
<img src='$ilink' id='main_image' class='shm-main-image' data-width='{$image->width}' data-height='{$image->height}' />
|
||||
";
|
||||
$page->add_block(new Block("Image", $html, "main", 10));
|
||||
}
|
||||
|
@ -12,8 +12,6 @@
|
||||
* OGV, WEBM: HTML5<br>
|
||||
* MP4's flash fallback is forced with a bit of Javascript as some browsers won't fallback if they can't play H.264.
|
||||
* In the future, it may be necessary to change the user agent checks to reflect the current state of H.264 support.<br><br>
|
||||
* Made possible by:<br>
|
||||
* <a href='http://getid3.sourceforge.net/'>getID3()</a> - Gets media information with PHP (no bulky FFMPEG API required).<br>
|
||||
*/
|
||||
|
||||
class VideoFileHandler extends DataHandlerExtension {
|
||||
@ -145,31 +143,25 @@ class VideoFileHandler extends DataHandlerExtension {
|
||||
* @return Image
|
||||
*/
|
||||
protected function create_image_from_data($filename, $metadata) {
|
||||
|
||||
$image = new Image();
|
||||
|
||||
require_once('lib/getid3/getid3/getid3.php');
|
||||
$getID3 = new getID3;
|
||||
$ThisFileInfo = $getID3->analyze($filename);
|
||||
//NOTE: No need to set width/height as we don't use it.
|
||||
$image->width = 1;
|
||||
$image->height = 1;
|
||||
|
||||
if (isset($ThisFileInfo['video']['resolution_x']) && isset($ThisFileInfo['video']['resolution_y'])) {
|
||||
$image->width = $ThisFileInfo['video']['resolution_x'];
|
||||
$image->height = $ThisFileInfo['video']['resolution_y'];
|
||||
} else {
|
||||
$image->width = 0;
|
||||
$image->height = 0;
|
||||
}
|
||||
|
||||
switch ($ThisFileInfo['mime_type']) {
|
||||
switch (mime_content_type($filename)) {
|
||||
case "video/webm":
|
||||
$image->ext = "webm";
|
||||
break;
|
||||
case "video/quicktime":
|
||||
case "video/mp4":
|
||||
$image->ext = "mp4";
|
||||
break;
|
||||
case "application/ogg":
|
||||
case "video/ogg":
|
||||
$image->ext = "ogv";
|
||||
break;
|
||||
case "video/flv":
|
||||
$image->ext = "flv";
|
||||
break;
|
||||
case "video/x-flv":
|
||||
$image->ext = "flv";
|
||||
break;
|
||||
@ -178,7 +170,7 @@ class VideoFileHandler extends DataHandlerExtension {
|
||||
$image->filesize = $metadata['size'];
|
||||
$image->hash = $metadata['hash'];
|
||||
$image->filename = $metadata['filename'];
|
||||
$image->tag_array = $metadata['tags'];
|
||||
$image->tag_array = is_array($metadata['tags']) ? $metadata['tags'] : Tag::explode($metadata['tags']);
|
||||
$image->source = $metadata['source'];
|
||||
|
||||
return $image;
|
||||
@ -189,20 +181,20 @@ class VideoFileHandler extends DataHandlerExtension {
|
||||
* @return bool
|
||||
*/
|
||||
protected function check_contents($file) {
|
||||
$success = FALSE;
|
||||
if (file_exists($file)) {
|
||||
require_once('lib/getid3/getid3/getid3.php');
|
||||
$getID3 = new getID3;
|
||||
$ThisFileInfo = $getID3->analyze($file);
|
||||
if (isset($ThisFileInfo['mime_type']) && (
|
||||
$ThisFileInfo['mime_type'] == "video/webm" ||
|
||||
$ThisFileInfo['mime_type'] == "video/quicktime" ||
|
||||
$ThisFileInfo['mime_type'] == "application/ogg" ||
|
||||
$ThisFileInfo['mime_type'] == 'video/x-flv')
|
||||
) {
|
||||
return TRUE;
|
||||
$mimeType = mime_content_type($file);
|
||||
|
||||
$success = in_array($mimeType, [
|
||||
'video/webm',
|
||||
'video/mp4',
|
||||
'video/ogg',
|
||||
'video/flv',
|
||||
'video/x-flv'
|
||||
]);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
return $success;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,19 +41,18 @@ class VideoFileHandlerTheme extends Themelet {
|
||||
//FLV doesn't support <video>.
|
||||
$html .= $html_fallback;
|
||||
} else {
|
||||
$html .= "
|
||||
<video controls class='shm-main-image' id='main_image' alt='main image'"
|
||||
. ($autoplay ? ' autoplay' : '')
|
||||
. ($loop ? ' loop' : '')
|
||||
. " data-width='{$image->width}' "
|
||||
. " data-height='{$image->height}'>
|
||||
$autoplay = ($autoplay ? ' autoplay' : '');
|
||||
$loop = ($loop ? ' loop' : '');
|
||||
|
||||
$html .= "
|
||||
<video controls class='shm-main-image' id='main_image' alt='main image' {$autoplay} {$loop} style='max-width: 100%'>
|
||||
<source src='{$ilink}' type='{$supportedExts[$ext]}'>
|
||||
|
||||
<!-- If browser doesn't support filetype, fallback to flash -->
|
||||
{$html_fallback}
|
||||
|
||||
</video>";
|
||||
</video>
|
||||
<script>$('#main_image').prop('volume', 0.25);</script>
|
||||
";
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -376,7 +376,7 @@ class ImageIO extends Extension {
|
||||
$image->tag_array = array();
|
||||
send_event(new TagSetEvent($image, $tags_to_set));
|
||||
|
||||
if($image->source) {
|
||||
if($image->source !== null) {
|
||||
log_info("core-image", "Source for Image #{$image->id} set to: {$image->source}");
|
||||
}
|
||||
}
|
||||
|
@ -161,14 +161,14 @@
|
||||
class SearchTermParseEvent extends Event {
|
||||
/** @var null|string */
|
||||
public $term = null;
|
||||
/** @var null */
|
||||
/** @var string[] */
|
||||
public $context = array();
|
||||
/** @var \Querylet[] */
|
||||
public $querylets = array();
|
||||
|
||||
/**
|
||||
* @param string|null $term
|
||||
* @param array $context
|
||||
* @param string[] $context
|
||||
*/
|
||||
public function __construct($term, array $context) {
|
||||
$this->term = $term;
|
||||
@ -225,6 +225,7 @@ class PostListBuildingEvent extends Event {
|
||||
}
|
||||
|
||||
class Index extends Extension {
|
||||
/** @var int */
|
||||
private $stpen = 0; // search term parse event number
|
||||
|
||||
public function onInitExt(InitExtEvent $event) {
|
||||
|
@ -31,7 +31,7 @@ class Oekaki extends Extension {
|
||||
$metadata = array();
|
||||
$metadata['filename'] = 'oekaki.png';
|
||||
$metadata['extension'] = $pathinfo['extension'];
|
||||
$metadata['tags'] = 'oekaki tagme';
|
||||
$metadata['tags'] = Tag::explode('oekaki tagme');
|
||||
$metadata['source'] = null;
|
||||
$duev = new DataUploadEvent($tmpname, $metadata);
|
||||
send_event($duev);
|
||||
|
@ -59,6 +59,11 @@ class _SafeOuroborosImage
|
||||
* @var integer
|
||||
*/
|
||||
public $width = null;
|
||||
/**
|
||||
* File extension
|
||||
* @var string
|
||||
*/
|
||||
public $file_ext = '';
|
||||
/**
|
||||
* File Size in bytes
|
||||
* @var integer
|
||||
@ -189,7 +194,7 @@ class _SafeOuroborosImage
|
||||
* Constructor
|
||||
* @param Image $img
|
||||
*/
|
||||
function __construct(Image $img)
|
||||
public function __construct(Image $img)
|
||||
{
|
||||
global $config;
|
||||
// author
|
||||
@ -343,7 +348,7 @@ class _SafeOuroborosTag
|
||||
public $name = '';
|
||||
public $type = 0;
|
||||
|
||||
function __construct(array $tag)
|
||||
public function __construct(array $tag)
|
||||
{
|
||||
$this->count = $tag['count'];
|
||||
$this->id = $tag['id'];
|
||||
@ -495,7 +500,7 @@ class OuroborosAPI extends Extension
|
||||
}
|
||||
}
|
||||
$meta = array();
|
||||
$meta['tags'] = $post->tags;
|
||||
$meta['tags'] = is_array($post->tags) ? $post->tags : Tag::explode($post->tags);
|
||||
$meta['source'] = $post->source;
|
||||
if (defined('ENABLED_EXTS')) {
|
||||
if (strstr(ENABLED_EXTS, 'rating') !== false) {
|
||||
@ -531,7 +536,8 @@ class OuroborosAPI extends Extension
|
||||
if (!is_null($img)) {
|
||||
$handler = $config->get_string("upload_collision_handler");
|
||||
if($handler == "merge") {
|
||||
$merged = array_merge(Tag::explode($post->tags), $img->get_tag_array());
|
||||
$postTags = is_array($post->tags) ? $post->tags : Tag::explode($post->tags);
|
||||
$merged = array_merge($postTags, $img->get_tag_array());
|
||||
send_event(new TagSetEvent($img, $merged));
|
||||
|
||||
// This is really the only thing besides tags we should care
|
||||
@ -771,6 +777,9 @@ class OuroborosAPI extends Extension
|
||||
$page->set_data($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*/
|
||||
private function createItemXML(XMLWriter &$xml, $type, $item)
|
||||
{
|
||||
$xml->startElement($type);
|
||||
|
@ -242,7 +242,7 @@ class Ratings extends Extension {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $context
|
||||
* @param string[] $context
|
||||
* @return bool
|
||||
*/
|
||||
private function no_rating_query($context) {
|
||||
|
@ -157,6 +157,11 @@ class SetupBlock extends Block {
|
||||
$this->body .= "<input type='hidden' name='_type_$name' value='int'>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string[] $options
|
||||
* @param null|string $label
|
||||
*/
|
||||
public function add_choice_option($name, $options, $label=null) {
|
||||
global $config;
|
||||
$current = $config->get_string($name);
|
||||
@ -176,6 +181,11 @@ class SetupBlock extends Block {
|
||||
$this->body .= $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string[] $options
|
||||
* @param null|string $label
|
||||
*/
|
||||
public function add_multichoice_option($name, $options, $label=null) {
|
||||
global $config;
|
||||
$current = $config->get_array($name);
|
||||
|
@ -83,18 +83,6 @@ class TagEditCloud extends Extension {
|
||||
}
|
||||
|
||||
switch($sort_method) {
|
||||
case 'a':
|
||||
case 'p':
|
||||
default:
|
||||
$order_by = $sort_method == 'a' ? "tag" : "count DESC";
|
||||
$tag_data = $database->get_all("
|
||||
SELECT tag, FLOOR(LN(LN(count - :tag_min1 + 1)+1)*150)/200 AS scaled, count
|
||||
FROM tags
|
||||
WHERE count >= :tag_min2
|
||||
ORDER BY $order_by
|
||||
LIMIT :limit",
|
||||
array("tag_min1" => $tags_min, "tag_min2" => $tags_min, "limit" => $max_count));
|
||||
break;
|
||||
case 'r':
|
||||
$relevant_tags = array_diff($image->get_tag_array(),$ignore_tags);
|
||||
if(count($relevant_tags) == 0) {
|
||||
@ -113,6 +101,18 @@ class TagEditCloud extends Extension {
|
||||
LIMIT :limit",
|
||||
array("tag_min1" => $tags_min, "tag_min2" => $tags_min, "limit" => $max_count));
|
||||
break;
|
||||
case 'a':
|
||||
case 'p':
|
||||
default:
|
||||
$order_by = $sort_method == 'a' ? "tag" : "count DESC";
|
||||
$tag_data = $database->get_all("
|
||||
SELECT tag, FLOOR(LN(LN(count - :tag_min1 + 1)+1)*150)/200 AS scaled, count
|
||||
FROM tags
|
||||
WHERE count >= :tag_min2
|
||||
ORDER BY $order_by
|
||||
LIMIT :limit",
|
||||
array("tag_min1" => $tags_min, "tag_min2" => $tags_min, "limit" => $max_count));
|
||||
break;
|
||||
}
|
||||
|
||||
$counter = 1;
|
||||
|
@ -35,6 +35,29 @@ class TagListTheme extends Themelet {
|
||||
|
||||
// =======================================================================
|
||||
|
||||
protected function get_tag_list_preamble() {
|
||||
global $config;
|
||||
|
||||
$tag_info_link_is_visible = !is_null($config->get_string('info_link'));
|
||||
$tag_count_is_visible = $config->get_bool("tag_list_numbers");
|
||||
|
||||
return '
|
||||
<table class="tag_list sortable">
|
||||
<colgroup>' .
|
||||
($tag_info_link_is_visible ? '<col class="tag_info_link_column">' : '') .
|
||||
('<col class="tag_name_column">') .
|
||||
($tag_count_is_visible ? '<col class="tag_count_column">' : '') . '
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>' .
|
||||
($tag_info_link_is_visible ? '<th class="tag_info_link_cell"></th>' : '') .
|
||||
('<th class="tag_name_cell">Tag</th>') .
|
||||
($tag_count_is_visible ? '<th class="tag_count_cell">#</th>' : '') . '
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>';
|
||||
}
|
||||
|
||||
/*
|
||||
* $tag_infos = array(
|
||||
* array('tag' => $tag, 'count' => $number_of_uses),
|
||||
@ -61,9 +84,9 @@ class TagListTheme extends Themelet {
|
||||
$category = $split[0];
|
||||
$tag_html = $split[1];
|
||||
if(!isset($tag_categories_html[$category])) {
|
||||
$tag_categories_html[$category] = '';
|
||||
$tag_categories_html[$category] = $this->get_tag_list_preamble();
|
||||
}
|
||||
$tag_categories_html[$category] .= $tag_html . '<br />';
|
||||
$tag_categories_html[$category] .= "<tr>$tag_html</tr>";
|
||||
|
||||
if(!isset($tag_categories_count[$category])) {
|
||||
$tag_categories_count[$category] = 0;
|
||||
@ -71,6 +94,10 @@ class TagListTheme extends Themelet {
|
||||
$tag_categories_count[$category] += 1;
|
||||
}
|
||||
|
||||
foreach(array_keys($tag_categories_html) as $category) {
|
||||
$tag_categories_html[$category] .= '</tbody></table>';
|
||||
}
|
||||
|
||||
asort($tag_categories_html);
|
||||
if(isset($tag_categories_html[' '])) $main_html = $tag_categories_html[' ']; else $main_html = null;
|
||||
unset($tag_categories_html[' ']);
|
||||
@ -99,10 +126,8 @@ class TagListTheme extends Themelet {
|
||||
* ...
|
||||
* )
|
||||
*/
|
||||
public function display_related_block(Page $page, $tag_infos) {
|
||||
global $config;
|
||||
|
||||
if($config->get_string('tag_list_related_sort') == 'alphabetical') asort($tag_infos);
|
||||
private function get_tag_list_html($tag_infos, $sort) {
|
||||
if($sort == 'alphabetical') asort($tag_infos);
|
||||
|
||||
if(class_exists('TagCategories')) {
|
||||
$this->tagcategories = new TagCategories;
|
||||
@ -111,15 +136,32 @@ class TagListTheme extends Themelet {
|
||||
else {
|
||||
$tag_category_dict = array();
|
||||
}
|
||||
$main_html = '';
|
||||
$main_html = $this->get_tag_list_preamble();
|
||||
|
||||
foreach($tag_infos as $row) {
|
||||
$split = $this->return_tag($row, $tag_category_dict);
|
||||
//$category = $split[0];
|
||||
$tag_html = $split[1];
|
||||
$main_html .= $tag_html . '<br />';
|
||||
$main_html .= "<tr>$tag_html</tr>";
|
||||
}
|
||||
|
||||
$main_html .= '</tbody></table>';
|
||||
|
||||
return $main_html;
|
||||
}
|
||||
|
||||
/*
|
||||
* $tag_infos = array(
|
||||
* array('tag' => $tag, 'count' => $number_of_uses),
|
||||
* ...
|
||||
* )
|
||||
*/
|
||||
public function display_related_block(Page $page, $tag_infos) {
|
||||
global $config;
|
||||
|
||||
$main_html = $this->get_tag_list_html(
|
||||
$tag_infos, $config->get_string('tag_list_related_sort'));
|
||||
|
||||
if($config->get_string('tag_list_image_type')=="tags") {
|
||||
$page->add_block(new Block("Tags", $main_html, "left", 10));
|
||||
}
|
||||
@ -138,25 +180,10 @@ class TagListTheme extends Themelet {
|
||||
public function display_popular_block(Page $page, $tag_infos) {
|
||||
global $config;
|
||||
|
||||
if($config->get_string('tag_list_popular_sort') == 'alphabetical') asort($tag_infos);
|
||||
|
||||
if(class_exists('TagCategories')) {
|
||||
$this->tagcategories = new TagCategories;
|
||||
$tag_category_dict = $this->tagcategories->getKeyedDict();
|
||||
}
|
||||
else {
|
||||
$tag_category_dict = array();
|
||||
}
|
||||
$main_html = '';
|
||||
|
||||
foreach($tag_infos as $row) {
|
||||
$split = self::return_tag($row, $tag_category_dict);
|
||||
//$category = $split[0];
|
||||
$tag_html = $split[1];
|
||||
$main_html .= $tag_html . '<br />';
|
||||
}
|
||||
|
||||
$main_html = $this->get_tag_list_html(
|
||||
$tag_infos, $config->get_string('tag_list_popular_sort'));
|
||||
$main_html .= " <br><a class='more' href='".make_link("tags")."'>Full List</a>\n";
|
||||
|
||||
$page->add_block(new Block("Popular Tags", $main_html, "left", 60));
|
||||
}
|
||||
|
||||
@ -170,25 +197,10 @@ class TagListTheme extends Themelet {
|
||||
public function display_refine_block(Page $page, $tag_infos, $search) {
|
||||
global $config;
|
||||
|
||||
if($config->get_string('tag_list_popular_sort') == 'alphabetical') asort($tag_infos);
|
||||
|
||||
if(class_exists('TagCategories')) {
|
||||
$this->tagcategories = new TagCategories;
|
||||
$tag_category_dict = $this->tagcategories->getKeyedDict();
|
||||
}
|
||||
else {
|
||||
$tag_category_dict = array();
|
||||
}
|
||||
$main_html = '';
|
||||
|
||||
foreach($tag_infos as $row) {
|
||||
$split = self::return_tag($row, $tag_category_dict);
|
||||
//$category = $split[0];
|
||||
$tag_html = $split[1];
|
||||
$main_html .= $tag_html . '<br />';
|
||||
}
|
||||
|
||||
$main_html = $this->get_tag_list_html(
|
||||
$tag_infos, $config->get_string('tag_list_popular_sort'));
|
||||
$main_html .= " <br><a class='more' href='".make_link("tags")."'>Full List</a>\n";
|
||||
|
||||
$page->add_block(new Block("refine Search", $main_html, "left", 60));
|
||||
}
|
||||
|
||||
@ -217,13 +229,13 @@ class TagListTheme extends Themelet {
|
||||
// if($n++) $display_html .= "\n<br/>";
|
||||
if(!is_null($config->get_string('info_link'))) {
|
||||
$link = html_escape(str_replace('$tag', url_escape($tag), $config->get_string('info_link')));
|
||||
$display_html .= ' <a class="tag_info_link'.$tag_category_css.'" '.$tag_category_style.'href="'.$link.'">?</a>';
|
||||
$display_html .= '<td class="tag_info_link_cell"> <a class="tag_info_link'.$tag_category_css.'" '.$tag_category_style.'href="'.$link.'">?</a></td>';
|
||||
}
|
||||
$link = $this->tag_link($row['tag']);
|
||||
$display_html .= ' <a class="tag_name'.$tag_category_css.'" '.$tag_category_style.'href="'.$link.'">'.$h_tag_no_underscores.'</a>';
|
||||
$display_html .= '<td class="tag_name_cell"> <a class="tag_name'.$tag_category_css.'" '.$tag_category_style.'href="'.$link.'">'.$h_tag_no_underscores.'</a></td>';
|
||||
|
||||
if($config->get_bool("tag_list_numbers")) {
|
||||
$display_html .= " <span class='tag_count'>$count</span>";
|
||||
$display_html .= "<td class='tag_count_cell'> <span class='tag_count'>$count</span></td>";
|
||||
}
|
||||
|
||||
return array($category, $display_html);
|
||||
|
@ -129,6 +129,7 @@ class Upgrade extends Extension {
|
||||
}
|
||||
}
|
||||
|
||||
/** @return int */
|
||||
public function get_priority() {return 5;}
|
||||
}
|
||||
|
||||
|
@ -29,18 +29,16 @@ else if(CA === 2) { // New Tags
|
||||
* jQuery should always active here, meaning we can use jQuery in this part of the bookmarklet.
|
||||
*/
|
||||
|
||||
if(document.getElementById("post_tag_string") !== null) {
|
||||
if(document.getElementById("image-container") !== null) {
|
||||
var imageContainer = $('#image-container')[0];
|
||||
if (typeof tag !== "ftp://ftp." && chk !==1) {
|
||||
var tag = $('#post_tag_string').text().replace(/\n/g, "");
|
||||
var tag = imageContainer.getAttribute('data-tags');
|
||||
}
|
||||
tag = tag.replace(/\+/g, "%2B");
|
||||
|
||||
var source = "http://" + document.location.hostname + document.location.href.match("\/posts\/[0-9]+");
|
||||
|
||||
var rlist = $('[name="post[rating]"]');
|
||||
for( var x=0; x < 3; x++){
|
||||
var rating = (rlist[x].checked === true ? rlist[x].value : rating);
|
||||
}
|
||||
var rating = imageContainer.getAttribute('data-rating');
|
||||
|
||||
var fileinfo = $('#sidebar > section:eq(3) > ul > :contains("Size") > a');
|
||||
var furl = "http://" + document.location.hostname + fileinfo.attr('href');
|
||||
@ -49,6 +47,7 @@ if(document.getElementById("post_tag_string") !== null) {
|
||||
|
||||
if(supext.search(furl.match("[a-zA-Z0-9]+$")[0]) !== -1){
|
||||
if(filesize <= maxsize){
|
||||
history.pushState(history.state, document.title, location.href);
|
||||
location.href = ste+furl+"&tags="+tag+"&rating="+rating+"&source="+source;
|
||||
}
|
||||
else{
|
||||
@ -61,15 +60,11 @@ if(document.getElementById("post_tag_string") !== null) {
|
||||
}
|
||||
|
||||
/*
|
||||
* konachan | sankakucomplex | gelbooru
|
||||
* konachan | sankakucomplex | gelbooru | etc.
|
||||
*/
|
||||
else if(document.getElementById('tag-sidebar') !== null) {
|
||||
if (typeof tag !== "ftp://ftp." && chk !==1) {
|
||||
if(document.location.href.search("sankakucomplex\\.com") >= 0 || document.location.href.search("gelbooru\\.com")){
|
||||
var tag = document.getElementById('tag-sidebar').innerText.replace(/ /g, "_").replace(/[\?_]*(.*?)_(\(\?\)_)?[0-9]+\n/g, "$1 ");
|
||||
}else{
|
||||
var tag = document.getElementById("post_tags").value;
|
||||
}
|
||||
var tag = document.getElementById('tag-sidebar').innerText.replace(/ /g, "_").replace(/[\?_]*(.*?)_(\(\?\)_)?[0-9]+$/gm, "$1 ");
|
||||
}
|
||||
tag = tag.replace(/\+/g, "%2B");
|
||||
|
||||
@ -77,21 +72,29 @@ else if(document.getElementById('tag-sidebar') !== null) {
|
||||
|
||||
var rating = document.getElementById("stats").innerHTML.match("Rating: ([a-zA-Z]+)")[1];
|
||||
|
||||
if(source.search("sankakucomplex\\.com") >= 0 || source.search("konachan\\.com") >= 0){
|
||||
if(document.getElementById('highres') !== null) {
|
||||
var fileinfo = document.getElementById("highres");
|
||||
//NOTE: If highres doesn't exist, post must be flash (only sankakucomplex has flash)
|
||||
}else if(source.search("gelbooru\\.com") >= 0){
|
||||
var fileinfo = document.getElementById('pfd').parentNode.parentNode.getElementsByTagName('a')[0];
|
||||
//gelbooru has no easy way to select the original image link, so we need to double check it is the correct link.
|
||||
fileinfo = (fileinfo.getAttribute('href') === "#" ? document.getElementById('pfd').parentNode.parentNode.getElementsByTagName('a')[1] : fileinfo);
|
||||
}else if(document.getElementById('pfd') !== null){
|
||||
// Try to find the "Original image" link in the options sidebar.
|
||||
var fileinfo;
|
||||
var nodes = document.getElementById('pfd').parentNode.parentNode.getElementsByTagName('a');
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var href = nodes[i].getAttribute('href');
|
||||
if (href === "#" || href === "javascript:;")
|
||||
continue;
|
||||
fileinfo = nodes[i];
|
||||
break;
|
||||
}
|
||||
fileinfo = fileinfo || document.getElementsByTagName('embed')[0]; //If fileinfo is null then image is most likely flash.
|
||||
}
|
||||
fileinfo = fileinfo || document.getElementsByTagName('embed')[0]; //If fileinfo is null then assume that the image is flash.
|
||||
var furl = fileinfo.href || fileinfo.src;
|
||||
furl = furl.split('?')[0]; // Remove trailing variables, if present.
|
||||
var fs = (fileinfo.innerText.match(/[0-9]+ (KB|MB)/) || ["0 KB"])[0].split(" ");
|
||||
var filesize = (fs[1] === "MB" ? fs[0] * 1024 : fs[0]);
|
||||
|
||||
if(supext.search(furl.match("[a-zA-Z0-9]+$")[0]) !== -1){
|
||||
if(filesize <= maxsize){
|
||||
history.pushState(history.state, document.title, location.href);
|
||||
location.href = ste+furl+"&tags="+tag+"&rating="+rating+"&source="+source;
|
||||
}
|
||||
else{
|
||||
@ -128,6 +131,7 @@ else if(document.getElementsByTagName("title")[0].innerHTML.search("Image [0-9.-
|
||||
if(tag.search(/\bflash\b/) === -1) {
|
||||
var img = document.getElementById("main_image").src;
|
||||
if(supext.search(img.match(".*\\.([a-z0-9]+)")[1]) !== -1) {
|
||||
history.pushState(history.state, document.title, location.href);
|
||||
location.href = ste+img+"&tags="+tag+"&source="+source;
|
||||
}
|
||||
else{
|
||||
@ -137,6 +141,7 @@ else if(document.getElementsByTagName("title")[0].innerHTML.search("Image [0-9.-
|
||||
else{
|
||||
var mov = document.location.hostname+document.getElementsByName("movie")[0].value;
|
||||
if(supext.search("swf") !== -1) {
|
||||
history.pushState(history.state, document.title, location.href);
|
||||
location.href = ste+mov+"&tags="+tag+"&source="+source;
|
||||
}
|
||||
else{
|
||||
|
@ -403,11 +403,14 @@ class Upload extends Extension {
|
||||
$metadata['tags'] = $tags;
|
||||
$metadata['source'] = (($url == $source) && !$config->get_bool('upload_tlsource') ? "" : $source);
|
||||
|
||||
$ext = false;
|
||||
if (is_array($headers)) {
|
||||
$metadata['extension'] = getExtension(findHeader($headers, 'Content-Type'));
|
||||
} else {
|
||||
$metadata['extension'] = $pathinfo['extension'];
|
||||
$ext = getExtension(findHeader($headers, 'Content-Type'));
|
||||
}
|
||||
if ($ext === false) {
|
||||
$ext = $pathinfo['extension'];
|
||||
}
|
||||
$metadata['extension'] = $ext;
|
||||
|
||||
/* check for locked > adds to metadata if it has */
|
||||
if(!empty($locked)){
|
||||
|
@ -228,6 +228,7 @@ class UploadTheme extends Themelet {
|
||||
if(class_exists("ICOFileHandler")){$supported_ext .= " ico ani cur";}
|
||||
if(class_exists("MP3FileHandler")){$supported_ext .= " mp3";}
|
||||
if(class_exists("SVGFileHandler")){$supported_ext .= " svg";}
|
||||
if(class_exists("VideoFileHandler")){$supported_ext .= " flv mp4 ogv webm m4v";}
|
||||
$title = "Booru to " . $config->get_string('title');
|
||||
// CA=0: Ask to use current or new tags | CA=1: Always use current tags | CA=2: Always use new tags
|
||||
$html .= '<p><a href="javascript:
|
||||
|
@ -45,6 +45,9 @@ class ViewImageTheme extends Themelet {
|
||||
return "$h_prev | $h_index | $h_next";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function build_navigation(Image $image) {
|
||||
$h_pin = $this->build_pin($image);
|
||||
$h_search = "
|
||||
|
@ -220,7 +220,7 @@ class Wiki extends Extension {
|
||||
|
||||
/**
|
||||
* @param string $title
|
||||
* @param int|null $revision
|
||||
* @param integer $revision
|
||||
* @return WikiPage
|
||||
*/
|
||||
private function get_page($title, $revision=-1) {
|
||||
@ -494,6 +494,10 @@ class Wiki extends Extension {
|
||||
|
||||
/**
|
||||
* callback function to format the diffence-lines with your 'style'
|
||||
* @param integer $nr1
|
||||
* @param integer $nr2
|
||||
* @param string $stat
|
||||
* @return string
|
||||
*/
|
||||
private function formatline( $nr1, $nr2, $stat, &$value ) { #change to $value if problems
|
||||
if(trim($value) == "") {
|
||||
|
@ -43,6 +43,9 @@ class WordFilter extends Extension {
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function get_map() {
|
||||
global $config;
|
||||
$raw = $config->get_string("word_filter");
|
||||
|
12
install.php
12
install.php
@ -114,6 +114,9 @@ do_install();
|
||||
// utilities {{{
|
||||
// TODO: Can some of these be pushed into "core/util.inc.php" ?
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
function check_gd_version() {
|
||||
$gdversion = 0;
|
||||
|
||||
@ -129,6 +132,9 @@ function check_gd_version() {
|
||||
return $gdversion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
function check_im_version() {
|
||||
$convert_check = exec("convert");
|
||||
|
||||
@ -469,6 +475,12 @@ EOD;
|
||||
echo "\n";
|
||||
} // }}}
|
||||
|
||||
/**
|
||||
* @param boolean $isPDO
|
||||
* @param string $errorMessage1
|
||||
* @param string $errorMessage2
|
||||
* @param integer $exitCode
|
||||
*/
|
||||
function handle_db_errors(/*bool*/ $isPDO, /*str*/ $errorMessage1, /*str*/ $errorMessage2, /*int*/ $exitCode) {
|
||||
$errorMessage1Extra = ($isPDO ? "Please check and ensure that the database configuration options are all correct." : "Please check the server log files for more information.");
|
||||
print <<<EOD
|
||||
|
@ -1,5 +0,0 @@
|
||||
In compliance with GPL, this message is to notify you that getID3 has been modified.
|
||||
|
||||
getid3.php was modified September 23, 2012 to add a boolean to force MP3 checking.
|
||||
|
||||
It carries the same license as its original.
|
@ -1,211 +0,0 @@
|
||||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// extension.cache.dbm.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:
|
||||
*
|
||||
* 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.dbm.php';
|
||||
* $getID3 = new getID3_cached('db3', '/tmp/getid3_cache.dbm',
|
||||
* '/tmp/getid3_cache.lock');
|
||||
* $getID3->encoding = 'UTF-8';
|
||||
* $info1 = $getID3->analyze('file1.flac');
|
||||
* $info2 = $getID3->analyze('file2.wv');
|
||||
*
|
||||
*
|
||||
* Supported Cache Types
|
||||
*
|
||||
* SQL Databases: (use extension.cache.mysql)
|
||||
*
|
||||
* cache_type cache_options
|
||||
* -------------------------------------------------------------------
|
||||
* mysql host, database, username, password
|
||||
*
|
||||
*
|
||||
* DBM-Style Databases: (this extension)
|
||||
*
|
||||
* 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_dbm extends getID3
|
||||
{
|
||||
|
||||
// public: constructor - see top of this file for cache type and cache_options
|
||||
function getID3_cached_dbm($cache_type, $dbm_filename, $lock_filename) {
|
||||
|
||||
// Check for dba extension
|
||||
if (!extension_loaded('dba')) {
|
||||
throw new Exception('PHP is not compiled with dba support, required to use DBM style cache.');
|
||||
}
|
||||
|
||||
// Check for specific dba driver
|
||||
if (!function_exists('dba_handlers') || !in_array($cache_type, dba_handlers())) {
|
||||
throw new Exception('PHP is not compiled --with '.$cache_type.' support, required to use DBM style cache.');
|
||||
}
|
||||
|
||||
// Create lock file if needed
|
||||
if (!file_exists($lock_filename)) {
|
||||
if (!touch($lock_filename)) {
|
||||
throw new Exception('failed to create lock file: '.$lock_filename);
|
||||
}
|
||||
}
|
||||
|
||||
// Open lock file for writing
|
||||
if (!is_writeable($lock_filename)) {
|
||||
throw new Exception('lock file: '.$lock_filename.' is not writable');
|
||||
}
|
||||
$this->lock = fopen($lock_filename, 'w');
|
||||
|
||||
// Acquire exclusive write lock to lock file
|
||||
flock($this->lock, LOCK_EX);
|
||||
|
||||
// Create dbm-file if needed
|
||||
if (!file_exists($dbm_filename)) {
|
||||
if (!touch($dbm_filename)) {
|
||||
throw new Exception('failed to create dbm file: '.$dbm_filename);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to open dbm file for writing
|
||||
$this->dba = dba_open($dbm_filename, 'w', $cache_type);
|
||||
if (!$this->dba) {
|
||||
|
||||
// Failed - create new dbm file
|
||||
$this->dba = dba_open($dbm_filename, 'n', $cache_type);
|
||||
|
||||
if (!$this->dba) {
|
||||
throw new Exception('failed to create dbm file: '.$dbm_filename);
|
||||
}
|
||||
|
||||
// Insert getID3 version number
|
||||
dba_insert(getID3::VERSION, getID3::VERSION, $this->dba);
|
||||
}
|
||||
|
||||
// Init misc values
|
||||
$this->cache_type = $cache_type;
|
||||
$this->dbm_filename = $dbm_filename;
|
||||
|
||||
// Register destructor
|
||||
register_shutdown_function(array($this, '__destruct'));
|
||||
|
||||
// Check version number and clear cache if changed
|
||||
if (dba_fetch(getID3::VERSION, $this->dba) != getID3::VERSION) {
|
||||
$this->clear_cache();
|
||||
}
|
||||
|
||||
parent::getID3();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// public: destuctor
|
||||
function __destruct() {
|
||||
|
||||
// Close dbm file
|
||||
dba_close($this->dba);
|
||||
|
||||
// Release exclusive lock
|
||||
flock($this->lock, LOCK_UN);
|
||||
|
||||
// Close lock file
|
||||
fclose($this->lock);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// public: clear cache
|
||||
function clear_cache() {
|
||||
|
||||
// Close dbm file
|
||||
dba_close($this->dba);
|
||||
|
||||
// Create new dbm file
|
||||
$this->dba = dba_open($this->dbm_filename, 'n', $this->cache_type);
|
||||
|
||||
if (!$this->dba) {
|
||||
throw new Exception('failed to clear cache/recreate dbm file: '.$this->dbm_filename);
|
||||
}
|
||||
|
||||
// Insert getID3 version number
|
||||
dba_insert(getID3::VERSION, getID3::VERSION, $this->dba);
|
||||
|
||||
// Re-register shutdown function
|
||||
register_shutdown_function(array($this, '__destruct'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// public: analyze file
|
||||
function analyze($filename) {
|
||||
|
||||
if (file_exists($filename)) {
|
||||
|
||||
// Calc key filename::mod_time::size - should be unique
|
||||
$key = $filename.'::'.filemtime($filename).'::'.filesize($filename);
|
||||
|
||||
// Loopup key
|
||||
$result = dba_fetch($key, $this->dba);
|
||||
|
||||
// Hit
|
||||
if ($result !== false) {
|
||||
return unserialize($result);
|
||||
}
|
||||
}
|
||||
|
||||
// Miss
|
||||
$result = parent::analyze($filename);
|
||||
|
||||
// Save result
|
||||
if (file_exists($filename)) {
|
||||
dba_insert($key, serialize($result), $this->dba);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,173 +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> //
|
||||
// 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
|
||||
{
|
||||
|
||||
// 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, $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 = '';
|
||||
if ($this->cursor = mysql_query("SELECT `value` FROM `".mysql_real_escape_string($this->table)."` 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 `".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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// public: analyze file
|
||||
function analyze($filename) {
|
||||
|
||||
if (file_exists($filename)) {
|
||||
|
||||
// Short-hands
|
||||
$filetime = filemtime($filename);
|
||||
$filesize = filesize($filename);
|
||||
|
||||
// Lookup file
|
||||
$this->cursor = mysql_query("SELECT `value` FROM `".mysql_real_escape_string($this->table)."` WHERE (`filename` = '".mysql_real_escape_string($filename)."') AND (`filesize` = '".mysql_real_escape_string($filesize)."') AND (`filetime` = '".mysql_real_escape_string($filetime)."')", $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);
|
||||
|
||||
// Save result
|
||||
if (file_exists($filename)) {
|
||||
$this->cursor = mysql_query("INSERT INTO `".mysql_real_escape_string($this->table)."` (`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 $analysis;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// private: (re)create sql table
|
||||
function create_table($drop=false) {
|
||||
|
||||
$this->cursor = mysql_query("CREATE TABLE IF NOT EXISTS `".mysql_real_escape_string($this->table)."` (
|
||||
`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,280 +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.gzip.php //
|
||||
// module for analyzing GZIP files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Module originally written by //
|
||||
// Mike Mozolin <teddybearØmail*ru> //
|
||||
// //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_gzip extends getid3_handler {
|
||||
|
||||
// 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)
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'gzip';
|
||||
|
||||
$start_length = 10;
|
||||
$unpack_header = 'a1id1/a1id2/a1cmethod/a1flags/a4mtime/a1xflags/a1os';
|
||||
//+---+---+---+---+---+---+---+---+---+---+
|
||||
//|ID1|ID2|CM |FLG| MTIME |XFL|OS |
|
||||
//+---+---+---+---+---+---+---+---+---+---+
|
||||
|
||||
if ($info['filesize'] > $info['php_memory_limit']) {
|
||||
$info['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;
|
||||
}
|
||||
fseek($this->getid3->fp, 0);
|
||||
$buffer = fread($this->getid3->fp, $info['filesize']);
|
||||
|
||||
$arr_members = explode("\x1F\x8B\x08", $buffer);
|
||||
while (true) {
|
||||
$is_wrong_members = false;
|
||||
$num_members = intval(count($arr_members));
|
||||
for ($i = 0; $i < $num_members; $i++) {
|
||||
if (strlen($arr_members[$i]) == 0) {
|
||||
continue;
|
||||
}
|
||||
$buf = "\x1F\x8B\x08".$arr_members[$i];
|
||||
|
||||
$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] = '';
|
||||
$is_wrong_members = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!$is_wrong_members) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$info['gzip']['files'] = array();
|
||||
|
||||
$fpointer = 0;
|
||||
$idx = 0;
|
||||
for ($i = 0; $i < $num_members; $i++) {
|
||||
if (strlen($arr_members[$i]) == 0) {
|
||||
continue;
|
||||
}
|
||||
$thisInfo = &$info['gzip']['member_header'][++$idx];
|
||||
|
||||
$buff = "\x1F\x8B\x08".$arr_members[$i];
|
||||
|
||||
$attr = unpack($unpack_header, substr($buff, 0, $start_length));
|
||||
$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']);
|
||||
|
||||
$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);
|
||||
|
||||
$thisInfo['compression'] = $this->get_xflag_type($thisInfo['raw']['xflags']);
|
||||
|
||||
$thisInfo['os'] = $this->get_os_type($thisInfo['raw']['os']);
|
||||
if (!$thisInfo['os']) {
|
||||
$info['error'][] = 'Read error on gzip file';
|
||||
return false;
|
||||
}
|
||||
|
||||
$fpointer = 10;
|
||||
$arr_xsubfield = array();
|
||||
// bit 2 - FLG.FEXTRA
|
||||
//+---+---+=================================+
|
||||
//| XLEN |...XLEN bytes of "extra field"...|
|
||||
//+---+---+=================================+
|
||||
if ($thisInfo['flags']['extra']) {
|
||||
$w_xlen = substr($buff, $fpointer, 2);
|
||||
$xlen = getid3_lib::LittleEndian2Int($w_xlen);
|
||||
$fpointer += 2;
|
||||
|
||||
$thisInfo['raw']['xfield'] = substr($buff, $fpointer, $xlen);
|
||||
// Extra SubFields
|
||||
//+---+---+---+---+==================================+
|
||||
//|SI1|SI2| LEN |... LEN bytes of subfield data ...|
|
||||
//+---+---+---+---+==================================+
|
||||
$idx = 0;
|
||||
while (true) {
|
||||
if ($idx >= $xlen) {
|
||||
break;
|
||||
}
|
||||
$si1 = ord(substr($buff, $fpointer + $idx++, 1));
|
||||
$si2 = ord(substr($buff, $fpointer + $idx++, 1));
|
||||
if (($si1 == 0x41) && ($si2 == 0x70)) {
|
||||
$w_xsublen = substr($buff, $fpointer + $idx, 2);
|
||||
$xsublen = getid3_lib::LittleEndian2Int($w_xsublen);
|
||||
$idx += 2;
|
||||
$arr_xsubfield[] = substr($buff, $fpointer + $idx, $xsublen);
|
||||
$idx += $xsublen;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$fpointer += $xlen;
|
||||
}
|
||||
// bit 3 - FLG.FNAME
|
||||
//+=========================================+
|
||||
//|...original file name, zero-terminated...|
|
||||
//+=========================================+
|
||||
// GZIP files may have only one file, with no filename, so assume original filename is current filename without .gz
|
||||
$thisInfo['filename'] = preg_replace('#\.gz$#i', '', $info['filename']);
|
||||
if ($thisInfo['flags']['filename']) {
|
||||
while (true) {
|
||||
if (ord($buff[$fpointer]) == 0) {
|
||||
$fpointer++;
|
||||
break;
|
||||
}
|
||||
$thisInfo['filename'] .= $buff[$fpointer];
|
||||
$fpointer++;
|
||||
}
|
||||
}
|
||||
// bit 4 - FLG.FCOMMENT
|
||||
//+===================================+
|
||||
//|...file comment, zero-terminated...|
|
||||
//+===================================+
|
||||
if ($thisInfo['flags']['comment']) {
|
||||
while (true) {
|
||||
if (ord($buff[$fpointer]) == 0) {
|
||||
$fpointer++;
|
||||
break;
|
||||
}
|
||||
$thisInfo['comment'] .= $buff[$fpointer];
|
||||
$fpointer++;
|
||||
}
|
||||
}
|
||||
// bit 1 - FLG.FHCRC
|
||||
//+---+---+
|
||||
//| CRC16 |
|
||||
//+---+---+
|
||||
if ($thisInfo['flags']['crc16']) {
|
||||
$w_crc = substr($buff, $fpointer, 2);
|
||||
$thisInfo['crc16'] = getid3_lib::LittleEndian2Int($w_crc);
|
||||
$fpointer += 2;
|
||||
}
|
||||
// bit 0 - FLG.FTEXT
|
||||
//if ($thisInfo['raw']['flags'] & 0x01) {
|
||||
// Ignored...
|
||||
//}
|
||||
// bits 5, 6, 7 - reserved
|
||||
|
||||
$thisInfo['crc32'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 8, 4));
|
||||
$thisInfo['filesize'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 4));
|
||||
|
||||
$info['gzip']['files'] = getid3_lib::array_merge_clobber($info['gzip']['files'], getid3_lib::CreateDeepArray($thisInfo['filename'], '/', $thisInfo['filesize']));
|
||||
|
||||
if ($this->option_gzip_parse_contents) {
|
||||
// Try to inflate GZip
|
||||
$csize = 0;
|
||||
$inflated = '';
|
||||
$chkcrc32 = '';
|
||||
if (function_exists('gzinflate')) {
|
||||
$cdata = substr($buff, $fpointer);
|
||||
$cdata = substr($cdata, 0, strlen($cdata) - 8);
|
||||
$csize = strlen($cdata);
|
||||
$inflated = gzinflate($cdata);
|
||||
|
||||
// Calculate CRC32 for inflated content
|
||||
$thisInfo['crc32_valid'] = (bool) (sprintf('%u', crc32($inflated)) == $thisInfo['crc32']);
|
||||
|
||||
// determine format
|
||||
$formattest = substr($inflated, 0, 32774);
|
||||
$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'] : '');
|
||||
switch ($determined_format['module']) {
|
||||
case 'tar':
|
||||
// view TAR-file info
|
||||
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
|
||||
$info['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);
|
||||
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 {
|
||||
$info['error'][] = 'Unable to fopen() temp file to parse TAR inside GZIP file';
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case '':
|
||||
default:
|
||||
// unknown or unhandled format
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Converts the OS type
|
||||
function get_os_type($key) {
|
||||
static $os_type = array(
|
||||
'0' => 'FAT filesystem (MS-DOS, OS/2, NT/Win32)',
|
||||
'1' => 'Amiga',
|
||||
'2' => 'VMS (or OpenVMS)',
|
||||
'3' => 'Unix',
|
||||
'4' => 'VM/CMS',
|
||||
'5' => 'Atari TOS',
|
||||
'6' => 'HPFS filesystem (OS/2, NT)',
|
||||
'7' => 'Macintosh',
|
||||
'8' => 'Z-System',
|
||||
'9' => 'CP/M',
|
||||
'10' => 'TOPS-20',
|
||||
'11' => 'NTFS filesystem (NT)',
|
||||
'12' => 'QDOS',
|
||||
'13' => 'Acorn RISCOS',
|
||||
'255' => 'unknown'
|
||||
);
|
||||
return (isset($os_type[$key]) ? $os_type[$key] : '');
|
||||
}
|
||||
|
||||
// Converts the eXtra FLags
|
||||
function get_xflag_type($key) {
|
||||
static $xflag_type = array(
|
||||
'0' => 'unknown',
|
||||
'2' => 'maximum compression',
|
||||
'4' => 'fastest algorithm'
|
||||
);
|
||||
return (isset($xflag_type[$key]) ? $xflag_type[$key] : '');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -1,53 +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 extends getid3_handler
|
||||
{
|
||||
|
||||
var $option_use_rar_extension = false;
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'rar';
|
||||
|
||||
if ($this->option_use_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 {
|
||||
$info['error'][] = 'failed to rar_open('.$info['filename'].')';
|
||||
}
|
||||
} else {
|
||||
$info['error'][] = 'RAR support does not appear to be available in this PHP installation';
|
||||
}
|
||||
} else {
|
||||
$info['error'][] = 'PHP-RAR processing has been disabled (set $getid3_rar->option_use_rar_extension=true to enable)';
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,96 +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.szip.php //
|
||||
// module for analyzing SZIP compressed files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_szip extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$SZIPHeader = fread($this->getid3->fp, 6);
|
||||
if (substr($SZIPHeader, 0, 4) != "SZ\x0A\x04") {
|
||||
$info['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));
|
||||
|
||||
while (!feof($this->getid3->fp)) {
|
||||
$NextBlockID = fread($this->getid3->fp, 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($this->getid3->fp, 4, SEEK_CUR);
|
||||
break;
|
||||
|
||||
case 'BH':
|
||||
$BHheaderbytes = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 3));
|
||||
$BHheaderdata = fread($this->getid3->fp, $BHheaderbytes);
|
||||
$BHheaderoffset = 0;
|
||||
while (strpos($BHheaderdata, "\x00", $BHheaderoffset) > 0) {
|
||||
//filename as \0 terminated string (empty string indicates end)
|
||||
//owner as \0 terminated string (empty is same as last file)
|
||||
//group as \0 terminated string (empty is same as last file)
|
||||
//3 byte filelength in this block
|
||||
//2 byte access flags
|
||||
//4 byte creation time (like in unix)
|
||||
//4 byte modification time (like in unix)
|
||||
//4 byte access time (like in unix)
|
||||
|
||||
$BHdataArray['filename'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00"));
|
||||
$BHheaderoffset += (strlen($BHdataArray['filename']) + 1);
|
||||
|
||||
$BHdataArray['owner'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00"));
|
||||
$BHheaderoffset += (strlen($BHdataArray['owner']) + 1);
|
||||
|
||||
$BHdataArray['group'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00"));
|
||||
$BHheaderoffset += (strlen($BHdataArray['group']) + 1);
|
||||
|
||||
$BHdataArray['filelength'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 3));
|
||||
$BHheaderoffset += 3;
|
||||
|
||||
$BHdataArray['access_flags'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 2));
|
||||
$BHheaderoffset += 2;
|
||||
|
||||
$BHdataArray['creation_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4));
|
||||
$BHheaderoffset += 4;
|
||||
|
||||
$BHdataArray['modification_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4));
|
||||
$BHheaderoffset += 4;
|
||||
|
||||
$BHdataArray['access_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4));
|
||||
$BHheaderoffset += 4;
|
||||
|
||||
$info['szip']['BH'][] = $BHdataArray;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,178 +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.tar.php //
|
||||
// module for analyzing TAR files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Module originally written by //
|
||||
// Mike Mozolin <teddybearØmail*ru> //
|
||||
// //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_tar extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$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
|
||||
|
||||
fseek($this->getid3->fp, 0);
|
||||
while (!feof($this->getid3->fp)) {
|
||||
$buffer = fread($this->getid3->fp, 512);
|
||||
if (strlen($buffer) < 512) {
|
||||
break;
|
||||
}
|
||||
|
||||
// check the block
|
||||
$checksum = 0;
|
||||
for ($i = 0; $i < 148; $i++) {
|
||||
$checksum += ord($buffer{$i});
|
||||
}
|
||||
for ($i = 148; $i < 156; $i++) {
|
||||
$checksum += ord(' ');
|
||||
}
|
||||
for ($i = 156; $i < 512; $i++) {
|
||||
$checksum += ord($buffer{$i});
|
||||
}
|
||||
$attr = unpack($unpack_header, $buffer);
|
||||
$name = (isset($attr['fname'] ) ? trim($attr['fname'] ) : '');
|
||||
$mode = octdec(isset($attr['mode'] ) ? trim($attr['mode'] ) : '');
|
||||
$uid = octdec(isset($attr['uid'] ) ? trim($attr['uid'] ) : '');
|
||||
$gid = octdec(isset($attr['gid'] ) ? trim($attr['gid'] ) : '');
|
||||
$size = octdec(isset($attr['size'] ) ? trim($attr['size'] ) : '');
|
||||
$mtime = octdec(isset($attr['mtime'] ) ? trim($attr['mtime'] ) : '');
|
||||
$chksum = octdec(isset($attr['chksum'] ) ? trim($attr['chksum'] ) : '');
|
||||
$typflag = (isset($attr['typflag']) ? trim($attr['typflag']) : '');
|
||||
$lnkname = (isset($attr['lnkname']) ? trim($attr['lnkname']) : '');
|
||||
$magic = (isset($attr['magic'] ) ? trim($attr['magic'] ) : '');
|
||||
$ver = (isset($attr['ver'] ) ? trim($attr['ver'] ) : '');
|
||||
$uname = (isset($attr['uname'] ) ? trim($attr['uname'] ) : '');
|
||||
$gname = (isset($attr['gname'] ) ? trim($attr['gname'] ) : '');
|
||||
$devmaj = octdec(isset($attr['devmaj'] ) ? trim($attr['devmaj'] ) : '');
|
||||
$devmin = octdec(isset($attr['devmin'] ) ? trim($attr['devmin'] ) : '');
|
||||
$prefix = (isset($attr['prefix'] ) ? trim($attr['prefix'] ) : '');
|
||||
if (($checksum == 256) && ($chksum == 0)) {
|
||||
// EOF Found
|
||||
break;
|
||||
}
|
||||
if ($prefix) {
|
||||
$name = $prefix.'/'.$name;
|
||||
}
|
||||
if ((preg_match('#/$#', $name)) && !$name) {
|
||||
$typeflag = 5;
|
||||
}
|
||||
if ($buffer == $null_512k) {
|
||||
// it's the end of the tar-file...
|
||||
break;
|
||||
}
|
||||
|
||||
// Read to the next chunk
|
||||
fseek($this->getid3->fp, $size, SEEK_CUR);
|
||||
|
||||
$diff = $size % 512;
|
||||
if ($diff != 0) {
|
||||
// Padding, throw away
|
||||
fseek($this->getid3->fp, (512 - $diff), SEEK_CUR);
|
||||
}
|
||||
// Protect against tar-files with garbage at the end
|
||||
if ($name == '') {
|
||||
break;
|
||||
}
|
||||
$info['tar']['file_details'][$name] = array (
|
||||
'name' => $name,
|
||||
'mode_raw' => $mode,
|
||||
'mode' => getid3_tar::display_perms($mode),
|
||||
'uid' => $uid,
|
||||
'gid' => $gid,
|
||||
'size' => $size,
|
||||
'mtime' => $mtime,
|
||||
'chksum' => $chksum,
|
||||
'typeflag' => getid3_tar::get_flag_type($typflag),
|
||||
'linkname' => $lnkname,
|
||||
'magic' => $magic,
|
||||
'version' => $ver,
|
||||
'uname' => $uname,
|
||||
'gname' => $gname,
|
||||
'devmajor' => $devmaj,
|
||||
'devminor' => $devmin
|
||||
);
|
||||
$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) {
|
||||
// Determine Type
|
||||
if ($mode & 0x1000) $type='p'; // FIFO pipe
|
||||
elseif ($mode & 0x2000) $type='c'; // Character special
|
||||
elseif ($mode & 0x4000) $type='d'; // Directory
|
||||
elseif ($mode & 0x6000) $type='b'; // Block special
|
||||
elseif ($mode & 0x8000) $type='-'; // Regular
|
||||
elseif ($mode & 0xA000) $type='l'; // Symbolic Link
|
||||
elseif ($mode & 0xC000) $type='s'; // Socket
|
||||
else $type='u'; // UNKNOWN
|
||||
|
||||
// Determine permissions
|
||||
$owner['read'] = (($mode & 00400) ? 'r' : '-');
|
||||
$owner['write'] = (($mode & 00200) ? 'w' : '-');
|
||||
$owner['execute'] = (($mode & 00100) ? 'x' : '-');
|
||||
$group['read'] = (($mode & 00040) ? 'r' : '-');
|
||||
$group['write'] = (($mode & 00020) ? 'w' : '-');
|
||||
$group['execute'] = (($mode & 00010) ? 'x' : '-');
|
||||
$world['read'] = (($mode & 00004) ? 'r' : '-');
|
||||
$world['write'] = (($mode & 00002) ? 'w' : '-');
|
||||
$world['execute'] = (($mode & 00001) ? 'x' : '-');
|
||||
|
||||
// Adjust for SUID, SGID and sticky bit
|
||||
if ($mode & 0x800) $owner['execute'] = ($owner['execute'] == 'x') ? 's' : 'S';
|
||||
if ($mode & 0x400) $group['execute'] = ($group['execute'] == 'x') ? 's' : 'S';
|
||||
if ($mode & 0x200) $world['execute'] = ($world['execute'] == 'x') ? 't' : 'T';
|
||||
|
||||
$s = sprintf('%1s', $type);
|
||||
$s .= sprintf('%1s%1s%1s', $owner['read'], $owner['write'], $owner['execute']);
|
||||
$s .= sprintf('%1s%1s%1s', $group['read'], $group['write'], $group['execute']);
|
||||
$s .= sprintf('%1s%1s%1s'."\n", $world['read'], $world['write'], $world['execute']);
|
||||
return $s;
|
||||
}
|
||||
|
||||
// Converts the file type
|
||||
function get_flag_type($typflag) {
|
||||
static $flag_types = array(
|
||||
'0' => 'LF_NORMAL',
|
||||
'1' => 'LF_LINK',
|
||||
'2' => 'LF_SYNLINK',
|
||||
'3' => 'LF_CHR',
|
||||
'4' => 'LF_BLK',
|
||||
'5' => 'LF_DIR',
|
||||
'6' => 'LF_FIFO',
|
||||
'7' => 'LF_CONFIG',
|
||||
'D' => 'LF_DUMPDIR',
|
||||
'K' => 'LF_LONGLINK',
|
||||
'L' => 'LF_LONGNAME',
|
||||
'M' => 'LF_MULTIVOL',
|
||||
'N' => 'LF_NAMES',
|
||||
'S' => 'LF_SPARSE',
|
||||
'V' => 'LF_VOLHDR'
|
||||
);
|
||||
return (isset($flag_types[$typflag]) ? $flag_types[$typflag] : '');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,424 +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 extends getid3_handler
|
||||
{
|
||||
|
||||
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'])) {
|
||||
$info['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($this->getid3->fp, -128 * $EOCDsearchCounter, SEEK_END);
|
||||
$EOCDsearchData = fread($this->getid3->fp, 128).$EOCDsearchData;
|
||||
|
||||
if (strstr($EOCDsearchData, 'PK'."\x05\x06")) {
|
||||
|
||||
$EOCDposition = strpos($EOCDsearchData, 'PK'."\x05\x06");
|
||||
fseek($this->getid3->fp, (-128 * $EOCDsearchCounter) + $EOCDposition, SEEK_END);
|
||||
$info['zip']['end_central_directory'] = $this->ZIPparseEndOfCentralDirectory();
|
||||
|
||||
fseek($this->getid3->fp, $info['zip']['end_central_directory']['directory_offset'], SEEK_SET);
|
||||
$info['zip']['entries_count'] = 0;
|
||||
while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($this->getid3->fp)) {
|
||||
$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) {
|
||||
$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) {
|
||||
$info['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';
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->getZIPentriesFilepointer()) {
|
||||
|
||||
// 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)) {
|
||||
$info['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)';
|
||||
}
|
||||
$info['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;
|
||||
|
||||
} else {
|
||||
|
||||
unset($info['zip']);
|
||||
$info['fileformat'] = '';
|
||||
$info['error'][] = 'Cannot find End Of Central Directory (truncated file?)';
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
$info['error'][] = 'No Local File Header entries found';
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['zip']['entries_count'] = 0;
|
||||
while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($this->getid3->fp)) {
|
||||
$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) {
|
||||
$info['error'][] = 'No Central Directory entries found (truncated file?)';
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($EOCD = $this->ZIPparseEndOfCentralDirectory()) {
|
||||
$info['zip']['end_central_directory'] = $EOCD;
|
||||
} else {
|
||||
$info['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;
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
$info['error'][] = 'No Local File Header entries found';
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function ZIPparseLocalFileHeader() {
|
||||
$LocalFileHeader['offset'] = ftell($this->getid3->fp);
|
||||
|
||||
$ZIPlocalFileHeader = fread($this->getid3->fp, 30);
|
||||
|
||||
$LocalFileHeader['raw']['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 0, 4));
|
||||
if ($LocalFileHeader['raw']['signature'] != 0x04034B50) {
|
||||
// invalid Local File Header Signature
|
||||
fseek($this->getid3->fp, $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($this->getid3->fp, $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($this->getid3->fp);
|
||||
//$LocalFileHeader['compressed_data'] = fread($this->getid3->fp, $LocalFileHeader['raw']['compressed_size']);
|
||||
fseek($this->getid3->fp, $LocalFileHeader['raw']['compressed_size'], SEEK_CUR);
|
||||
|
||||
if ($LocalFileHeader['flags']['data_descriptor_used']) {
|
||||
$DataDescriptor = fread($this->getid3->fp, 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() {
|
||||
$CentralDirectory['offset'] = ftell($this->getid3->fp);
|
||||
|
||||
$ZIPcentralDirectory = fread($this->getid3->fp, 46);
|
||||
|
||||
$CentralDirectory['raw']['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 0, 4));
|
||||
if ($CentralDirectory['raw']['signature'] != 0x02014B50) {
|
||||
// invalid Central Directory Signature
|
||||
fseek($this->getid3->fp, $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($this->getid3->fp, $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() {
|
||||
$EndOfCentralDirectory['offset'] = ftell($this->getid3->fp);
|
||||
|
||||
$ZIPendOfCentralDirectory = fread($this->getid3->fp, 22);
|
||||
|
||||
$EndOfCentralDirectory['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 0, 4));
|
||||
if ($EndOfCentralDirectory['signature'] != 0x06054B50) {
|
||||
// invalid End Of Central Directory Signature
|
||||
fseek($this->getid3->fp, $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($this->getid3->fp, $EndOfCentralDirectory['comment_length']);
|
||||
}
|
||||
|
||||
return $EndOfCentralDirectory;
|
||||
}
|
||||
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
|
||||
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'
|
||||
);
|
||||
|
||||
return (isset($ZIPversionOSLookup[$index]) ? $ZIPversionOSLookup[$index] : '[unknown]');
|
||||
}
|
||||
|
||||
static 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]');
|
||||
}
|
||||
|
||||
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
@ -1,73 +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 extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['error'][] = 'Bink / Smacker files not properly processed by this version of getID3() ['.$this->getid3->version().']';
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$fileTypeID = fread($this->getid3->fp, 3);
|
||||
switch ($fileTypeID) {
|
||||
case 'BIK':
|
||||
return $this->ParseBink();
|
||||
break;
|
||||
|
||||
case 'SMK':
|
||||
return $this->ParseSmacker();
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Expecting "BIK" or "SMK" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($fileTypeID).'"';
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
function ParseBink() {
|
||||
$info = &$this->getid3->info;
|
||||
$info['fileformat'] = 'bink';
|
||||
$info['video']['dataformat'] = 'bink';
|
||||
|
||||
$fileData = 'BIK'.fread($this->getid3->fp, 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)) {
|
||||
$info['error'][] = 'Probably truncated file: expecting '.$info['bink']['data_size'].' bytes, found '.($info['avdataend'] - $info['avdataoffset']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function ParseSmacker() {
|
||||
$info = &$this->getid3->info;
|
||||
$info['fileformat'] = 'smacker';
|
||||
$info['video']['dataformat'] = 'smacker';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,731 +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) //
|
||||
// //
|
||||
// //
|
||||
// * 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() //
|
||||
// //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// 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 extends getid3_handler
|
||||
{
|
||||
var $max_frames = 100000; // break out of the loop if too many frames have been scanned; only scan this many if meta frame does not contain useful duration
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
|
||||
$FLVdataLength = $info['avdataend'] - $info['avdataoffset'];
|
||||
$FLVheader = fread($this->getid3->fp, 5);
|
||||
|
||||
$info['fileformat'] = 'flv';
|
||||
$info['flv']['header']['signature'] = substr($FLVheader, 0, 3);
|
||||
$info['flv']['header']['version'] = getid3_lib::BigEndian2Int(substr($FLVheader, 3, 1));
|
||||
$TypeFlags = getid3_lib::BigEndian2Int(substr($FLVheader, 4, 1));
|
||||
|
||||
$magic = 'FLV';
|
||||
if ($info['flv']['header']['signature'] != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['flv']['header']['signature']).'"';
|
||||
unset($info['flv']);
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['flv']['header']['hasAudio'] = (bool) ($TypeFlags & 0x04);
|
||||
$info['flv']['header']['hasVideo'] = (bool) ($TypeFlags & 0x01);
|
||||
|
||||
$FrameSizeDataLength = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 4));
|
||||
$FLVheaderFrameLength = 9;
|
||||
if ($FrameSizeDataLength > $FLVheaderFrameLength) {
|
||||
fseek($this->getid3->fp, $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 (((ftell($this->getid3->fp) + 16) < $info['avdataend']) && (($tagParseCount++ <= $this->max_frames) || !$found_valid_meta_playtime)) {
|
||||
$ThisTagHeader = fread($this->getid3->fp, 16);
|
||||
|
||||
$PreviousTagLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 0, 4));
|
||||
$TagType = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 4, 1));
|
||||
$DataLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 5, 3));
|
||||
$Timestamp = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 8, 3));
|
||||
$LastHeaderByte = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 15, 1));
|
||||
$NextOffset = ftell($this->getid3->fp) - 1 + $DataLength;
|
||||
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 = fread($this->getid3->fp, 11);
|
||||
|
||||
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 = fread($this->getid3->fp, $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));
|
||||
$PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2));
|
||||
$PictureSizeEnc['x'] >>= 7;
|
||||
$PictureSizeEnc['y'] >>= 7;
|
||||
$info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFF;
|
||||
$info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFF;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
$PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 3));
|
||||
$PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 3));
|
||||
$PictureSizeEnc['x'] >>= 7;
|
||||
$PictureSizeEnc['y'] >>= 7;
|
||||
$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;
|
||||
|
||||
}
|
||||
}
|
||||
$info['video']['pixel_aspect_ratio'] = $info['video']['resolution_x'] / $info['video']['resolution_y'];
|
||||
}
|
||||
break;
|
||||
|
||||
// Meta tag
|
||||
case GETID3_FLV_TAG_META:
|
||||
if (!$found_meta) {
|
||||
$found_meta = true;
|
||||
fseek($this->getid3->fp, -1, SEEK_CUR);
|
||||
$datachunk = fread($this->getid3->fp, $DataLength);
|
||||
$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;
|
||||
}
|
||||
fseek($this->getid3->fp, $NextOffset, SEEK_SET);
|
||||
}
|
||||
|
||||
$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'] = $this->FLVaudioFormat($info['flv']['audio']['audioFormat']);
|
||||
$info['audio']['sample_rate'] = $this->FLVaudioRate($info['flv']['audio']['audioRate']);
|
||||
$info['audio']['bits_per_sample'] = $this->FLVaudioBitDepth($info['flv']['audio']['audioSampleSize']);
|
||||
|
||||
$info['audio']['channels'] = $info['flv']['audio']['audioType'] + 1; // 0=mono,1=stereo
|
||||
$info['audio']['lossless'] = ($info['flv']['audio']['audioFormat'] ? false : true); // 0=uncompressed
|
||||
$info['audio']['dataformat'] = 'flv';
|
||||
}
|
||||
if (!empty($info['flv']['header']['hasVideo'])) {
|
||||
$info['video']['codec'] = $this->FLVvideoCodec($info['flv']['video']['videoCodec']);
|
||||
$info['video']['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'] = $this->FLVaudioFormat($info['flv']['meta']['onMetaData']['audiocodecid']);
|
||||
}
|
||||
if (isset($info['flv']['meta']['onMetaData']['videocodecid'])) {
|
||||
$info['video']['codec'] = $this->FLVvideoCodec($info['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();
|
||||
|
||||
if ($significantBits > 31) {
|
||||
// something is broken, this is an emergency escape to prevent infinite loops
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
File diff suppressed because it is too large
Load Diff
@ -1,299 +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 extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
if ($info['avdataend'] <= $info['avdataoffset']) {
|
||||
$info['error'][] = '"avdataend" ('.$info['avdataend'].') is unexpectedly less-than-or-equal-to "avdataoffset" ('.$info['avdataoffset'].')';
|
||||
return false;
|
||||
}
|
||||
$info['fileformat'] = 'mpeg';
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$MPEGstreamData = fread($this->getid3->fp, min(100000, $info['avdataend'] - $info['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)
|
||||
|
||||
$info['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;
|
||||
|
||||
$info['mpeg']['video']['raw']['framesize_horizontal'] = ($FrameSizeDWORD & 0xFFF000) >> 12; // 12 bits for horizontal frame size
|
||||
$info['mpeg']['video']['raw']['framesize_vertical'] = ($FrameSizeDWORD & 0x000FFF); // 12 bits for vertical frame size
|
||||
$info['mpeg']['video']['raw']['pixel_aspect_ratio'] = ($AspectRatioFrameRateDWORD & 0xF0) >> 4;
|
||||
$info['mpeg']['video']['raw']['frame_rate'] = ($AspectRatioFrameRateDWORD & 0x0F);
|
||||
|
||||
$info['mpeg']['video']['framesize_horizontal'] = $info['mpeg']['video']['raw']['framesize_horizontal'];
|
||||
$info['mpeg']['video']['framesize_vertical'] = $info['mpeg']['video']['raw']['framesize_vertical'];
|
||||
|
||||
$info['mpeg']['video']['pixel_aspect_ratio'] = $this->MPEGvideoAspectRatioLookup($info['mpeg']['video']['raw']['pixel_aspect_ratio']);
|
||||
$info['mpeg']['video']['pixel_aspect_ratio_text'] = $this->MPEGvideoAspectRatioTextLookup($info['mpeg']['video']['raw']['pixel_aspect_ratio']);
|
||||
$info['mpeg']['video']['frame_rate'] = $this->MPEGvideoFramerateLookup($info['mpeg']['video']['raw']['frame_rate']);
|
||||
|
||||
$info['mpeg']['video']['raw']['bitrate'] = getid3_lib::Bin2Dec(substr($assortedinformation, 0, 18));
|
||||
$info['mpeg']['video']['raw']['marker_bit'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 18, 1));
|
||||
$info['mpeg']['video']['raw']['vbv_buffer_size'] = getid3_lib::Bin2Dec(substr($assortedinformation, 19, 10));
|
||||
$info['mpeg']['video']['raw']['constrained_param_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 29, 1));
|
||||
$info['mpeg']['video']['raw']['intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 30, 1));
|
||||
if ($info['mpeg']['video']['raw']['intra_quant_flag']) {
|
||||
|
||||
// read 512 bits
|
||||
$info['mpeg']['video']['raw']['intra_quant'] = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 64));
|
||||
$VideoChunkOffset += 64;
|
||||
|
||||
$info['mpeg']['video']['raw']['non_intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($info['mpeg']['video']['raw']['intra_quant'], 511, 1));
|
||||
$info['mpeg']['video']['raw']['intra_quant'] = getid3_lib::Bin2Dec(substr($assortedinformation, 31, 1)).substr(getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 64)), 0, 511);
|
||||
|
||||
if ($info['mpeg']['video']['raw']['non_intra_quant_flag']) {
|
||||
$info['mpeg']['video']['raw']['non_intra_quant'] = substr($MPEGstreamData, $VideoChunkOffset, 64);
|
||||
$VideoChunkOffset += 64;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$info['mpeg']['video']['raw']['non_intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 31, 1));
|
||||
if ($info['mpeg']['video']['raw']['non_intra_quant_flag']) {
|
||||
$info['mpeg']['video']['raw']['non_intra_quant'] = substr($MPEGstreamData, $VideoChunkOffset, 64);
|
||||
$VideoChunkOffset += 64;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($info['mpeg']['video']['raw']['bitrate'] == 0x3FFFF) { // 18 set bits
|
||||
|
||||
$info['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']['framesize_horizontal'];
|
||||
$info['video']['resolution_y'] = $info['mpeg']['video']['framesize_vertical'];
|
||||
$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;
|
||||
|
||||
} else {
|
||||
|
||||
$info['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) {
|
||||
$info['video']['codec'] = 'MPEG-2';
|
||||
} else {
|
||||
$info['video']['codec'] = 'MPEG-1';
|
||||
}
|
||||
|
||||
|
||||
$AudioChunkOffset = 0;
|
||||
while (true) {
|
||||
while (substr($MPEGstreamData, $AudioChunkOffset++, 4) !== GETID3_MPEG_AUDIO_START) {
|
||||
if ($AudioChunkOffset >= $MPEGstreamDataLength) {
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$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
|
||||
fseek($getid3_temp->fp, ftell($this->getid3->fp), SEEK_SET);
|
||||
$getid3_temp->info = $info; // only overwrite real data if valid header found
|
||||
if ($getid3_mp3->decodeMPEGaudioHeader(($AudioChunkOffset + 3) + 8 + $i, $getid3_temp->info, false)) {
|
||||
$info = $getid3_temp->info;
|
||||
$info['audio']['bitrate_mode'] = 'cbr';
|
||||
$info['audio']['lossless'] = false;
|
||||
unset($getid3_temp, $getid3_mp3);
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
unset($getid3_temp, $getid3_mp3);
|
||||
}
|
||||
|
||||
// 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 patter
|
||||
// Use interpolated lookup tables to approximately guess how much is overhead, because
|
||||
// playtime is calculated as filesize / total-bitrate
|
||||
$info['playtime_seconds'] *= $this->MPEGsystemNonOverheadPercentage($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;
|
||||
//$info['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) {
|
||||
$info['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,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.audio.nsv.php //
|
||||
// module for analyzing Nullsoft NSV files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_nsv extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$NSVheader = fread($this->getid3->fp, 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:
|
||||
$info['error'][] = 'Expecting "NSVs" or "NSVf" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($NSVheader).'"';
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isset($info['nsv']['NSVf'])) {
|
||||
$info['warning'][] = 'NSVf header not present - cannot calculate playtime or bitrate';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getNSVsHeaderFilepointer($fileoffset) {
|
||||
$info = &$this->getid3->info;
|
||||
fseek($this->getid3->fp, $fileoffset, SEEK_SET);
|
||||
$NSVsheader = fread($this->getid3->fp, 28);
|
||||
$offset = 0;
|
||||
|
||||
$info['nsv']['NSVs']['identifier'] = substr($NSVsheader, $offset, 4);
|
||||
$offset += 4;
|
||||
|
||||
if ($info['nsv']['NSVs']['identifier'] != 'NSVs') {
|
||||
$info['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;
|
||||
}
|
||||
|
||||
function getNSVfHeaderFilepointer($fileoffset, $getTOCoffsets=false) {
|
||||
$info = &$this->getid3->info;
|
||||
fseek($this->getid3->fp, $fileoffset, SEEK_SET);
|
||||
$NSVfheader = fread($this->getid3->fp, 28);
|
||||
$offset = 0;
|
||||
|
||||
$info['nsv']['NSVf']['identifier'] = substr($NSVfheader, $offset, 4);
|
||||
$offset += 4;
|
||||
|
||||
if ($info['nsv']['NSVf']['identifier'] != 'NSVf') {
|
||||
$info['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']) {
|
||||
$info['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) {
|
||||
$info['error'][] = 'Corrupt NSV file: NSVf.playtime_ms == zero';
|
||||
return false;
|
||||
}
|
||||
|
||||
$NSVfheader .= fread($this->getid3->fp, $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;
|
||||
}
|
||||
|
||||
|
||||
static 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
@ -1,530 +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.real.php //
|
||||
// module for analyzing Real Audio/Video files //
|
||||
// dependencies: module.audio-video.riff.php //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
|
||||
|
||||
class getid3_real extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'real';
|
||||
$info['bitrate'] = 0;
|
||||
$info['playtime_seconds'] = 0;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$ChunkCounter = 0;
|
||||
while (ftell($this->getid3->fp) < $info['avdataend']) {
|
||||
$ChunkData = fread($this->getid3->fp, 8);
|
||||
$ChunkName = substr($ChunkData, 0, 4);
|
||||
$ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, 4, 4));
|
||||
|
||||
if ($ChunkName == '.ra'."\xFD") {
|
||||
$ChunkData .= fread($this->getid3->fp, $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'];
|
||||
|
||||
$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 ($info['real']['old_ra_header']['comments'] as $key => $valuearray) {
|
||||
if (strlen(trim($valuearray[0])) > 0) {
|
||||
$info['real']['comments'][$key][] = trim($valuearray[0]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
$info['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
|
||||
$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($this->getid3->fp) - 8;
|
||||
$thisfile_real_chunks_currentchunk['length'] = $ChunkSize;
|
||||
if (($thisfile_real_chunks_currentchunk['offset'] + $thisfile_real_chunks_currentchunk['length']) > $info['avdataend']) {
|
||||
$info['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 > ($this->getid3->fread_buffer_size() + 8)) {
|
||||
|
||||
$ChunkData .= fread($this->getid3->fp, $this->getid3->fread_buffer_size() - 8);
|
||||
fseek($this->getid3->fp, $thisfile_real_chunks_currentchunk['offset'] + $ChunkSize, SEEK_SET);
|
||||
|
||||
} elseif(($ChunkSize - 8) > 0) {
|
||||
|
||||
$ChunkData .= fread($this->getid3->fp, $ChunkSize - 8);
|
||||
|
||||
}
|
||||
$offset = 8;
|
||||
|
||||
switch ($ChunkName) {
|
||||
|
||||
case '.RMF': // RealMedia File Header
|
||||
$thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
|
||||
$offset += 2;
|
||||
switch ($thisfile_real_chunks_currentchunk['object_version']) {
|
||||
|
||||
case 0:
|
||||
$thisfile_real_chunks_currentchunk['file_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['headers_count'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
//$info['warning'][] = 'Expected .RMF-object_version to be "0", actual value is "'.$thisfile_real_chunks_currentchunk['object_version'].'" (should not be a problem)';
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'PROP': // Properties Header
|
||||
$thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
|
||||
$offset += 2;
|
||||
if ($thisfile_real_chunks_currentchunk['object_version'] == 0) {
|
||||
$thisfile_real_chunks_currentchunk['max_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['avg_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['max_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['avg_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['num_packets'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['duration'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['preroll'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['index_offset'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['data_offset'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['num_streams'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_real_chunks_currentchunk['flags_raw'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
|
||||
$offset += 2;
|
||||
$info['playtime_seconds'] = $thisfile_real_chunks_currentchunk['duration'] / 1000;
|
||||
if ($thisfile_real_chunks_currentchunk['duration'] > 0) {
|
||||
$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);
|
||||
$thisfile_real_chunks_currentchunk['flags']['live_broadcast'] = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0004);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'MDPR': // Media Properties Header
|
||||
$thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
|
||||
$offset += 2;
|
||||
if ($thisfile_real_chunks_currentchunk['object_version'] == 0) {
|
||||
$thisfile_real_chunks_currentchunk['stream_number'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_real_chunks_currentchunk['max_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['avg_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['max_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['avg_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['start_time'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['preroll'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['duration'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['stream_name_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 1));
|
||||
$offset += 1;
|
||||
$thisfile_real_chunks_currentchunk['stream_name'] = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['stream_name_size']);
|
||||
$offset += $thisfile_real_chunks_currentchunk['stream_name_size'];
|
||||
$thisfile_real_chunks_currentchunk['mime_type_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 1));
|
||||
$offset += 1;
|
||||
$thisfile_real_chunks_currentchunk['mime_type'] = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['mime_type_size']);
|
||||
$offset += $thisfile_real_chunks_currentchunk['mime_type_size'];
|
||||
$thisfile_real_chunks_currentchunk['type_specific_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['type_specific_data'] = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['type_specific_len']);
|
||||
$offset += $thisfile_real_chunks_currentchunk['type_specific_len'];
|
||||
|
||||
// shortcut
|
||||
$thisfile_real_chunks_currentchunk_typespecificdata = &$thisfile_real_chunks_currentchunk['type_specific_data'];
|
||||
|
||||
switch ($thisfile_real_chunks_currentchunk['mime_type']) {
|
||||
case 'video/x-pn-realvideo':
|
||||
case 'video/x-pn-multirate-realvideo':
|
||||
// http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html
|
||||
|
||||
// shortcut
|
||||
$thisfile_real_chunks_currentchunk['video_info'] = array();
|
||||
$thisfile_real_chunks_currentchunk_videoinfo = &$thisfile_real_chunks_currentchunk['video_info'];
|
||||
|
||||
$thisfile_real_chunks_currentchunk_videoinfo['dwSize'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 0, 4));
|
||||
$thisfile_real_chunks_currentchunk_videoinfo['fourcc1'] = substr($thisfile_real_chunks_currentchunk_typespecificdata, 4, 4);
|
||||
$thisfile_real_chunks_currentchunk_videoinfo['fourcc2'] = substr($thisfile_real_chunks_currentchunk_typespecificdata, 8, 4);
|
||||
$thisfile_real_chunks_currentchunk_videoinfo['width'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 12, 2));
|
||||
$thisfile_real_chunks_currentchunk_videoinfo['height'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 14, 2));
|
||||
$thisfile_real_chunks_currentchunk_videoinfo['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 16, 2));
|
||||
//$thisfile_real_chunks_currentchunk_videoinfo['unknown1'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 18, 2));
|
||||
//$thisfile_real_chunks_currentchunk_videoinfo['unknown2'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 20, 2));
|
||||
$thisfile_real_chunks_currentchunk_videoinfo['frames_per_second'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 22, 2));
|
||||
//$thisfile_real_chunks_currentchunk_videoinfo['unknown3'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 24, 2));
|
||||
//$thisfile_real_chunks_currentchunk_videoinfo['unknown4'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 26, 2));
|
||||
//$thisfile_real_chunks_currentchunk_videoinfo['unknown5'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 28, 2));
|
||||
//$thisfile_real_chunks_currentchunk_videoinfo['unknown6'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 30, 2));
|
||||
//$thisfile_real_chunks_currentchunk_videoinfo['unknown7'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 32, 2));
|
||||
//$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']);
|
||||
|
||||
$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']);
|
||||
|
||||
$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') {
|
||||
$info['audio']['streams'][$thisfile_real_chunks_currentchunk['stream_number']][$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'logical-fileinfo':
|
||||
// shortcut
|
||||
$thisfile_real_chunks_currentchunk['logical_fileinfo'] = array();
|
||||
$thisfile_real_chunks_currentchunk_logicalfileinfo = &$thisfile_real_chunks_currentchunk['logical_fileinfo'];
|
||||
|
||||
$thisfile_real_chunks_currentchunk_logicalfileinfo_offset = 0;
|
||||
$thisfile_real_chunks_currentchunk_logicalfileinfo['logical_fileinfo_length'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4));
|
||||
$thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4;
|
||||
|
||||
//$thisfile_real_chunks_currentchunk_logicalfileinfo['unknown1'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4));
|
||||
$thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4;
|
||||
|
||||
$thisfile_real_chunks_currentchunk_logicalfileinfo['num_tags'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4));
|
||||
$thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4;
|
||||
|
||||
//$thisfile_real_chunks_currentchunk_logicalfileinfo['unknown2'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4));
|
||||
$thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4;
|
||||
|
||||
//$thisfile_real_chunks_currentchunk_logicalfileinfo['d'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 1));
|
||||
|
||||
//$thisfile_real_chunks_currentchunk_logicalfileinfo['one_type'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4));
|
||||
//$thisfile_real_chunks_currentchunk_logicalfileinfo_thislength = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 4 + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 2));
|
||||
//$thisfile_real_chunks_currentchunk_logicalfileinfo['one'] = substr($thisfile_real_chunks_currentchunk_typespecificdata, 6 + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, $thisfile_real_chunks_currentchunk_logicalfileinfo_thislength);
|
||||
//$thisfile_real_chunks_currentchunk_logicalfileinfo_offset += (6 + $thisfile_real_chunks_currentchunk_logicalfileinfo_thislength);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
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':
|
||||
$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':
|
||||
$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':
|
||||
$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;
|
||||
}
|
||||
$info['bitrate'] = (isset($info['video']['bitrate']) ? $info['video']['bitrate'] : 0) + (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'CONT': // Content Description Header (text comments)
|
||||
$thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
|
||||
$offset += 2;
|
||||
if ($thisfile_real_chunks_currentchunk['object_version'] == 0) {
|
||||
$thisfile_real_chunks_currentchunk['title_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_real_chunks_currentchunk['title'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['title_len']);
|
||||
$offset += $thisfile_real_chunks_currentchunk['title_len'];
|
||||
|
||||
$thisfile_real_chunks_currentchunk['artist_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_real_chunks_currentchunk['artist'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['artist_len']);
|
||||
$offset += $thisfile_real_chunks_currentchunk['artist_len'];
|
||||
|
||||
$thisfile_real_chunks_currentchunk['copyright_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_real_chunks_currentchunk['copyright'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['copyright_len']);
|
||||
$offset += $thisfile_real_chunks_currentchunk['copyright_len'];
|
||||
|
||||
$thisfile_real_chunks_currentchunk['comment_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_real_chunks_currentchunk['comment'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['comment_len']);
|
||||
$offset += $thisfile_real_chunks_currentchunk['comment_len'];
|
||||
|
||||
|
||||
$commentkeystocopy = array('title'=>'title', 'artist'=>'artist', 'copyright'=>'copyright', 'comment'=>'comment');
|
||||
foreach ($commentkeystocopy as $key => $val) {
|
||||
if ($thisfile_real_chunks_currentchunk[$key]) {
|
||||
$info['real']['comments'][$val][] = trim($thisfile_real_chunks_currentchunk[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'DATA': // Data Chunk Header
|
||||
// do nothing
|
||||
break;
|
||||
|
||||
case 'INDX': // Index Section Header
|
||||
$thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
|
||||
$offset += 2;
|
||||
if ($thisfile_real_chunks_currentchunk['object_version'] == 0) {
|
||||
$thisfile_real_chunks_currentchunk['num_indices'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_real_chunks_currentchunk['stream_number'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_real_chunks_currentchunk['next_index_header'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
if ($thisfile_real_chunks_currentchunk['next_index_header'] == 0) {
|
||||
// last index chunk found, ignore rest of file
|
||||
break 2;
|
||||
} else {
|
||||
// non-last index chunk, seek to next index chunk (skipping actual index data)
|
||||
fseek($this->getid3->fp, $thisfile_real_chunks_currentchunk['next_index_header'], SEEK_SET);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unhandled RealMedia chunk "'.$ChunkName.'" at offset '.$thisfile_real_chunks_currentchunk['offset'];
|
||||
break;
|
||||
}
|
||||
$ChunkCounter++;
|
||||
}
|
||||
|
||||
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) {
|
||||
// http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html
|
||||
|
||||
$ParsedArray = array();
|
||||
$ParsedArray['magic'] = substr($OldRAheaderData, 0, 4);
|
||||
if ($ParsedArray['magic'] != '.ra'."\xFD") {
|
||||
return false;
|
||||
}
|
||||
$ParsedArray['version1'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 4, 2));
|
||||
|
||||
if ($ParsedArray['version1'] < 3) {
|
||||
|
||||
return false;
|
||||
|
||||
} elseif ($ParsedArray['version1'] == 3) {
|
||||
|
||||
$ParsedArray['fourcc1'] = '.ra3';
|
||||
$ParsedArray['bits_per_sample'] = 16; // hard-coded for old versions?
|
||||
$ParsedArray['sample_rate'] = 8000; // hard-coded for old versions?
|
||||
|
||||
$ParsedArray['header_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 6, 2));
|
||||
$ParsedArray['channels'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 8, 2)); // always 1 (?)
|
||||
//$ParsedArray['unknown1'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 10, 2));
|
||||
//$ParsedArray['unknown2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 12, 2));
|
||||
//$ParsedArray['unknown3'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 14, 2));
|
||||
$ParsedArray['bytes_per_minute'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 16, 2));
|
||||
$ParsedArray['audio_bytes'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 18, 4));
|
||||
$ParsedArray['comments_raw'] = substr($OldRAheaderData, 22, $ParsedArray['header_size'] - 22 + 1); // not including null terminator
|
||||
|
||||
$commentoffset = 0;
|
||||
$commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
|
||||
$ParsedArray['comments']['title'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
|
||||
$commentoffset += $commentlength;
|
||||
|
||||
$commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
|
||||
$ParsedArray['comments']['artist'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
|
||||
$commentoffset += $commentlength;
|
||||
|
||||
$commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
|
||||
$ParsedArray['comments']['copyright'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
|
||||
$commentoffset += $commentlength;
|
||||
|
||||
$commentoffset++; // final null terminator (?)
|
||||
$commentoffset++; // fourcc length (?) should be 4
|
||||
$ParsedArray['fourcc'] = substr($OldRAheaderData, 23 + $commentoffset, 4);
|
||||
|
||||
} elseif ($ParsedArray['version1'] <= 5) {
|
||||
|
||||
//$ParsedArray['unknown1'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 6, 2));
|
||||
$ParsedArray['fourcc1'] = substr($OldRAheaderData, 8, 4);
|
||||
$ParsedArray['file_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 12, 4));
|
||||
$ParsedArray['version2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 16, 2));
|
||||
$ParsedArray['header_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 18, 4));
|
||||
$ParsedArray['codec_flavor_id'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 22, 2));
|
||||
$ParsedArray['coded_frame_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 24, 4));
|
||||
$ParsedArray['audio_bytes'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 28, 4));
|
||||
$ParsedArray['bytes_per_minute'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 32, 4));
|
||||
//$ParsedArray['unknown5'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 36, 4));
|
||||
$ParsedArray['sub_packet_h'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 40, 2));
|
||||
$ParsedArray['frame_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 42, 2));
|
||||
$ParsedArray['sub_packet_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 44, 2));
|
||||
//$ParsedArray['unknown6'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 46, 2));
|
||||
|
||||
switch ($ParsedArray['version1']) {
|
||||
|
||||
case 4:
|
||||
$ParsedArray['sample_rate'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 48, 2));
|
||||
//$ParsedArray['unknown8'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 50, 2));
|
||||
$ParsedArray['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 52, 2));
|
||||
$ParsedArray['channels'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 54, 2));
|
||||
$ParsedArray['length_fourcc2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 56, 1));
|
||||
$ParsedArray['fourcc2'] = substr($OldRAheaderData, 57, 4);
|
||||
$ParsedArray['length_fourcc3'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 61, 1));
|
||||
$ParsedArray['fourcc3'] = substr($OldRAheaderData, 62, 4);
|
||||
//$ParsedArray['unknown9'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 66, 1));
|
||||
//$ParsedArray['unknown10'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 67, 2));
|
||||
$ParsedArray['comments_raw'] = substr($OldRAheaderData, 69, $ParsedArray['header_size'] - 69 + 16);
|
||||
|
||||
$commentoffset = 0;
|
||||
$commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
|
||||
$ParsedArray['comments']['title'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
|
||||
$commentoffset += $commentlength;
|
||||
|
||||
$commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
|
||||
$ParsedArray['comments']['artist'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
|
||||
$commentoffset += $commentlength;
|
||||
|
||||
$commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
|
||||
$ParsedArray['comments']['copyright'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
|
||||
$commentoffset += $commentlength;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
$ParsedArray['sample_rate'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 48, 4));
|
||||
$ParsedArray['sample_rate2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 52, 4));
|
||||
$ParsedArray['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 56, 4));
|
||||
$ParsedArray['channels'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 60, 2));
|
||||
$ParsedArray['genr'] = substr($OldRAheaderData, 62, 4);
|
||||
$ParsedArray['fourcc3'] = substr($OldRAheaderData, 66, 4);
|
||||
$ParsedArray['comments'] = array();
|
||||
break;
|
||||
}
|
||||
$ParsedArray['fourcc'] = $ParsedArray['fourcc3'];
|
||||
|
||||
}
|
||||
foreach ($ParsedArray['comments'] as $key => $value) {
|
||||
if ($ParsedArray['comments'][$key][0] === false) {
|
||||
$ParsedArray['comments'][$key][0] = '';
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function RealAudioCodecFourCClookup($fourcc, $bitrate) {
|
||||
static $RealAudioCodecFourCClookup = array();
|
||||
if (empty($RealAudioCodecFourCClookup)) {
|
||||
// http://www.its.msstate.edu/net/real/reports/config/tags.stats
|
||||
// http://www.freelists.org/archives/matroska-devel/06-2003/fullthread18.html
|
||||
|
||||
$RealAudioCodecFourCClookup['14_4'][8000] = 'RealAudio v2 (14.4kbps)';
|
||||
$RealAudioCodecFourCClookup['14.4'][8000] = 'RealAudio v2 (14.4kbps)';
|
||||
$RealAudioCodecFourCClookup['lpcJ'][8000] = 'RealAudio v2 (14.4kbps)';
|
||||
$RealAudioCodecFourCClookup['28_8'][15200] = 'RealAudio v2 (28.8kbps)';
|
||||
$RealAudioCodecFourCClookup['28.8'][15200] = 'RealAudio v2 (28.8kbps)';
|
||||
$RealAudioCodecFourCClookup['sipr'][4933] = 'RealAudio v4 (5kbps Voice)';
|
||||
$RealAudioCodecFourCClookup['sipr'][6444] = 'RealAudio v4 (6.5kbps Voice)';
|
||||
$RealAudioCodecFourCClookup['sipr'][8444] = 'RealAudio v4 (8.5kbps Voice)';
|
||||
$RealAudioCodecFourCClookup['sipr'][16000] = 'RealAudio v4 (16kbps Wideband)';
|
||||
$RealAudioCodecFourCClookup['dnet'][8000] = 'RealAudio v3 (8kbps Music)';
|
||||
$RealAudioCodecFourCClookup['dnet'][16000] = 'RealAudio v3 (16kbps Music Low Response)';
|
||||
$RealAudioCodecFourCClookup['dnet'][15963] = 'RealAudio v3 (16kbps Music Mid/High Response)';
|
||||
$RealAudioCodecFourCClookup['dnet'][20000] = 'RealAudio v3 (20kbps Music Stereo)';
|
||||
$RealAudioCodecFourCClookup['dnet'][32000] = 'RealAudio v3 (32kbps Music Mono)';
|
||||
$RealAudioCodecFourCClookup['dnet'][31951] = 'RealAudio v3 (32kbps Music Stereo)';
|
||||
$RealAudioCodecFourCClookup['dnet'][39965] = 'RealAudio v3 (40kbps Music Mono)';
|
||||
$RealAudioCodecFourCClookup['dnet'][40000] = 'RealAudio v3 (40kbps Music Stereo)';
|
||||
$RealAudioCodecFourCClookup['dnet'][79947] = 'RealAudio v3 (80kbps Music Mono)';
|
||||
$RealAudioCodecFourCClookup['dnet'][80000] = 'RealAudio v3 (80kbps Music Stereo)';
|
||||
|
||||
$RealAudioCodecFourCClookup['dnet'][0] = 'RealAudio v3';
|
||||
$RealAudioCodecFourCClookup['sipr'][0] = 'RealAudio v4';
|
||||
$RealAudioCodecFourCClookup['cook'][0] = 'RealAudio G2';
|
||||
$RealAudioCodecFourCClookup['atrc'][0] = 'RealAudio 8';
|
||||
}
|
||||
$roundbitrate = intval(round($bitrate));
|
||||
if (isset($RealAudioCodecFourCClookup[$fourcc][$roundbitrate])) {
|
||||
return $RealAudioCodecFourCClookup[$fourcc][$roundbitrate];
|
||||
} elseif (isset($RealAudioCodecFourCClookup[$fourcc][0])) {
|
||||
return $RealAudioCodecFourCClookup[$fourcc][0];
|
||||
}
|
||||
return $fourcc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
File diff suppressed because it is too large
Load Diff
@ -1,142 +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 extends getid3_handler
|
||||
{
|
||||
var $ReturnAllTagData = false;
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'swf';
|
||||
$info['video']['dataformat'] = 'swf';
|
||||
|
||||
// http://www.openswf.org/spec/SWFfileformat.html
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
|
||||
$SWFfileData = fread($this->getid3->fp, $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:
|
||||
$info['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;
|
||||
break;
|
||||
}
|
||||
$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 {
|
||||
$info['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;
|
||||
}
|
||||
|
||||
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
|
||||
//$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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -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.audio.aa.php //
|
||||
// module for analyzing Audible Audiobook files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_aa extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$AAheader = fread($this->getid3->fp, 8);
|
||||
|
||||
$magic = "\x57\x90\x75\x36";
|
||||
if (substr($AAheader, 4, 4) != $magic) {
|
||||
$info['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_au = &$info['aa'];
|
||||
|
||||
$info['fileformat'] = 'aa';
|
||||
$info['audio']['dataformat'] = 'aa';
|
||||
$info['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'] > ($info['avdataend'] - $info['avdataoffset'])) {
|
||||
$info['warning'][] = 'Possible truncated file - expecting "'.$thisfile_au['filesize'].'" bytes of data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"';
|
||||
}
|
||||
|
||||
$info['audio']['bits_per_sample'] = 16; // is it?
|
||||
$info['audio']['sample_rate'] = $thisfile_au['sample_rate'];
|
||||
$info['audio']['channels'] = $thisfile_au['channels'];
|
||||
|
||||
//$info['playtime_seconds'] = 0;
|
||||
//$info['audio']['bitrate'] = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,515 +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 extends getid3_handler
|
||||
{
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
if (fread($this->getid3->fp, 4) == 'ADIF') {
|
||||
$this->getAACADIFheaderFilepointer();
|
||||
} else {
|
||||
$this->getAACADTSheaderFilepointer();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getAACADIFheaderFilepointer() {
|
||||
$info = &$this->getid3->info;
|
||||
$info['fileformat'] = 'aac';
|
||||
$info['audio']['dataformat'] = 'aac';
|
||||
$info['audio']['lossless'] = false;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$AACheader = fread($this->getid3->fp, 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'] = (bool) (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'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
|
||||
$bitoffset += 1;
|
||||
$info['aac']['header']['home'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
|
||||
$bitoffset += 1;
|
||||
$info['aac']['header']['is_vbr'] = (bool) (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) {
|
||||
$info['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']);
|
||||
$info['error'][] = 'AAC-ADIF synch not found at offset '.$info['avdataoffset'].' (expected "ADIF", found "'.substr($AACheader, 0, 4).'" instead)';
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
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)) {
|
||||
$info['warning'][] = 'Unable to parse AAC file beyond '.ftell($this->getid3->fp).' (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)';
|
||||
return false;
|
||||
}
|
||||
fseek($this->getid3->fp, $byteoffset, SEEK_SET);
|
||||
|
||||
// First get substring
|
||||
$substring = fread($this->getid3->fp, 9); // header is 7 bytes (or 9 if CRC is present)
|
||||
$substringlength = strlen($substring);
|
||||
if ($substringlength != 9) {
|
||||
$info['error'][] = 'Failed to read 7 bytes at offset '.(ftell($this->getid3->fp) - $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) {
|
||||
$info['error'][] = 'Synch pattern (0x0FFF) not found at offset '.(ftell($this->getid3->fp) - $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) {
|
||||
$info['warning'][] = 'Layer error - expected "0", found "'.$info['aac']['header']['raw']['mpeg_layer'].'" instead';
|
||||
}
|
||||
if ($info['aac']['header']['sample_frequency'] == 0) {
|
||||
$info['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'][$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) {
|
||||
$info['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.
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,473 +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 extends getid3_handler
|
||||
{
|
||||
private $AC3header = '';
|
||||
private $BSIoffset = 0;
|
||||
|
||||
|
||||
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
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$this->AC3header['syncinfo'] = fread($this->getid3->fp, 5);
|
||||
$thisfile_ac3_raw['synchinfo']['synchword'] = substr($this->AC3header['syncinfo'], 0, 2);
|
||||
|
||||
$magic = "\x0B\x77";
|
||||
if ($thisfile_ac3_raw['synchinfo']['synchword'] != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_ac3_raw['synchinfo']['synchword']).'"';
|
||||
unset($info['fileformat'], $info['ac3']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['audio']['dataformat'] = 'ac3';
|
||||
$info['audio']['bitrate_mode'] = 'cbr';
|
||||
$info['audio']['lossless'] = false;
|
||||
|
||||
// syncinfo() {
|
||||
// syncword 16
|
||||
// crc1 16
|
||||
// fscod 2
|
||||
// frmsizecod 6
|
||||
// } /* end of syncinfo */
|
||||
|
||||
$thisfile_ac3_raw['synchinfo']['crc1'] = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], 2, 2));
|
||||
$ac3_synchinfo_fscod_frmsizecod = getid3_lib::LittleEndian2Int(substr($this->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) {
|
||||
$info['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']);
|
||||
$info['audio']['bitrate'] = $thisfile_ac3['bitrate'];
|
||||
|
||||
$this->AC3header['bsi'] = getid3_lib::BigEndian2Bin(fread($this->getid3->fp, 15));
|
||||
$ac3_bsi_offset = 0;
|
||||
|
||||
$thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(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.
|
||||
$info['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'] = $this->readHeaderBSI(3);
|
||||
$thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(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:
|
||||
$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'];
|
||||
|
||||
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'] = $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'] = $this->readHeaderBSI(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'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3['dolby_surround_mode'] = $this->AC3dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['lfeon'] = (bool) $this->readHeaderBSI(1);
|
||||
$thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['lfeon'];
|
||||
if ($thisfile_ac3_raw_bsi['lfeon']) {
|
||||
//$info['audio']['channels']++;
|
||||
$info['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'] = $this->readHeaderBSI(5);
|
||||
$thisfile_ac3['dialogue_normalization'] = '-'.$thisfile_ac3_raw_bsi['dialnorm'].'dB';
|
||||
|
||||
$thisfile_ac3_raw_bsi['compre_flag'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['compre_flag']) {
|
||||
$thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8);
|
||||
$thisfile_ac3['heavy_compression'] = $this->AC3heavyCompression($thisfile_ac3_raw_bsi['compr']);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['langcode_flag'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['langcode_flag']) {
|
||||
$thisfile_ac3_raw_bsi['langcod'] = $this->readHeaderBSI(8);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['audprodie'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['audprodie']) {
|
||||
$thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5);
|
||||
$thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(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'] = $this->readHeaderBSI(5);
|
||||
$thisfile_ac3['dialogue_normalization2'] = '-'.$thisfile_ac3_raw_bsi['dialnorm2'].'dB';
|
||||
|
||||
$thisfile_ac3_raw_bsi['compre_flag2'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['compre_flag2']) {
|
||||
$thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8);
|
||||
$thisfile_ac3['heavy_compression2'] = $this->AC3heavyCompression($thisfile_ac3_raw_bsi['compr2']);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['langcode_flag2'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['langcode_flag2']) {
|
||||
$thisfile_ac3_raw_bsi['langcod2'] = $this->readHeaderBSI(8);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['audprodie2'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['audprodie2']) {
|
||||
$thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5);
|
||||
$thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(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) $this->readHeaderBSI(1);
|
||||
|
||||
$thisfile_ac3_raw_bsi['original'] = (bool) $this->readHeaderBSI(1);
|
||||
|
||||
$thisfile_ac3_raw_bsi['timecode1_flag'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['timecode1_flag']) {
|
||||
$thisfile_ac3_raw_bsi['timecode1'] = $this->readHeaderBSI(14);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['timecode2_flag'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['timecode2_flag']) {
|
||||
$thisfile_ac3_raw_bsi['timecode2'] = $this->readHeaderBSI(14);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['addbsi_flag'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['addbsi_flag']) {
|
||||
$thisfile_ac3_raw_bsi['addbsi_length'] = $this->readHeaderBSI(6);
|
||||
|
||||
$this->AC3header['bsi'] .= getid3_lib::BigEndian2Bin(fread($this->getid3->fp, $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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function readHeaderBSI($length) {
|
||||
$data = substr($this->AC3header['bsi'], $this->BSIoffset, $length);
|
||||
$this->BSIoffset += $length;
|
||||
|
||||
return bindec($data);
|
||||
}
|
||||
|
||||
public static 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);
|
||||
}
|
||||
|
||||
public static 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);
|
||||
}
|
||||
|
||||
public static 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);
|
||||
}
|
||||
|
||||
public static 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);
|
||||
}
|
||||
|
||||
public static 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);
|
||||
}
|
||||
|
||||
public static 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);
|
||||
}
|
||||
|
||||
public static 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;
|
||||
}
|
||||
|
||||
public static 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;
|
||||
}
|
||||
|
||||
public static 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);
|
||||
}
|
||||
|
||||
public static 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);
|
||||
}
|
||||
|
||||
public static 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,165 +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.au.php //
|
||||
// module for analyzing AU files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_au extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$AUheader = fread($this->getid3->fp, 8);
|
||||
|
||||
$magic = '.snd';
|
||||
if (substr($AUheader, 0, 4) != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" (".snd") at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AUheader, 0, 4)).'"';
|
||||
return false;
|
||||
}
|
||||
|
||||
// shortcut
|
||||
$info['au'] = array();
|
||||
$thisfile_au = &$info['au'];
|
||||
|
||||
$info['fileformat'] = 'au';
|
||||
$info['audio']['dataformat'] = 'au';
|
||||
$info['audio']['bitrate_mode'] = 'cbr';
|
||||
$thisfile_au['encoding'] = 'ISO-8859-1';
|
||||
|
||||
$thisfile_au['header_length'] = getid3_lib::BigEndian2Int(substr($AUheader, 4, 4));
|
||||
$AUheader .= fread($this->getid3->fp, $thisfile_au['header_length'] - 8);
|
||||
$info['avdataoffset'] += $thisfile_au['header_length'];
|
||||
|
||||
$thisfile_au['data_size'] = getid3_lib::BigEndian2Int(substr($AUheader, 8, 4));
|
||||
$thisfile_au['data_format_id'] = getid3_lib::BigEndian2Int(substr($AUheader, 12, 4));
|
||||
$thisfile_au['sample_rate'] = getid3_lib::BigEndian2Int(substr($AUheader, 16, 4));
|
||||
$thisfile_au['channels'] = getid3_lib::BigEndian2Int(substr($AUheader, 20, 4));
|
||||
$thisfile_au['comments']['comment'][] = trim(substr($AUheader, 24));
|
||||
|
||||
$thisfile_au['data_format'] = $this->AUdataFormatNameLookup($thisfile_au['data_format_id']);
|
||||
$thisfile_au['used_bits_per_sample'] = $this->AUdataFormatUsedBitsPerSampleLookup($thisfile_au['data_format_id']);
|
||||
if ($thisfile_au['bits_per_sample'] = $this->AUdataFormatBitsPerSampleLookup($thisfile_au['data_format_id'])) {
|
||||
$info['audio']['bits_per_sample'] = $thisfile_au['bits_per_sample'];
|
||||
} else {
|
||||
unset($thisfile_au['bits_per_sample']);
|
||||
}
|
||||
|
||||
$info['audio']['sample_rate'] = $thisfile_au['sample_rate'];
|
||||
$info['audio']['channels'] = $thisfile_au['channels'];
|
||||
|
||||
if (($info['avdataoffset'] + $thisfile_au['data_size']) > $info['avdataend']) {
|
||||
$info['warning'][] = 'Possible truncated file - expecting "'.$thisfile_au['data_size'].'" bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"';
|
||||
}
|
||||
|
||||
$info['playtime_seconds'] = $thisfile_au['data_size'] / ($thisfile_au['sample_rate'] * $thisfile_au['channels'] * ($thisfile_au['used_bits_per_sample'] / 8));
|
||||
$info['audio']['bitrate'] = ($thisfile_au['data_size'] * 8) / $info['playtime_seconds'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function AUdataFormatNameLookup($id) {
|
||||
static $AUdataFormatNameLookup = array(
|
||||
0 => 'unspecified format',
|
||||
1 => '8-bit mu-law',
|
||||
2 => '8-bit linear',
|
||||
3 => '16-bit linear',
|
||||
4 => '24-bit linear',
|
||||
5 => '32-bit linear',
|
||||
6 => 'floating-point',
|
||||
7 => 'double-precision float',
|
||||
8 => 'fragmented sampled data',
|
||||
9 => 'SUN_FORMAT_NESTED',
|
||||
10 => 'DSP program',
|
||||
11 => '8-bit fixed-point',
|
||||
12 => '16-bit fixed-point',
|
||||
13 => '24-bit fixed-point',
|
||||
14 => '32-bit fixed-point',
|
||||
|
||||
16 => 'non-audio display data',
|
||||
17 => 'SND_FORMAT_MULAW_SQUELCH',
|
||||
18 => '16-bit linear with emphasis',
|
||||
19 => '16-bit linear with compression',
|
||||
20 => '16-bit linear with emphasis + compression',
|
||||
21 => 'Music Kit DSP commands',
|
||||
22 => 'SND_FORMAT_DSP_COMMANDS_SAMPLES',
|
||||
23 => 'CCITT g.721 4-bit ADPCM',
|
||||
24 => 'CCITT g.722 ADPCM',
|
||||
25 => 'CCITT g.723 3-bit ADPCM',
|
||||
26 => 'CCITT g.723 5-bit ADPCM',
|
||||
27 => 'A-Law 8-bit'
|
||||
);
|
||||
return (isset($AUdataFormatNameLookup[$id]) ? $AUdataFormatNameLookup[$id] : false);
|
||||
}
|
||||
|
||||
function AUdataFormatBitsPerSampleLookup($id) {
|
||||
static $AUdataFormatBitsPerSampleLookup = array(
|
||||
1 => 8,
|
||||
2 => 8,
|
||||
3 => 16,
|
||||
4 => 24,
|
||||
5 => 32,
|
||||
6 => 32,
|
||||
7 => 64,
|
||||
|
||||
11 => 8,
|
||||
12 => 16,
|
||||
13 => 24,
|
||||
14 => 32,
|
||||
|
||||
18 => 16,
|
||||
19 => 16,
|
||||
20 => 16,
|
||||
|
||||
23 => 16,
|
||||
|
||||
25 => 16,
|
||||
26 => 16,
|
||||
27 => 8
|
||||
);
|
||||
return (isset($AUdataFormatBitsPerSampleLookup[$id]) ? $AUdataFormatBitsPerSampleLookup[$id] : false);
|
||||
}
|
||||
|
||||
function AUdataFormatUsedBitsPerSampleLookup($id) {
|
||||
static $AUdataFormatUsedBitsPerSampleLookup = array(
|
||||
1 => 8,
|
||||
2 => 8,
|
||||
3 => 16,
|
||||
4 => 24,
|
||||
5 => 32,
|
||||
6 => 32,
|
||||
7 => 64,
|
||||
|
||||
11 => 8,
|
||||
12 => 16,
|
||||
13 => 24,
|
||||
14 => 32,
|
||||
|
||||
18 => 16,
|
||||
19 => 16,
|
||||
20 => 16,
|
||||
|
||||
23 => 4,
|
||||
|
||||
25 => 3,
|
||||
26 => 5,
|
||||
27 => 8,
|
||||
);
|
||||
return (isset($AUdataFormatUsedBitsPerSampleLookup[$id]) ? $AUdataFormatUsedBitsPerSampleLookup[$id] : false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,127 +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 extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// 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
|
||||
|
||||
$info['fileformat'] = 'avr';
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$AVRheader = fread($this->getid3->fp, 128);
|
||||
|
||||
$info['avr']['raw']['magic'] = substr($AVRheader, 0, 4);
|
||||
$magic = '2BIT';
|
||||
if ($info['avr']['raw']['magic'] != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['avr']['raw']['magic']).'"';
|
||||
unset($info['fileformat']);
|
||||
unset($info['avr']);
|
||||
return false;
|
||||
}
|
||||
$info['avdataoffset'] += 128;
|
||||
|
||||
$info['avr']['sample_name'] = rtrim(substr($AVRheader, 4, 8));
|
||||
$info['avr']['raw']['mono'] = getid3_lib::BigEndian2Int(substr($AVRheader, 12, 2));
|
||||
$info['avr']['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($AVRheader, 14, 2));
|
||||
$info['avr']['raw']['signed'] = getid3_lib::BigEndian2Int(substr($AVRheader, 16, 2));
|
||||
$info['avr']['raw']['loop'] = getid3_lib::BigEndian2Int(substr($AVRheader, 18, 2));
|
||||
$info['avr']['raw']['midi'] = getid3_lib::BigEndian2Int(substr($AVRheader, 20, 2));
|
||||
$info['avr']['raw']['replay_freq'] = getid3_lib::BigEndian2Int(substr($AVRheader, 22, 1));
|
||||
$info['avr']['sample_rate'] = getid3_lib::BigEndian2Int(substr($AVRheader, 23, 3));
|
||||
$info['avr']['sample_length'] = getid3_lib::BigEndian2Int(substr($AVRheader, 26, 4));
|
||||
$info['avr']['loop_start'] = getid3_lib::BigEndian2Int(substr($AVRheader, 30, 4));
|
||||
$info['avr']['loop_end'] = getid3_lib::BigEndian2Int(substr($AVRheader, 34, 4));
|
||||
$info['avr']['midi_split'] = getid3_lib::BigEndian2Int(substr($AVRheader, 38, 2));
|
||||
$info['avr']['sample_compression'] = getid3_lib::BigEndian2Int(substr($AVRheader, 40, 2));
|
||||
$info['avr']['reserved'] = getid3_lib::BigEndian2Int(substr($AVRheader, 42, 2));
|
||||
$info['avr']['sample_name_extra'] = rtrim(substr($AVRheader, 44, 20));
|
||||
$info['avr']['comment'] = rtrim(substr($AVRheader, 64, 64));
|
||||
|
||||
$info['avr']['flags']['stereo'] = (($info['avr']['raw']['mono'] == 0) ? false : true);
|
||||
$info['avr']['flags']['signed'] = (($info['avr']['raw']['signed'] == 0) ? false : true);
|
||||
$info['avr']['flags']['loop'] = (($info['avr']['raw']['loop'] == 0) ? false : true);
|
||||
|
||||
$info['avr']['midi_notes'] = array();
|
||||
if (($info['avr']['raw']['midi'] & 0xFF00) != 0xFF00) {
|
||||
$info['avr']['midi_notes'][] = ($info['avr']['raw']['midi'] & 0xFF00) >> 8;
|
||||
}
|
||||
if (($info['avr']['raw']['midi'] & 0x00FF) != 0x00FF) {
|
||||
$info['avr']['midi_notes'][] = ($info['avr']['raw']['midi'] & 0x00FF);
|
||||
}
|
||||
|
||||
if (($info['avdataend'] - $info['avdataoffset']) != ($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 1 : 2))) {
|
||||
$info['warning'][] = 'Probable truncated file: expecting '.($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 1 : 2)).' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']);
|
||||
}
|
||||
|
||||
$info['audio']['dataformat'] = 'avr';
|
||||
$info['audio']['lossless'] = true;
|
||||
$info['audio']['bitrate_mode'] = 'cbr';
|
||||
$info['audio']['bits_per_sample'] = $info['avr']['bits_per_sample'];
|
||||
$info['audio']['sample_rate'] = $info['avr']['sample_rate'];
|
||||
$info['audio']['channels'] = ($info['avr']['flags']['stereo'] ? 2 : 1);
|
||||
$info['playtime_seconds'] = ($info['avr']['sample_length'] / $info['audio']['channels']) / $info['avr']['sample_rate'];
|
||||
$info['audio']['bitrate'] = ($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 8 : 16)) / $info['playtime_seconds'];
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,230 +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 extends getid3_handler
|
||||
{
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// shortcut
|
||||
$info['bonk'] = array();
|
||||
$thisfile_bonk = &$info['bonk'];
|
||||
|
||||
$thisfile_bonk['dataoffset'] = $info['avdataoffset'];
|
||||
$thisfile_bonk['dataend'] = $info['avdataend'];
|
||||
|
||||
if (!getid3_lib::intValueSupported($thisfile_bonk['dataend'])) {
|
||||
|
||||
$info['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($this->getid3->fp, $thisfile_bonk['dataend'] - 8, SEEK_SET);
|
||||
$PossibleBonkTag = fread($this->getid3->fp, 8);
|
||||
while ($this->BonkIsValidTagName(substr($PossibleBonkTag, 4, 4), true)) {
|
||||
$BonkTagSize = getid3_lib::LittleEndian2Int(substr($PossibleBonkTag, 0, 4));
|
||||
fseek($this->getid3->fp, 0 - $BonkTagSize, SEEK_CUR);
|
||||
$BonkTagOffset = ftell($this->getid3->fp);
|
||||
$TagHeaderTest = fread($this->getid3->fp, 5);
|
||||
if (($TagHeaderTest{0} != "\x00") || (substr($PossibleBonkTag, 4, 4) != strtolower(substr($PossibleBonkTag, 4, 4)))) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes("\x00".strtoupper(substr($PossibleBonkTag, 4, 4))).'" at offset '.$BonkTagOffset.', found "'.getid3_lib::PrintHexBytes($TagHeaderTest).'"';
|
||||
return false;
|
||||
}
|
||||
$BonkTagName = substr($TagHeaderTest, 1, 4);
|
||||
|
||||
$thisfile_bonk[$BonkTagName]['size'] = $BonkTagSize;
|
||||
$thisfile_bonk[$BonkTagName]['offset'] = $BonkTagOffset;
|
||||
$this->HandleBonkTags($BonkTagName);
|
||||
$NextTagEndOffset = $BonkTagOffset - 8;
|
||||
if ($NextTagEndOffset < $thisfile_bonk['dataoffset']) {
|
||||
if (empty($info['audio']['encoder'])) {
|
||||
$info['audio']['encoder'] = 'Extended BONK v0.9+';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
fseek($this->getid3->fp, $NextTagEndOffset, SEEK_SET);
|
||||
$PossibleBonkTag = fread($this->getid3->fp, 8);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// seek-from-beginning method for v0.4 and v0.5
|
||||
if (empty($thisfile_bonk['BONK'])) {
|
||||
fseek($this->getid3->fp, $thisfile_bonk['dataoffset'], SEEK_SET);
|
||||
do {
|
||||
$TagHeaderTest = fread($this->getid3->fp, 5);
|
||||
switch ($TagHeaderTest) {
|
||||
case "\x00".'BONK':
|
||||
if (empty($info['audio']['encoder'])) {
|
||||
$info['audio']['encoder'] = 'BONK v0.4';
|
||||
}
|
||||
break;
|
||||
|
||||
case "\x00".'INFO':
|
||||
$info['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($BonkTagName);
|
||||
|
||||
} while (true);
|
||||
}
|
||||
|
||||
// parse META block for v0.6 - v0.8
|
||||
if (empty($thisfile_bonk['INFO']) && isset($thisfile_bonk['META']['tags']['info'])) {
|
||||
fseek($this->getid3->fp, $thisfile_bonk['META']['tags']['info'], SEEK_SET);
|
||||
$TagHeaderTest = fread($this->getid3->fp, 5);
|
||||
if ($TagHeaderTest == "\x00".'INFO') {
|
||||
$info['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($BonkTagName);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($info['audio']['encoder'])) {
|
||||
$info['audio']['encoder'] = 'Extended BONK v0.9+';
|
||||
}
|
||||
if (empty($thisfile_bonk['BONK'])) {
|
||||
unset($info['bonk']);
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
function HandleBonkTags($BonkTagName) {
|
||||
$info = &$this->getid3->info;
|
||||
switch ($BonkTagName) {
|
||||
case 'BONK':
|
||||
// shortcut
|
||||
$thisfile_bonk_BONK = &$info['bonk']['BONK'];
|
||||
|
||||
$BonkData = "\x00".'BONK'.fread($this->getid3->fp, 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));
|
||||
|
||||
$info['avdataoffset'] = $thisfile_bonk_BONK['offset'] + 5 + 17;
|
||||
$info['avdataend'] = $thisfile_bonk_BONK['offset'] + $thisfile_bonk_BONK['size'];
|
||||
|
||||
$info['fileformat'] = 'bonk';
|
||||
$info['audio']['dataformat'] = 'bonk';
|
||||
$info['audio']['bitrate_mode'] = 'vbr'; // assumed
|
||||
$info['audio']['channels'] = $thisfile_bonk_BONK['channels'];
|
||||
$info['audio']['sample_rate'] = $thisfile_bonk_BONK['sample_rate'];
|
||||
$info['audio']['channelmode'] = ($thisfile_bonk_BONK['joint_stereo'] ? 'joint stereo' : 'stereo');
|
||||
$info['audio']['lossless'] = $thisfile_bonk_BONK['lossless'];
|
||||
$info['audio']['codec'] = 'bonk';
|
||||
|
||||
$info['playtime_seconds'] = $thisfile_bonk_BONK['number_samples'] / ($thisfile_bonk_BONK['sample_rate'] * $thisfile_bonk_BONK['channels']);
|
||||
if ($info['playtime_seconds'] > 0) {
|
||||
$info['audio']['bitrate'] = (($info['bonk']['dataend'] - $info['bonk']['dataoffset']) * 8) / $info['playtime_seconds'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'INFO':
|
||||
// shortcut
|
||||
$thisfile_bonk_INFO = &$info['bonk']['INFO'];
|
||||
|
||||
$thisfile_bonk_INFO['version'] = getid3_lib::LittleEndian2Int(fread($this->getid3->fp, 1));
|
||||
$thisfile_bonk_INFO['entries_count'] = 0;
|
||||
$NextInfoDataPair = fread($this->getid3->fp, 5);
|
||||
if (!$this->BonkIsValidTagName(substr($NextInfoDataPair, 1, 4))) {
|
||||
while (!feof($this->getid3->fp)) {
|
||||
//$CurrentSeekInfo['offset'] = getid3_lib::LittleEndian2Int(substr($NextInfoDataPair, 0, 4));
|
||||
//$CurrentSeekInfo['nextbit'] = getid3_lib::LittleEndian2Int(substr($NextInfoDataPair, 4, 1));
|
||||
//$thisfile_bonk_INFO[] = $CurrentSeekInfo;
|
||||
|
||||
$NextInfoDataPair = fread($this->getid3->fp, 5);
|
||||
if ($this->BonkIsValidTagName(substr($NextInfoDataPair, 1, 4))) {
|
||||
fseek($this->getid3->fp, -5, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
$thisfile_bonk_INFO['entries_count']++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'META':
|
||||
$BonkData = "\x00".'META'.fread($this->getid3->fp, $info['bonk']['META']['size'] - 5);
|
||||
$info['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;
|
||||
$info['bonk']['META']['tags'][$MetaEntryTagName] = $MetaEntryTagOffset;
|
||||
}
|
||||
break;
|
||||
|
||||
case ' ID3':
|
||||
$info['audio']['encoder'] = 'Extended BONK v0.9+';
|
||||
|
||||
// ID3v2 checking is optional
|
||||
if (class_exists('getid3_id3v2')) {
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_id3v2 = new getid3_id3v2($getid3_temp);
|
||||
$getid3_id3v2->StartingOffset = $info['bonk'][' ID3']['offset'] + 2;
|
||||
$info['bonk'][' ID3']['valid'] = $getid3_id3v2->Analyze();
|
||||
if ($info['bonk'][' ID3']['valid']) {
|
||||
$info['id3v2'] = $getid3_temp->info['id3v2'];
|
||||
}
|
||||
unset($getid3_temp, $getid3_id3v2);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unexpected Bonk tag "'.$BonkTagName.'" at offset '.$info['bonk'][$BonkTagName]['offset'];
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static 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,75 +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 extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$DSSheader = fread($this->getid3->fp, 1256);
|
||||
|
||||
if (!preg_match('#^(\x02|\x03)dss#', $DSSheader)) {
|
||||
$info['error'][] = 'Expecting "[02-03] 64 73 73" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(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
|
||||
$info['dss'] = array();
|
||||
$thisfile_dss = &$info['dss'];
|
||||
|
||||
$info['fileformat'] = 'dss';
|
||||
$info['audio']['dataformat'] = 'dss';
|
||||
$info['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));
|
||||
|
||||
|
||||
//$info['audio']['bits_per_sample'] = ?;
|
||||
//$info['audio']['sample_rate'] = ?;
|
||||
$info['audio']['channels'] = 1;
|
||||
|
||||
$info['playtime_seconds'] = $thisfile_dss['length'];
|
||||
$info['audio']['bitrate'] = ($info['filesize'] * 8) / $info['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,246 +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 extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// 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/
|
||||
|
||||
$info['fileformat'] = 'dts';
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$DTSheader = fread($this->getid3->fp, 16);
|
||||
$info['dts']['raw']['magic'] = substr($DTSheader, 0, 4);
|
||||
|
||||
$magic = "\x7F\xFE\x80\x01";
|
||||
if ($info['dts']['raw']['magic'] != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['dts']['raw']['magic']).'"';
|
||||
unset($info['fileformat'], $info['dts']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$fhBS = getid3_lib::BigEndian2Bin(substr($DTSheader, 4, 12));
|
||||
$bsOffset = 0;
|
||||
$info['dts']['raw']['frame_type'] = $this->readBinData($fhBS, $bsOffset, 1);
|
||||
$info['dts']['raw']['deficit_samples'] = $this->readBinData($fhBS, $bsOffset, 5);
|
||||
$info['dts']['flags']['crc_present'] = (bool) $this->readBinData($fhBS, $bsOffset, 1);
|
||||
$info['dts']['raw']['pcm_sample_blocks'] = $this->readBinData($fhBS, $bsOffset, 7);
|
||||
$info['dts']['raw']['frame_byte_size'] = $this->readBinData($fhBS, $bsOffset, 14);
|
||||
$info['dts']['raw']['channel_arrangement'] = $this->readBinData($fhBS, $bsOffset, 6);
|
||||
$info['dts']['raw']['sample_frequency'] = $this->readBinData($fhBS, $bsOffset, 4);
|
||||
$info['dts']['raw']['bitrate'] = $this->readBinData($fhBS, $bsOffset, 5);
|
||||
$info['dts']['flags']['embedded_downmix'] = (bool) $this->readBinData($fhBS, $bsOffset, 1);
|
||||
$info['dts']['flags']['dynamicrange'] = (bool) $this->readBinData($fhBS, $bsOffset, 1);
|
||||
$info['dts']['flags']['timestamp'] = (bool) $this->readBinData($fhBS, $bsOffset, 1);
|
||||
$info['dts']['flags']['auxdata'] = (bool) $this->readBinData($fhBS, $bsOffset, 1);
|
||||
$info['dts']['flags']['hdcd'] = (bool) $this->readBinData($fhBS, $bsOffset, 1);
|
||||
$info['dts']['raw']['extension_audio'] = $this->readBinData($fhBS, $bsOffset, 3);
|
||||
$info['dts']['flags']['extended_coding'] = (bool) $this->readBinData($fhBS, $bsOffset, 1);
|
||||
$info['dts']['flags']['audio_sync_insertion'] = (bool) $this->readBinData($fhBS, $bsOffset, 1);
|
||||
$info['dts']['raw']['lfe_effects'] = $this->readBinData($fhBS, $bsOffset, 2);
|
||||
$info['dts']['flags']['predictor_history'] = (bool) $this->readBinData($fhBS, $bsOffset, 1);
|
||||
if ($info['dts']['flags']['crc_present']) {
|
||||
$info['dts']['raw']['crc16'] = $this->readBinData($fhBS, $bsOffset, 16);
|
||||
}
|
||||
$info['dts']['flags']['mri_perfect_reconst'] = (bool) $this->readBinData($fhBS, $bsOffset, 1);
|
||||
$info['dts']['raw']['encoder_soft_version'] = $this->readBinData($fhBS, $bsOffset, 4);
|
||||
$info['dts']['raw']['copy_history'] = $this->readBinData($fhBS, $bsOffset, 2);
|
||||
$info['dts']['raw']['bits_per_sample'] = $this->readBinData($fhBS, $bsOffset, 2);
|
||||
$info['dts']['flags']['surround_es'] = (bool) $this->readBinData($fhBS, $bsOffset, 1);
|
||||
$info['dts']['flags']['front_sum_diff'] = (bool) $this->readBinData($fhBS, $bsOffset, 1);
|
||||
$info['dts']['flags']['surround_sum_diff'] = (bool) $this->readBinData($fhBS, $bsOffset, 1);
|
||||
$info['dts']['raw']['dialog_normalization'] = $this->readBinData($fhBS, $bsOffset, 4);
|
||||
|
||||
|
||||
$info['dts']['bitrate'] = self::DTSbitrateLookup($info['dts']['raw']['bitrate']);
|
||||
$info['dts']['bits_per_sample'] = self::DTSbitPerSampleLookup($info['dts']['raw']['bits_per_sample']);
|
||||
$info['dts']['sample_rate'] = self::DTSsampleRateLookup($info['dts']['raw']['sample_frequency']);
|
||||
$info['dts']['dialog_normalization'] = self::DTSdialogNormalization($info['dts']['raw']['dialog_normalization'], $info['dts']['raw']['encoder_soft_version']);
|
||||
$info['dts']['flags']['lossless'] = (($info['dts']['raw']['bitrate'] == 31) ? true : false);
|
||||
$info['dts']['bitrate_mode'] = (($info['dts']['raw']['bitrate'] == 30) ? 'vbr' : 'cbr');
|
||||
$info['dts']['channels'] = self::DTSnumChannelsLookup($info['dts']['raw']['channel_arrangement']);
|
||||
$info['dts']['channel_arrangement'] = self::DTSchannelArrangementLookup($info['dts']['raw']['channel_arrangement']);
|
||||
|
||||
$info['audio']['dataformat'] = 'dts';
|
||||
$info['audio']['lossless'] = $info['dts']['flags']['lossless'];
|
||||
$info['audio']['bitrate_mode'] = $info['dts']['bitrate_mode'];
|
||||
$info['audio']['bits_per_sample'] = $info['dts']['bits_per_sample'];
|
||||
$info['audio']['sample_rate'] = $info['dts']['sample_rate'];
|
||||
$info['audio']['channels'] = $info['dts']['channels'];
|
||||
$info['audio']['bitrate'] = $info['dts']['bitrate'];
|
||||
if (isset($info['avdataend'])) {
|
||||
$info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($info['dts']['bitrate'] / 8);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function readBinData($bin, &$offset, $length) {
|
||||
$data = substr($bin, $offset, $length);
|
||||
$offset += $length;
|
||||
return bindec($data);
|
||||
}
|
||||
|
||||
private static 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);
|
||||
}
|
||||
|
||||
private static 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);
|
||||
}
|
||||
|
||||
private static function DTSbitPerSampleLookup($index) {
|
||||
$DTSbitPerSampleLookup = array(
|
||||
0 => 16,
|
||||
1 => 20,
|
||||
2 => 24,
|
||||
3 => 24,
|
||||
);
|
||||
return (isset($DTSbitPerSampleLookup[$index]) ? $DTSbitPerSampleLookup[$index] : false);
|
||||
}
|
||||
|
||||
private static 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;
|
||||
}
|
||||
|
||||
private static 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');
|
||||
}
|
||||
|
||||
private static function DTSdialogNormalization($index, $version) {
|
||||
switch ($version) {
|
||||
case 7:
|
||||
return 0 - $index;
|
||||
break;
|
||||
case 6:
|
||||
return 0 - 16 - $index;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,480 +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 extends getid3_handler
|
||||
{
|
||||
var $inline_attachments = true; // true: return full data for all attachments; false: return no data for all attachments; integer: return data for attachments <= than this; string: save as file to this directory
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// http://flac.sourceforge.net/format.html
|
||||
|
||||
$this->fseek($info['avdataoffset'], SEEK_SET);
|
||||
$StreamMarker = $this->fread(4);
|
||||
$magic = 'fLaC';
|
||||
if ($StreamMarker != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($StreamMarker).'"';
|
||||
return false;
|
||||
}
|
||||
$info['fileformat'] = 'flac';
|
||||
$info['audio']['dataformat'] = 'flac';
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
$info['audio']['lossless'] = true;
|
||||
|
||||
return $this->FLACparseMETAdata();
|
||||
}
|
||||
|
||||
|
||||
function FLACparseMETAdata() {
|
||||
$info = &$this->getid3->info;
|
||||
do {
|
||||
$METAdataBlockOffset = $this->ftell();
|
||||
$METAdataBlockHeader = $this->fread(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) {
|
||||
$info['error'][] = 'corrupt or invalid METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$METAdataBlockType.') at offset '.$METAdataBlockOffset;
|
||||
break;
|
||||
}
|
||||
|
||||
$info['flac'][$METAdataBlockTypeText]['raw'] = array();
|
||||
$ThisFileInfo_flac_METAdataBlockTypeText_raw = &$info['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;
|
||||
if (($METAdataBlockOffset + 4 + $METAdataBlockLength) > $info['avdataend']) {
|
||||
$info['error'][] = 'METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$METAdataBlockType.') at offset '.$METAdataBlockOffset.' extends beyond end of file';
|
||||
break;
|
||||
}
|
||||
if ($METAdataBlockLength < 1) {
|
||||
$info['error'][] = 'METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$METAdataBlockLength.') at offset '.$METAdataBlockOffset.' is invalid';
|
||||
break;
|
||||
}
|
||||
$ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'] = $this->fread($METAdataBlockLength);
|
||||
$info['avdataoffset'] = $this->ftell();
|
||||
|
||||
switch ($METAdataBlockTypeText) {
|
||||
case 'STREAMINFO': // 0x00
|
||||
if (!$this->FLACparseSTREAMINFO($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'])) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PADDING': // 0x01
|
||||
// ignore
|
||||
break;
|
||||
|
||||
case 'APPLICATION': // 0x02
|
||||
if (!$this->FLACparseAPPLICATION($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'])) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'SEEKTABLE': // 0x03
|
||||
if (!$this->FLACparseSEEKTABLE($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'])) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'VORBIS_COMMENT': // 0x04
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->info['avdataoffset'] = $this->ftell() - $METAdataBlockLength;
|
||||
$getid3_temp->info['audio']['dataformat'] = 'flac';
|
||||
$getid3_temp->info['flac'] = $info['flac'];
|
||||
$getid3_ogg = new getid3_ogg($getid3_temp);
|
||||
$getid3_ogg->ParseVorbisCommentsFilepointer();
|
||||
$maybe_copy_keys = array('vendor', 'comments_raw', 'comments', 'replay_gain');
|
||||
foreach ($maybe_copy_keys as $maybe_copy_key) {
|
||||
if (!empty($getid3_temp->info['ogg'][$maybe_copy_key])) {
|
||||
$info['ogg'][$maybe_copy_key] = $getid3_temp->info['ogg'][$maybe_copy_key];
|
||||
}
|
||||
}
|
||||
if (!empty($getid3_temp->info['replay_gain'])) {
|
||||
$info['replay_gain'] = $getid3_temp->info['replay_gain'];
|
||||
}
|
||||
unset($getid3_temp, $getid3_ogg);
|
||||
break;
|
||||
|
||||
case 'CUESHEET': // 0x05
|
||||
if (!getid3_flac::FLACparseCUESHEET($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'])) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PICTURE': // 0x06
|
||||
if (!getid3_flac::FLACparsePICTURE($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'])) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unhandled METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$METAdataBlockType.') at offset '.$METAdataBlockOffset;
|
||||
break;
|
||||
}
|
||||
|
||||
} while ($METAdataLastBlockFlag === false);
|
||||
|
||||
if (isset($info['flac']['PICTURE'])) {
|
||||
foreach ($info['flac']['PICTURE'] as $key => $valuearray) {
|
||||
if (!empty($valuearray['image_mime']) && !empty($valuearray['data'])) {
|
||||
$info['ogg']['comments']['picture'][] = array('image_mime'=>$valuearray['image_mime'], 'data'=>$valuearray['data']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($info['flac']['STREAMINFO'])) {
|
||||
$info['flac']['compressed_audio_bytes'] = $info['avdataend'] - $info['avdataoffset'];
|
||||
$info['flac']['uncompressed_audio_bytes'] = $info['flac']['STREAMINFO']['samples_stream'] * $info['flac']['STREAMINFO']['channels'] * ($info['flac']['STREAMINFO']['bits_per_sample'] / 8);
|
||||
if ($info['flac']['uncompressed_audio_bytes'] == 0) {
|
||||
$info['error'][] = 'Corrupt FLAC file: uncompressed_audio_bytes == zero';
|
||||
return false;
|
||||
}
|
||||
$info['flac']['compression_ratio'] = $info['flac']['compressed_audio_bytes'] / $info['flac']['uncompressed_audio_bytes'];
|
||||
}
|
||||
|
||||
// set md5_data_source - built into flac 0.5+
|
||||
if (isset($info['flac']['STREAMINFO']['audio_signature'])) {
|
||||
|
||||
if ($info['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) {
|
||||
|
||||
$info['warning'][] = 'FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)';
|
||||
|
||||
} else {
|
||||
|
||||
$info['md5_data_source'] = '';
|
||||
$md5 = $info['flac']['STREAMINFO']['audio_signature'];
|
||||
for ($i = 0; $i < strlen($md5); $i++) {
|
||||
$info['md5_data_source'] .= str_pad(dechex(ord($md5{$i})), 2, '00', STR_PAD_LEFT);
|
||||
}
|
||||
if (!preg_match('/^[0-9a-f]{32}$/', $info['md5_data_source'])) {
|
||||
unset($info['md5_data_source']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample'];
|
||||
if ($info['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
|
||||
$info['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($info['ogg']['vendor'])) {
|
||||
$info['audio']['encoder'] = $info['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');
|
||||
}
|
||||
|
||||
function FLACparseSTREAMINFO($METAdataBlockData) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$offset = 0;
|
||||
$info['flac']['STREAMINFO']['min_block_size'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 2));
|
||||
$offset += 2;
|
||||
$info['flac']['STREAMINFO']['max_block_size'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 2));
|
||||
$offset += 2;
|
||||
$info['flac']['STREAMINFO']['min_frame_size'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 3));
|
||||
$offset += 3;
|
||||
$info['flac']['STREAMINFO']['max_frame_size'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 3));
|
||||
$offset += 3;
|
||||
|
||||
$SampleRateChannelsSampleBitsStreamSamples = getid3_lib::BigEndian2Bin(substr($METAdataBlockData, $offset, 8));
|
||||
$info['flac']['STREAMINFO']['sample_rate'] = getid3_lib::Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 0, 20));
|
||||
$info['flac']['STREAMINFO']['channels'] = getid3_lib::Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 20, 3)) + 1;
|
||||
$info['flac']['STREAMINFO']['bits_per_sample'] = getid3_lib::Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 23, 5)) + 1;
|
||||
$info['flac']['STREAMINFO']['samples_stream'] = getid3_lib::Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 28, 36));
|
||||
$offset += 8;
|
||||
|
||||
$info['flac']['STREAMINFO']['audio_signature'] = substr($METAdataBlockData, $offset, 16);
|
||||
$offset += 16;
|
||||
|
||||
if (!empty($info['flac']['STREAMINFO']['sample_rate'])) {
|
||||
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
$info['audio']['sample_rate'] = $info['flac']['STREAMINFO']['sample_rate'];
|
||||
$info['audio']['channels'] = $info['flac']['STREAMINFO']['channels'];
|
||||
$info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample'];
|
||||
$info['playtime_seconds'] = $info['flac']['STREAMINFO']['samples_stream'] / $info['flac']['STREAMINFO']['sample_rate'];
|
||||
if ($info['playtime_seconds'] > 0) {
|
||||
$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
}
|
||||
|
||||
} else {
|
||||
$info['error'][] = 'Corrupt METAdata block: STREAMINFO';
|
||||
return false;
|
||||
}
|
||||
unset($info['flac']['STREAMINFO']['raw']);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function FLACparseAPPLICATION($METAdataBlockData) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$offset = 0;
|
||||
$ApplicationID = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 4));
|
||||
$offset += 4;
|
||||
$info['flac']['APPLICATION'][$ApplicationID]['name'] = getid3_flac::FLACapplicationIDLookup($ApplicationID);
|
||||
$info['flac']['APPLICATION'][$ApplicationID]['data'] = substr($METAdataBlockData, $offset);
|
||||
$offset = $METAdataBlockLength;
|
||||
|
||||
unset($info['flac']['APPLICATION']['raw']);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function FLACparseSEEKTABLE($METAdataBlockData) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$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($info['flac']['SEEKTABLE']['placeholders'], 1);
|
||||
$offset += 10;
|
||||
|
||||
} else {
|
||||
|
||||
$SampleNumber = getid3_lib::BigEndian2Int($SampleNumberString);
|
||||
$info['flac']['SEEKTABLE'][$SampleNumber]['offset'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 8));
|
||||
$offset += 8;
|
||||
$info['flac']['SEEKTABLE'][$SampleNumber]['samples'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 2));
|
||||
$offset += 2;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
unset($info['flac']['SEEKTABLE']['raw']);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function FLACparseCUESHEET($METAdataBlockData) {
|
||||
$info = &$this->getid3->info;
|
||||
$offset = 0;
|
||||
$info['flac']['CUESHEET']['media_catalog_number'] = trim(substr($METAdataBlockData, $offset, 128), "\0");
|
||||
$offset += 128;
|
||||
$info['flac']['CUESHEET']['lead_in_samples'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 8));
|
||||
$offset += 8;
|
||||
$info['flac']['CUESHEET']['flags']['is_cd'] = (bool) (getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1)) & 0x80);
|
||||
$offset += 1;
|
||||
|
||||
$offset += 258; // reserved
|
||||
|
||||
$info['flac']['CUESHEET']['number_tracks'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1));
|
||||
$offset += 1;
|
||||
|
||||
for ($track = 0; $track < $info['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;
|
||||
|
||||
$info['flac']['CUESHEET']['tracks'][$TrackNumber]['sample_offset'] = $TrackSampleOffset;
|
||||
|
||||
$info['flac']['CUESHEET']['tracks'][$TrackNumber]['isrc'] = substr($METAdataBlockData, $offset, 12);
|
||||
$offset += 12;
|
||||
|
||||
$TrackFlagsRaw = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1));
|
||||
$offset += 1;
|
||||
$info['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['is_audio'] = (bool) ($TrackFlagsRaw & 0x80);
|
||||
$info['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['pre_emphasis'] = (bool) ($TrackFlagsRaw & 0x40);
|
||||
|
||||
$offset += 13; // reserved
|
||||
|
||||
$info['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1));
|
||||
$offset += 1;
|
||||
|
||||
for ($index = 0; $index < $info['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
|
||||
|
||||
$info['flac']['CUESHEET']['tracks'][$TrackNumber]['indexes'][$IndexNumber] = $IndexSampleOffset;
|
||||
}
|
||||
}
|
||||
|
||||
unset($info['flac']['CUESHEET']['raw']);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function FLACparsePICTURE($meta_data_block_data) {
|
||||
$info = &$this->getid3->info;
|
||||
$picture = &$info['flac']['PICTURE'][sizeof($info['flac']['PICTURE']) - 1];
|
||||
$picture['offset'] = $info['flac']['PICTURE']['raw']['offset'];
|
||||
unset($info['flac']['PICTURE']['raw']);
|
||||
|
||||
$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['image_mime'] = 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['data'] = substr($meta_data_block_data, $offset, $length);
|
||||
$offset += $length;
|
||||
$picture['data_length'] = strlen($picture['data']);
|
||||
|
||||
|
||||
do {
|
||||
if ($this->inline_attachments === false) {
|
||||
// skip entirely
|
||||
unset($picture['data']);
|
||||
break;
|
||||
}
|
||||
if ($this->inline_attachments === true) {
|
||||
// great
|
||||
} elseif (is_int($this->inline_attachments)) {
|
||||
if ($this->inline_attachments < $picture['data_length']) {
|
||||
// too big, skip
|
||||
$info['warning'][] = 'attachment at '.$picture['offset'].' is too large to process inline ('.number_format($picture['data_length']).' bytes)';
|
||||
unset($picture['data']);
|
||||
break;
|
||||
}
|
||||
} elseif (is_string($this->inline_attachments)) {
|
||||
$this->inline_attachments = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->inline_attachments), DIRECTORY_SEPARATOR);
|
||||
if (!is_dir($this->inline_attachments) || !is_writable($this->inline_attachments)) {
|
||||
// cannot write, skip
|
||||
$info['warning'][] = 'attachment at '.$picture['offset'].' cannot be saved to "'.$this->inline_attachments.'" (not writable)';
|
||||
unset($picture['data']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if we get this far, must be OK
|
||||
if (is_string($this->inline_attachments)) {
|
||||
$destination_filename = $this->inline_attachments.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$picture['offset'];
|
||||
if (!file_exists($destination_filename) || is_writable($destination_filename)) {
|
||||
file_put_contents($destination_filename, $picture['data']);
|
||||
} else {
|
||||
$info['warning'][] = 'attachment at '.$picture['offset'].' cannot be saved to "'.$destination_filename.'" (not writable)';
|
||||
}
|
||||
$picture['data_filename'] = $destination_filename;
|
||||
unset($picture['data']);
|
||||
} else {
|
||||
if (!isset($info['flac']['comments']['picture'])) {
|
||||
$info['flac']['comments']['picture'] = array();
|
||||
}
|
||||
$info['flac']['comments']['picture'][] = array('data'=>$picture['data'], 'image_mime'=>$picture['image_mime']);
|
||||
}
|
||||
} while (false);
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -1,229 +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 extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$offset = 0;
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$rawdata = fread($this->getid3->fp, $this->getid3->fread_buffer_size());
|
||||
|
||||
switch (substr($rawdata, $offset, 4)) {
|
||||
case 'LA02':
|
||||
case 'LA03':
|
||||
case 'LA04':
|
||||
$info['fileformat'] = 'la';
|
||||
$info['audio']['dataformat'] = 'la';
|
||||
$info['audio']['lossless'] = true;
|
||||
|
||||
$info['la']['version_major'] = (int) substr($rawdata, $offset + 2, 1);
|
||||
$info['la']['version_minor'] = (int) substr($rawdata, $offset + 3, 1);
|
||||
$info['la']['version'] = (float) $info['la']['version_major'] + ($info['la']['version_minor'] / 10);
|
||||
$offset += 4;
|
||||
|
||||
$info['la']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
|
||||
$offset += 4;
|
||||
if ($info['la']['uncompressed_size'] == 0) {
|
||||
$info['error'][] = 'Corrupt LA file: uncompressed_size == zero';
|
||||
return false;
|
||||
}
|
||||
|
||||
$WAVEchunk = substr($rawdata, $offset, 4);
|
||||
if ($WAVEchunk !== 'WAVE') {
|
||||
$info['error'][] = 'Expected "WAVE" ('.getid3_lib::PrintHexBytes('WAVE').') at offset '.$offset.', found "'.$WAVEchunk.'" ('.getid3_lib::PrintHexBytes($WAVEchunk).') instead.';
|
||||
return false;
|
||||
}
|
||||
$offset += 4;
|
||||
|
||||
$info['la']['fmt_size'] = 24;
|
||||
if ($info['la']['version'] >= 0.3) {
|
||||
|
||||
$info['la']['fmt_size'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
|
||||
$info['la']['header_size'] = 49 + $info['la']['fmt_size'] - 24;
|
||||
$offset += 4;
|
||||
|
||||
} else {
|
||||
|
||||
// version 0.2 didn't support additional data blocks
|
||||
$info['la']['header_size'] = 41;
|
||||
|
||||
}
|
||||
|
||||
$fmt_chunk = substr($rawdata, $offset, 4);
|
||||
if ($fmt_chunk !== 'fmt ') {
|
||||
$info['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;
|
||||
|
||||
$info['la']['raw']['format'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2));
|
||||
$offset += 2;
|
||||
|
||||
$info['la']['channels'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2));
|
||||
$offset += 2;
|
||||
if ($info['la']['channels'] == 0) {
|
||||
$info['error'][] = 'Corrupt LA file: channels == zero';
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['la']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
|
||||
$offset += 4;
|
||||
if ($info['la']['sample_rate'] == 0) {
|
||||
$info['error'][] = 'Corrupt LA file: sample_rate == zero';
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['la']['bytes_per_second'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
|
||||
$offset += 4;
|
||||
$info['la']['bytes_per_sample'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2));
|
||||
$offset += 2;
|
||||
$info['la']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2));
|
||||
$offset += 2;
|
||||
|
||||
$info['la']['samples'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$info['la']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 1));
|
||||
$offset += 1;
|
||||
$info['la']['flags']['seekable'] = (bool) ($info['la']['raw']['flags'] & 0x01);
|
||||
if ($info['la']['version'] >= 0.4) {
|
||||
$info['la']['flags']['high_compression'] = (bool) ($info['la']['raw']['flags'] & 0x02);
|
||||
}
|
||||
|
||||
$info['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 ($info['la']['version'] >= 0.4) {
|
||||
$info['la']['blocksize'] = 61440;
|
||||
$info['la']['seekevery'] = 19;
|
||||
} else {
|
||||
$info['la']['blocksize'] = 73728;
|
||||
$info['la']['seekevery'] = 16;
|
||||
}
|
||||
|
||||
$info['la']['seekpoint_count'] = 0;
|
||||
if ($info['la']['flags']['seekable']) {
|
||||
$info['la']['seekpoint_count'] = floor($info['la']['samples'] / ($info['la']['blocksize'] * $info['la']['seekevery']));
|
||||
|
||||
for ($i = 0; $i < $info['la']['seekpoint_count']; $i++) {
|
||||
$info['la']['seekpoints'][] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
|
||||
$offset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if ($info['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.
|
||||
$info['la']['footerstart'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
if ($info['la']['footerstart'] > $info['filesize']) {
|
||||
$info['warning'][] = 'FooterStart value points to offset '.$info['la']['footerstart'].' which is beyond end-of-file ('.$info['filesize'].')';
|
||||
$info['la']['footerstart'] = $info['filesize'];
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// La v0.2 didn't have FooterStart value
|
||||
$info['la']['footerstart'] = $info['avdataend'];
|
||||
|
||||
}
|
||||
|
||||
if ($info['la']['footerstart'] < $info['avdataend']) {
|
||||
if ($RIFFtempfilename = tempnam(GETID3_TEMP_DIR, 'id3')) {
|
||||
if ($RIFF_fp = fopen($RIFFtempfilename, 'w+b')) {
|
||||
$RIFFdata = 'WAVE';
|
||||
if ($info['la']['version'] == 0.2) {
|
||||
$RIFFdata .= substr($rawdata, 12, 24);
|
||||
} else {
|
||||
$RIFFdata .= substr($rawdata, 16, 24);
|
||||
}
|
||||
if ($info['la']['footerstart'] < $info['avdataend']) {
|
||||
fseek($this->getid3->fp, $info['la']['footerstart'], SEEK_SET);
|
||||
$RIFFdata .= fread($this->getid3->fp, $info['avdataend'] - $info['la']['footerstart']);
|
||||
}
|
||||
$RIFFdata = 'RIFF'.getid3_lib::LittleEndian2String(strlen($RIFFdata), 4, false).$RIFFdata;
|
||||
fwrite($RIFF_fp, $RIFFdata, strlen($RIFFdata));
|
||||
fclose($RIFF_fp);
|
||||
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($RIFFtempfilename);
|
||||
$getid3_riff = new getid3_riff($getid3_temp);
|
||||
$getid3_riff->Analyze();
|
||||
|
||||
if (empty($getid3_temp->info['error'])) {
|
||||
$info['riff'] = $getid3_temp->info['riff'];
|
||||
} else {
|
||||
$info['warning'][] = 'Error parsing RIFF portion of La file: '.implode($getid3_temp->info['error']);
|
||||
}
|
||||
unset($getid3_temp, $getid3_riff);
|
||||
}
|
||||
unlink($RIFFtempfilename);
|
||||
}
|
||||
}
|
||||
|
||||
// $info['avdataoffset'] should be zero to begin with, but just in case it's not, include the addition anyway
|
||||
$info['avdataend'] = $info['avdataoffset'] + $info['la']['footerstart'];
|
||||
$info['avdataoffset'] = $info['avdataoffset'] + $offset;
|
||||
|
||||
//$info['la']['codec'] = RIFFwFormatTagLookup($info['la']['raw']['format']);
|
||||
$info['la']['compression_ratio'] = (float) (($info['avdataend'] - $info['avdataoffset']) / $info['la']['uncompressed_size']);
|
||||
$info['playtime_seconds'] = (float) ($info['la']['samples'] / $info['la']['sample_rate']) / $info['la']['channels'];
|
||||
if ($info['playtime_seconds'] == 0) {
|
||||
$info['error'][] = 'Corrupt LA file: playtime_seconds == zero';
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['audio']['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds'];
|
||||
//$info['audio']['codec'] = $info['la']['codec'];
|
||||
$info['audio']['bits_per_sample'] = $info['la']['bits_per_sample'];
|
||||
break;
|
||||
|
||||
default:
|
||||
if (substr($rawdata, $offset, 2) == 'LA') {
|
||||
$info['error'][] = 'This version of getID3() ['.$this->getid3->version().'] does not 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 {
|
||||
$info['error'][] = 'Not a LA (Lossless-Audio) file';
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
$info['audio']['channels'] = $info['la']['channels'];
|
||||
$info['audio']['sample_rate'] = (int) $info['la']['sample_rate'];
|
||||
$info['audio']['encoder'] = 'LA v'.$info['la']['version'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,130 +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 extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$LPACheader = fread($this->getid3->fp, 14);
|
||||
if (substr($LPACheader, 0, 4) != 'LPAC') {
|
||||
$info['error'][] = 'Expected "LPAC" at offset '.$info['avdataoffset'].', found "'.$StreamMarker.'"';
|
||||
return false;
|
||||
}
|
||||
$info['avdataoffset'] += 14;
|
||||
|
||||
$info['fileformat'] = 'lpac';
|
||||
$info['audio']['dataformat'] = 'lpac';
|
||||
$info['audio']['lossless'] = true;
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
|
||||
$info['lpac']['file_version'] = getid3_lib::BigEndian2Int(substr($LPACheader, 4, 1));
|
||||
$flags['audio_type'] = getid3_lib::BigEndian2Int(substr($LPACheader, 5, 1));
|
||||
$info['lpac']['total_samples']= getid3_lib::BigEndian2Int(substr($LPACheader, 6, 4));
|
||||
$flags['parameters'] = getid3_lib::BigEndian2Int(substr($LPACheader, 10, 4));
|
||||
|
||||
$info['lpac']['flags']['is_wave'] = (bool) ($flags['audio_type'] & 0x40);
|
||||
$info['lpac']['flags']['stereo'] = (bool) ($flags['audio_type'] & 0x04);
|
||||
$info['lpac']['flags']['24_bit'] = (bool) ($flags['audio_type'] & 0x02);
|
||||
$info['lpac']['flags']['16_bit'] = (bool) ($flags['audio_type'] & 0x01);
|
||||
|
||||
if ($info['lpac']['flags']['24_bit'] && $info['lpac']['flags']['16_bit']) {
|
||||
$info['warning'][] = '24-bit and 16-bit flags cannot both be set';
|
||||
}
|
||||
|
||||
$info['lpac']['flags']['fast_compress'] = (bool) ($flags['parameters'] & 0x40000000);
|
||||
$info['lpac']['flags']['random_access'] = (bool) ($flags['parameters'] & 0x08000000);
|
||||
$info['lpac']['block_length'] = pow(2, (($flags['parameters'] & 0x07000000) >> 24)) * 256;
|
||||
$info['lpac']['flags']['adaptive_prediction_order'] = (bool) ($flags['parameters'] & 0x00800000);
|
||||
$info['lpac']['flags']['adaptive_quantization'] = (bool) ($flags['parameters'] & 0x00400000);
|
||||
$info['lpac']['flags']['joint_stereo'] = (bool) ($flags['parameters'] & 0x00040000);
|
||||
$info['lpac']['quantization'] = ($flags['parameters'] & 0x00001F00) >> 8;
|
||||
$info['lpac']['max_prediction_order'] = ($flags['parameters'] & 0x0000003F);
|
||||
|
||||
if ($info['lpac']['flags']['fast_compress'] && ($info['lpac']['max_prediction_order'] != 3)) {
|
||||
$info['warning'][] = 'max_prediction_order expected to be "3" if fast_compress is true, actual value is "'.$info['lpac']['max_prediction_order'].'"';
|
||||
}
|
||||
switch ($info['lpac']['file_version']) {
|
||||
case 6:
|
||||
if ($info['lpac']['flags']['adaptive_quantization']) {
|
||||
$info['warning'][] = 'adaptive_quantization expected to be false in LPAC file stucture v6, actually true';
|
||||
}
|
||||
if ($info['lpac']['quantization'] != 20) {
|
||||
$info['warning'][] = 'Quantization expected to be 20 in LPAC file stucture v6, actually '.$info['lpac']['flags']['Q'];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
//$info['warning'][] = 'This version of getID3() ['.$this->getid3->version().'] only supports LPAC file format version 6, this file is version '.$info['lpac']['file_version'].' - please report to info@getid3.org';
|
||||
break;
|
||||
}
|
||||
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->info = $info;
|
||||
$getid3_riff = new getid3_riff($getid3_temp);
|
||||
$getid3_riff->Analyze();
|
||||
$info['avdataoffset'] = $getid3_temp->info['avdataoffset'];
|
||||
$info['riff'] = $getid3_temp->info['riff'];
|
||||
$info['error'] = $getid3_temp->info['error'];
|
||||
$info['warning'] = $getid3_temp->info['warning'];
|
||||
$info['lpac']['comments']['comment'] = $getid3_temp->info['comments'];
|
||||
$info['audio']['sample_rate'] = $getid3_temp->info['audio']['sample_rate'];
|
||||
unset($getid3_temp, $getid3_riff);
|
||||
|
||||
$info['audio']['channels'] = ($info['lpac']['flags']['stereo'] ? 2 : 1);
|
||||
|
||||
if ($info['lpac']['flags']['24_bit']) {
|
||||
$info['audio']['bits_per_sample'] = $info['riff']['audio'][0]['bits_per_sample'];
|
||||
} elseif ($info['lpac']['flags']['16_bit']) {
|
||||
$info['audio']['bits_per_sample'] = 16;
|
||||
} else {
|
||||
$info['audio']['bits_per_sample'] = 8;
|
||||
}
|
||||
|
||||
if ($info['lpac']['flags']['fast_compress']) {
|
||||
// fast
|
||||
$info['audio']['encoder_options'] = '-1';
|
||||
} else {
|
||||
switch ($info['lpac']['max_prediction_order']) {
|
||||
case 20: // simple
|
||||
$info['audio']['encoder_options'] = '-2';
|
||||
break;
|
||||
case 30: // medium
|
||||
$info['audio']['encoder_options'] = '-3';
|
||||
break;
|
||||
case 40: // high
|
||||
$info['audio']['encoder_options'] = '-4';
|
||||
break;
|
||||
case 60: // extrahigh
|
||||
$info['audio']['encoder_options'] = '-5';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$info['playtime_seconds'] = $info['lpac']['total_samples'] / $info['audio']['sample_rate'];
|
||||
$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,526 +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.midi.php //
|
||||
// module for Midi Audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
define('GETID3_MIDI_MAGIC_MTHD', 'MThd'); // MIDI file header magic
|
||||
define('GETID3_MIDI_MAGIC_MTRK', 'MTrk'); // MIDI track header magic
|
||||
|
||||
class getid3_midi extends getid3_handler
|
||||
{
|
||||
var $scanwholefile = true;
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// shortcut
|
||||
$info['midi']['raw'] = array();
|
||||
$thisfile_midi = &$info['midi'];
|
||||
$thisfile_midi_raw = &$thisfile_midi['raw'];
|
||||
|
||||
$info['fileformat'] = 'midi';
|
||||
$info['audio']['dataformat'] = 'midi';
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$MIDIdata = fread($this->getid3->fp, $this->getid3->fread_buffer_size());
|
||||
$offset = 0;
|
||||
$MIDIheaderID = substr($MIDIdata, $offset, 4); // 'MThd'
|
||||
if ($MIDIheaderID != GETID3_MIDI_MAGIC_MTHD) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(GETID3_MIDI_MAGIC_MTHD).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($MIDIheaderID).'"';
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
$offset += 4;
|
||||
$thisfile_midi_raw['headersize'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_midi_raw['fileformat'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_midi_raw['tracks'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_midi_raw['ticksperqnote'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2));
|
||||
$offset += 2;
|
||||
|
||||
for ($i = 0; $i < $thisfile_midi_raw['tracks']; $i++) {
|
||||
while ((strlen($MIDIdata) - $offset) < 8) {
|
||||
$MIDIdata .= fread($this->getid3->fp, $this->getid3->fread_buffer_size());
|
||||
}
|
||||
$trackID = substr($MIDIdata, $offset, 4);
|
||||
$offset += 4;
|
||||
if ($trackID == GETID3_MIDI_MAGIC_MTRK) {
|
||||
$tracksize = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 4));
|
||||
$offset += 4;
|
||||
// $thisfile_midi['tracks'][$i]['size'] = $tracksize;
|
||||
$trackdataarray[$i] = substr($MIDIdata, $offset, $tracksize);
|
||||
$offset += $tracksize;
|
||||
} else {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(GETID3_MIDI_MAGIC_MTRK).'" at '.($offset - 4).', found "'.getid3_lib::PrintHexBytes($trackID).'" instead';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($trackdataarray) || !is_array($trackdataarray)) {
|
||||
$info['error'][] = 'Cannot find MIDI track information';
|
||||
unset($thisfile_midi);
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->scanwholefile) { // this can take quite a long time, so have the option to bypass it if speed is very important
|
||||
$thisfile_midi['totalticks'] = 0;
|
||||
$info['playtime_seconds'] = 0;
|
||||
$CurrentMicroSecondsPerBeat = 500000; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat
|
||||
$CurrentBeatsPerMinute = 120; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat
|
||||
$MicroSecondsPerQuarterNoteAfter = array ();
|
||||
|
||||
foreach ($trackdataarray as $tracknumber => $trackdata) {
|
||||
|
||||
$eventsoffset = 0;
|
||||
$LastIssuedMIDIcommand = 0;
|
||||
$LastIssuedMIDIchannel = 0;
|
||||
$CumulativeDeltaTime = 0;
|
||||
$TicksAtCurrentBPM = 0;
|
||||
while ($eventsoffset < strlen($trackdata)) {
|
||||
$eventid = 0;
|
||||
if (isset($MIDIevents[$tracknumber]) && is_array($MIDIevents[$tracknumber])) {
|
||||
$eventid = count($MIDIevents[$tracknumber]);
|
||||
}
|
||||
$deltatime = 0;
|
||||
for ($i = 0; $i < 4; $i++) {
|
||||
$deltatimebyte = ord(substr($trackdata, $eventsoffset++, 1));
|
||||
$deltatime = ($deltatime << 7) + ($deltatimebyte & 0x7F);
|
||||
if ($deltatimebyte & 0x80) {
|
||||
// another byte follows
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$CumulativeDeltaTime += $deltatime;
|
||||
$TicksAtCurrentBPM += $deltatime;
|
||||
$MIDIevents[$tracknumber][$eventid]['deltatime'] = $deltatime;
|
||||
$MIDI_event_channel = ord(substr($trackdata, $eventsoffset++, 1));
|
||||
if ($MIDI_event_channel & 0x80) {
|
||||
// OK, normal event - MIDI command has MSB set
|
||||
$LastIssuedMIDIcommand = $MIDI_event_channel >> 4;
|
||||
$LastIssuedMIDIchannel = $MIDI_event_channel & 0x0F;
|
||||
} else {
|
||||
// running event - assume last command
|
||||
$eventsoffset--;
|
||||
}
|
||||
$MIDIevents[$tracknumber][$eventid]['eventid'] = $LastIssuedMIDIcommand;
|
||||
$MIDIevents[$tracknumber][$eventid]['channel'] = $LastIssuedMIDIchannel;
|
||||
if ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x08) { // Note off (key is released)
|
||||
|
||||
$notenumber = ord(substr($trackdata, $eventsoffset++, 1));
|
||||
$velocity = ord(substr($trackdata, $eventsoffset++, 1));
|
||||
|
||||
} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x09) { // Note on (key is pressed)
|
||||
|
||||
$notenumber = ord(substr($trackdata, $eventsoffset++, 1));
|
||||
$velocity = ord(substr($trackdata, $eventsoffset++, 1));
|
||||
|
||||
} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0A) { // Key after-touch
|
||||
|
||||
$notenumber = ord(substr($trackdata, $eventsoffset++, 1));
|
||||
$velocity = ord(substr($trackdata, $eventsoffset++, 1));
|
||||
|
||||
} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0B) { // Control Change
|
||||
|
||||
$controllernum = ord(substr($trackdata, $eventsoffset++, 1));
|
||||
$newvalue = ord(substr($trackdata, $eventsoffset++, 1));
|
||||
|
||||
} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0C) { // Program (patch) change
|
||||
|
||||
$newprogramnum = ord(substr($trackdata, $eventsoffset++, 1));
|
||||
|
||||
$thisfile_midi_raw['track'][$tracknumber]['instrumentid'] = $newprogramnum;
|
||||
if ($tracknumber == 10) {
|
||||
$thisfile_midi_raw['track'][$tracknumber]['instrument'] = $this->GeneralMIDIpercussionLookup($newprogramnum);
|
||||
} else {
|
||||
$thisfile_midi_raw['track'][$tracknumber]['instrument'] = $this->GeneralMIDIinstrumentLookup($newprogramnum);
|
||||
}
|
||||
|
||||
} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0D) { // Channel after-touch
|
||||
|
||||
$channelnumber = ord(substr($trackdata, $eventsoffset++, 1));
|
||||
|
||||
} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0E) { // Pitch wheel change (2000H is normal or no change)
|
||||
|
||||
$changeLSB = ord(substr($trackdata, $eventsoffset++, 1));
|
||||
$changeMSB = ord(substr($trackdata, $eventsoffset++, 1));
|
||||
$pitchwheelchange = (($changeMSB & 0x7F) << 7) & ($changeLSB & 0x7F);
|
||||
|
||||
} elseif (($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0F) && ($MIDIevents[$tracknumber][$eventid]['channel'] == 0x0F)) {
|
||||
|
||||
$METAeventCommand = ord(substr($trackdata, $eventsoffset++, 1));
|
||||
$METAeventLength = ord(substr($trackdata, $eventsoffset++, 1));
|
||||
$METAeventData = substr($trackdata, $eventsoffset, $METAeventLength);
|
||||
$eventsoffset += $METAeventLength;
|
||||
switch ($METAeventCommand) {
|
||||
case 0x00: // Set track sequence number
|
||||
$track_sequence_number = getid3_lib::BigEndian2Int(substr($METAeventData, 0, $METAeventLength));
|
||||
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['seqno'] = $track_sequence_number;
|
||||
break;
|
||||
|
||||
case 0x01: // Text: generic
|
||||
$text_generic = substr($METAeventData, 0, $METAeventLength);
|
||||
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['text'] = $text_generic;
|
||||
$thisfile_midi['comments']['comment'][] = $text_generic;
|
||||
break;
|
||||
|
||||
case 0x02: // Text: copyright
|
||||
$text_copyright = substr($METAeventData, 0, $METAeventLength);
|
||||
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['copyright'] = $text_copyright;
|
||||
$thisfile_midi['comments']['copyright'][] = $text_copyright;
|
||||
break;
|
||||
|
||||
case 0x03: // Text: track name
|
||||
$text_trackname = substr($METAeventData, 0, $METAeventLength);
|
||||
$thisfile_midi_raw['track'][$tracknumber]['name'] = $text_trackname;
|
||||
break;
|
||||
|
||||
case 0x04: // Text: track instrument name
|
||||
$text_instrument = substr($METAeventData, 0, $METAeventLength);
|
||||
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['instrument'] = $text_instrument;
|
||||
break;
|
||||
|
||||
case 0x05: // Text: lyrics
|
||||
$text_lyrics = substr($METAeventData, 0, $METAeventLength);
|
||||
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['lyrics'] = $text_lyrics;
|
||||
if (!isset($thisfile_midi['lyrics'])) {
|
||||
$thisfile_midi['lyrics'] = '';
|
||||
}
|
||||
$thisfile_midi['lyrics'] .= $text_lyrics."\n";
|
||||
break;
|
||||
|
||||
case 0x06: // Text: marker
|
||||
$text_marker = substr($METAeventData, 0, $METAeventLength);
|
||||
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['marker'] = $text_marker;
|
||||
break;
|
||||
|
||||
case 0x07: // Text: cue point
|
||||
$text_cuepoint = substr($METAeventData, 0, $METAeventLength);
|
||||
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['cuepoint'] = $text_cuepoint;
|
||||
break;
|
||||
|
||||
case 0x2F: // End Of Track
|
||||
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['EOT'] = $CumulativeDeltaTime;
|
||||
break;
|
||||
|
||||
case 0x51: // Tempo: microseconds / quarter note
|
||||
$CurrentMicroSecondsPerBeat = getid3_lib::BigEndian2Int(substr($METAeventData, 0, $METAeventLength));
|
||||
if ($CurrentMicroSecondsPerBeat == 0) {
|
||||
$info['error'][] = 'Corrupt MIDI file: CurrentMicroSecondsPerBeat == zero';
|
||||
return false;
|
||||
}
|
||||
$thisfile_midi_raw['events'][$tracknumber][$CumulativeDeltaTime]['us_qnote'] = $CurrentMicroSecondsPerBeat;
|
||||
$CurrentBeatsPerMinute = (1000000 / $CurrentMicroSecondsPerBeat) * 60;
|
||||
$MicroSecondsPerQuarterNoteAfter[$CumulativeDeltaTime] = $CurrentMicroSecondsPerBeat;
|
||||
$TicksAtCurrentBPM = 0;
|
||||
break;
|
||||
|
||||
case 0x58: // Time signature
|
||||
$timesig_numerator = getid3_lib::BigEndian2Int($METAeventData{0});
|
||||
$timesig_denominator = pow(2, getid3_lib::BigEndian2Int($METAeventData{1})); // $02 -> x/4, $03 -> x/8, etc
|
||||
$timesig_32inqnote = getid3_lib::BigEndian2Int($METAeventData{2}); // number of 32nd notes to the quarter note
|
||||
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_32inqnote'] = $timesig_32inqnote;
|
||||
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_numerator'] = $timesig_numerator;
|
||||
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_denominator'] = $timesig_denominator;
|
||||
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_text'] = $timesig_numerator.'/'.$timesig_denominator;
|
||||
$thisfile_midi['timesignature'][] = $timesig_numerator.'/'.$timesig_denominator;
|
||||
break;
|
||||
|
||||
case 0x59: // Keysignature
|
||||
$keysig_sharpsflats = getid3_lib::BigEndian2Int($METAeventData{0});
|
||||
if ($keysig_sharpsflats & 0x80) {
|
||||
// (-7 -> 7 flats, 0 ->key of C, 7 -> 7 sharps)
|
||||
$keysig_sharpsflats -= 256;
|
||||
}
|
||||
|
||||
$keysig_majorminor = getid3_lib::BigEndian2Int($METAeventData{1}); // 0 -> major, 1 -> minor
|
||||
$keysigs = array(-7=>'Cb', -6=>'Gb', -5=>'Db', -4=>'Ab', -3=>'Eb', -2=>'Bb', -1=>'F', 0=>'C', 1=>'G', 2=>'D', 3=>'A', 4=>'E', 5=>'B', 6=>'F#', 7=>'C#');
|
||||
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_sharps'] = (($keysig_sharpsflats > 0) ? abs($keysig_sharpsflats) : 0);
|
||||
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_flats'] = (($keysig_sharpsflats < 0) ? abs($keysig_sharpsflats) : 0);
|
||||
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_minor'] = (bool) $keysig_majorminor;
|
||||
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_text'] = $keysigs[$keysig_sharpsflats].' '.($thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_minor'] ? 'minor' : 'major');
|
||||
|
||||
// $keysigs[$keysig_sharpsflats] gets an int key (correct) - $keysigs["$keysig_sharpsflats"] gets a string key (incorrect)
|
||||
$thisfile_midi['keysignature'][] = $keysigs[$keysig_sharpsflats].' '.((bool) $keysig_majorminor ? 'minor' : 'major');
|
||||
break;
|
||||
|
||||
case 0x7F: // Sequencer specific information
|
||||
$custom_data = substr($METAeventData, 0, $METAeventLength);
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unhandled META Event Command: '.$METAeventCommand;
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$info['warning'][] = 'Unhandled MIDI Event ID: '.$MIDIevents[$tracknumber][$eventid]['eventid'].' + Channel ID: '.$MIDIevents[$tracknumber][$eventid]['channel'];
|
||||
|
||||
}
|
||||
}
|
||||
if (($tracknumber > 0) || (count($trackdataarray) == 1)) {
|
||||
$thisfile_midi['totalticks'] = max($thisfile_midi['totalticks'], $CumulativeDeltaTime);
|
||||
}
|
||||
}
|
||||
$previoustickoffset = null;
|
||||
|
||||
ksort($MicroSecondsPerQuarterNoteAfter);
|
||||
foreach ($MicroSecondsPerQuarterNoteAfter as $tickoffset => $microsecondsperbeat) {
|
||||
if (is_null($previoustickoffset)) {
|
||||
$prevmicrosecondsperbeat = $microsecondsperbeat;
|
||||
$previoustickoffset = $tickoffset;
|
||||
continue;
|
||||
}
|
||||
if ($thisfile_midi['totalticks'] > $tickoffset) {
|
||||
|
||||
if ($thisfile_midi_raw['ticksperqnote'] == 0) {
|
||||
$info['error'][] = 'Corrupt MIDI file: ticksperqnote == zero';
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['playtime_seconds'] += (($tickoffset - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote']) * ($prevmicrosecondsperbeat / 1000000);
|
||||
|
||||
$prevmicrosecondsperbeat = $microsecondsperbeat;
|
||||
$previoustickoffset = $tickoffset;
|
||||
}
|
||||
}
|
||||
if ($thisfile_midi['totalticks'] > $previoustickoffset) {
|
||||
|
||||
if ($thisfile_midi_raw['ticksperqnote'] == 0) {
|
||||
$info['error'][] = 'Corrupt MIDI file: ticksperqnote == zero';
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['playtime_seconds'] += (($thisfile_midi['totalticks'] - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote']) * ($microsecondsperbeat / 1000000);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!empty($info['playtime_seconds'])) {
|
||||
$info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
}
|
||||
|
||||
if (!empty($thisfile_midi['lyrics'])) {
|
||||
$thisfile_midi['comments']['lyrics'][] = $thisfile_midi['lyrics'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function GeneralMIDIinstrumentLookup($instrumentid) {
|
||||
|
||||
$begin = __LINE__;
|
||||
|
||||
/** This is not a comment!
|
||||
|
||||
0 Acoustic Grand
|
||||
1 Bright Acoustic
|
||||
2 Electric Grand
|
||||
3 Honky-Tonk
|
||||
4 Electric Piano 1
|
||||
5 Electric Piano 2
|
||||
6 Harpsichord
|
||||
7 Clavier
|
||||
8 Celesta
|
||||
9 Glockenspiel
|
||||
10 Music Box
|
||||
11 Vibraphone
|
||||
12 Marimba
|
||||
13 Xylophone
|
||||
14 Tubular Bells
|
||||
15 Dulcimer
|
||||
16 Drawbar Organ
|
||||
17 Percussive Organ
|
||||
18 Rock Organ
|
||||
19 Church Organ
|
||||
20 Reed Organ
|
||||
21 Accordian
|
||||
22 Harmonica
|
||||
23 Tango Accordian
|
||||
24 Acoustic Guitar (nylon)
|
||||
25 Acoustic Guitar (steel)
|
||||
26 Electric Guitar (jazz)
|
||||
27 Electric Guitar (clean)
|
||||
28 Electric Guitar (muted)
|
||||
29 Overdriven Guitar
|
||||
30 Distortion Guitar
|
||||
31 Guitar Harmonics
|
||||
32 Acoustic Bass
|
||||
33 Electric Bass (finger)
|
||||
34 Electric Bass (pick)
|
||||
35 Fretless Bass
|
||||
36 Slap Bass 1
|
||||
37 Slap Bass 2
|
||||
38 Synth Bass 1
|
||||
39 Synth Bass 2
|
||||
40 Violin
|
||||
41 Viola
|
||||
42 Cello
|
||||
43 Contrabass
|
||||
44 Tremolo Strings
|
||||
45 Pizzicato Strings
|
||||
46 Orchestral Strings
|
||||
47 Timpani
|
||||
48 String Ensemble 1
|
||||
49 String Ensemble 2
|
||||
50 SynthStrings 1
|
||||
51 SynthStrings 2
|
||||
52 Choir Aahs
|
||||
53 Voice Oohs
|
||||
54 Synth Voice
|
||||
55 Orchestra Hit
|
||||
56 Trumpet
|
||||
57 Trombone
|
||||
58 Tuba
|
||||
59 Muted Trumpet
|
||||
60 French Horn
|
||||
61 Brass Section
|
||||
62 SynthBrass 1
|
||||
63 SynthBrass 2
|
||||
64 Soprano Sax
|
||||
65 Alto Sax
|
||||
66 Tenor Sax
|
||||
67 Baritone Sax
|
||||
68 Oboe
|
||||
69 English Horn
|
||||
70 Bassoon
|
||||
71 Clarinet
|
||||
72 Piccolo
|
||||
73 Flute
|
||||
74 Recorder
|
||||
75 Pan Flute
|
||||
76 Blown Bottle
|
||||
77 Shakuhachi
|
||||
78 Whistle
|
||||
79 Ocarina
|
||||
80 Lead 1 (square)
|
||||
81 Lead 2 (sawtooth)
|
||||
82 Lead 3 (calliope)
|
||||
83 Lead 4 (chiff)
|
||||
84 Lead 5 (charang)
|
||||
85 Lead 6 (voice)
|
||||
86 Lead 7 (fifths)
|
||||
87 Lead 8 (bass + lead)
|
||||
88 Pad 1 (new age)
|
||||
89 Pad 2 (warm)
|
||||
90 Pad 3 (polysynth)
|
||||
91 Pad 4 (choir)
|
||||
92 Pad 5 (bowed)
|
||||
93 Pad 6 (metallic)
|
||||
94 Pad 7 (halo)
|
||||
95 Pad 8 (sweep)
|
||||
96 FX 1 (rain)
|
||||
97 FX 2 (soundtrack)
|
||||
98 FX 3 (crystal)
|
||||
99 FX 4 (atmosphere)
|
||||
100 FX 5 (brightness)
|
||||
101 FX 6 (goblins)
|
||||
102 FX 7 (echoes)
|
||||
103 FX 8 (sci-fi)
|
||||
104 Sitar
|
||||
105 Banjo
|
||||
106 Shamisen
|
||||
107 Koto
|
||||
108 Kalimba
|
||||
109 Bagpipe
|
||||
110 Fiddle
|
||||
111 Shanai
|
||||
112 Tinkle Bell
|
||||
113 Agogo
|
||||
114 Steel Drums
|
||||
115 Woodblock
|
||||
116 Taiko Drum
|
||||
117 Melodic Tom
|
||||
118 Synth Drum
|
||||
119 Reverse Cymbal
|
||||
120 Guitar Fret Noise
|
||||
121 Breath Noise
|
||||
122 Seashore
|
||||
123 Bird Tweet
|
||||
124 Telephone Ring
|
||||
125 Helicopter
|
||||
126 Applause
|
||||
127 Gunshot
|
||||
|
||||
*/
|
||||
|
||||
return getid3_lib::EmbeddedLookup($instrumentid, $begin, __LINE__, __FILE__, 'GeneralMIDIinstrument');
|
||||
}
|
||||
|
||||
function GeneralMIDIpercussionLookup($instrumentid) {
|
||||
|
||||
$begin = __LINE__;
|
||||
|
||||
/** This is not a comment!
|
||||
|
||||
35 Acoustic Bass Drum
|
||||
36 Bass Drum 1
|
||||
37 Side Stick
|
||||
38 Acoustic Snare
|
||||
39 Hand Clap
|
||||
40 Electric Snare
|
||||
41 Low Floor Tom
|
||||
42 Closed Hi-Hat
|
||||
43 High Floor Tom
|
||||
44 Pedal Hi-Hat
|
||||
45 Low Tom
|
||||
46 Open Hi-Hat
|
||||
47 Low-Mid Tom
|
||||
48 Hi-Mid Tom
|
||||
49 Crash Cymbal 1
|
||||
50 High Tom
|
||||
51 Ride Cymbal 1
|
||||
52 Chinese Cymbal
|
||||
53 Ride Bell
|
||||
54 Tambourine
|
||||
55 Splash Cymbal
|
||||
56 Cowbell
|
||||
57 Crash Cymbal 2
|
||||
59 Ride Cymbal 2
|
||||
60 Hi Bongo
|
||||
61 Low Bongo
|
||||
62 Mute Hi Conga
|
||||
63 Open Hi Conga
|
||||
64 Low Conga
|
||||
65 High Timbale
|
||||
66 Low Timbale
|
||||
67 High Agogo
|
||||
68 Low Agogo
|
||||
69 Cabasa
|
||||
70 Maracas
|
||||
71 Short Whistle
|
||||
72 Long Whistle
|
||||
73 Short Guiro
|
||||
74 Long Guiro
|
||||
75 Claves
|
||||
76 Hi Wood Block
|
||||
77 Low Wood Block
|
||||
78 Mute Cuica
|
||||
79 Open Cuica
|
||||
80 Mute Triangle
|
||||
81 Open Triangle
|
||||
|
||||
*/
|
||||
|
||||
return getid3_lib::EmbeddedLookup($instrumentid, $begin, __LINE__, __FILE__, 'GeneralMIDIpercussion');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -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 extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$fileheader = fread($this->getid3->fp, 1088);
|
||||
if (preg_match('#^IMPM#', $fileheader)) {
|
||||
return $this->getITheaderFilepointer();
|
||||
} elseif (preg_match('#^Extended Module#', $fileheader)) {
|
||||
return $this->getXMheaderFilepointer();
|
||||
} elseif (preg_match('#^.{44}SCRM#', $fileheader)) {
|
||||
return $this->getS3MheaderFilepointer();
|
||||
} elseif (preg_match('#^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)#', $fileheader)) {
|
||||
return $this->getMODheaderFilepointer();
|
||||
}
|
||||
$info['error'][] = 'This is not a known type of MOD file';
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function getMODheaderFilepointer() {
|
||||
$info = &$this->getid3->info;
|
||||
fseek($this->getid3->fp, $info['avdataoffset'] + 1080);
|
||||
$FormatID = fread($this->getid3->fp, 4);
|
||||
if (!preg_match('#^(M.K.|[5-9]CHN|[1-3][0-9]CH)$#', $FormatID)) {
|
||||
$info['error'][] = 'This is not a known type of MOD file';
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['fileformat'] = 'mod';
|
||||
|
||||
$info['error'][] = 'MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
|
||||
return false;
|
||||
}
|
||||
|
||||
function getXMheaderFilepointer() {
|
||||
$info = &$this->getid3->info;
|
||||
fseek($this->getid3->fp, $info['avdataoffset']);
|
||||
$FormatID = fread($this->getid3->fp, 15);
|
||||
if (!preg_match('#^Extended Module$#', $FormatID)) {
|
||||
$info['error'][] = 'This is not a known type of XM-MOD file';
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['fileformat'] = 'xm';
|
||||
|
||||
$info['error'][] = 'XM-MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
|
||||
return false;
|
||||
}
|
||||
|
||||
function getS3MheaderFilepointer() {
|
||||
$info = &$this->getid3->info;
|
||||
fseek($this->getid3->fp, $info['avdataoffset'] + 44);
|
||||
$FormatID = fread($this->getid3->fp, 4);
|
||||
if (!preg_match('#^SCRM$#', $FormatID)) {
|
||||
$info['error'][] = 'This is not a ScreamTracker MOD file';
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['fileformat'] = 's3m';
|
||||
|
||||
$info['error'][] = 'ScreamTracker parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
|
||||
return false;
|
||||
}
|
||||
|
||||
function getITheaderFilepointer() {
|
||||
$info = &$this->getid3->info;
|
||||
fseek($this->getid3->fp, $info['avdataoffset']);
|
||||
$FormatID = fread($this->getid3->fp, 4);
|
||||
if (!preg_match('#^IMPM$#', $FormatID)) {
|
||||
$info['error'][] = 'This is not an ImpulseTracker MOD file';
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['fileformat'] = 'it';
|
||||
|
||||
$info['error'][] = 'ImpulseTracker parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,205 +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.monkey.php //
|
||||
// module for analyzing Monkey's Audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_monkey extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// based loosely on code from TMonkey by Jurgen Faul <jfaulØgmx*de>
|
||||
// http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html
|
||||
|
||||
$info['fileformat'] = 'mac';
|
||||
$info['audio']['dataformat'] = 'mac';
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
$info['audio']['lossless'] = true;
|
||||
|
||||
$info['monkeys_audio']['raw'] = array();
|
||||
$thisfile_monkeysaudio = &$info['monkeys_audio'];
|
||||
$thisfile_monkeysaudio_raw = &$thisfile_monkeysaudio['raw'];
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$MACheaderData = fread($this->getid3->fp, 74);
|
||||
|
||||
$thisfile_monkeysaudio_raw['magic'] = substr($MACheaderData, 0, 4);
|
||||
$magic = 'MAC ';
|
||||
if ($thisfile_monkeysaudio_raw['magic'] != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_monkeysaudio_raw['magic']).'"';
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
$thisfile_monkeysaudio_raw['nVersion'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 4, 2)); // appears to be uint32 in 3.98+
|
||||
|
||||
if ($thisfile_monkeysaudio_raw['nVersion'] < 3980) {
|
||||
$thisfile_monkeysaudio_raw['nCompressionLevel'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 6, 2));
|
||||
$thisfile_monkeysaudio_raw['nFormatFlags'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 8, 2));
|
||||
$thisfile_monkeysaudio_raw['nChannels'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 10, 2));
|
||||
$thisfile_monkeysaudio_raw['nSampleRate'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 12, 4));
|
||||
$thisfile_monkeysaudio_raw['nHeaderDataBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 16, 4));
|
||||
$thisfile_monkeysaudio_raw['nWAVTerminatingBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 20, 4));
|
||||
$thisfile_monkeysaudio_raw['nTotalFrames'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 24, 4));
|
||||
$thisfile_monkeysaudio_raw['nFinalFrameSamples'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 28, 4));
|
||||
$thisfile_monkeysaudio_raw['nPeakLevel'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 32, 4));
|
||||
$thisfile_monkeysaudio_raw['nSeekElements'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 38, 2));
|
||||
$offset = 8;
|
||||
} else {
|
||||
$offset = 8;
|
||||
// APE_DESCRIPTOR
|
||||
$thisfile_monkeysaudio_raw['nDescriptorBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_monkeysaudio_raw['nHeaderBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_monkeysaudio_raw['nSeekTableBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_monkeysaudio_raw['nHeaderDataBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_monkeysaudio_raw['nAPEFrameDataBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_monkeysaudio_raw['nAPEFrameDataBytesHigh'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_monkeysaudio_raw['nTerminatingDataBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_monkeysaudio_raw['cFileMD5'] = substr($MACheaderData, $offset, 16);
|
||||
$offset += 16;
|
||||
|
||||
// APE_HEADER
|
||||
$thisfile_monkeysaudio_raw['nCompressionLevel'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_monkeysaudio_raw['nFormatFlags'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_monkeysaudio_raw['nBlocksPerFrame'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_monkeysaudio_raw['nFinalFrameBlocks'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_monkeysaudio_raw['nTotalFrames'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_monkeysaudio_raw['nBitsPerSample'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_monkeysaudio_raw['nChannels'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_monkeysaudio_raw['nSampleRate'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
|
||||
$offset += 4;
|
||||
}
|
||||
|
||||
$thisfile_monkeysaudio['flags']['8-bit'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0001);
|
||||
$thisfile_monkeysaudio['flags']['crc-32'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0002);
|
||||
$thisfile_monkeysaudio['flags']['peak_level'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0004);
|
||||
$thisfile_monkeysaudio['flags']['24-bit'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0008);
|
||||
$thisfile_monkeysaudio['flags']['seek_elements'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0010);
|
||||
$thisfile_monkeysaudio['flags']['no_wav_header'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0020);
|
||||
$thisfile_monkeysaudio['version'] = $thisfile_monkeysaudio_raw['nVersion'] / 1000;
|
||||
$thisfile_monkeysaudio['compression'] = $this->MonkeyCompressionLevelNameLookup($thisfile_monkeysaudio_raw['nCompressionLevel']);
|
||||
if ($thisfile_monkeysaudio_raw['nVersion'] < 3980) {
|
||||
$thisfile_monkeysaudio['samples_per_frame'] = $this->MonkeySamplesPerFrame($thisfile_monkeysaudio_raw['nVersion'], $thisfile_monkeysaudio_raw['nCompressionLevel']);
|
||||
}
|
||||
$thisfile_monkeysaudio['bits_per_sample'] = ($thisfile_monkeysaudio['flags']['24-bit'] ? 24 : ($thisfile_monkeysaudio['flags']['8-bit'] ? 8 : 16));
|
||||
$thisfile_monkeysaudio['channels'] = $thisfile_monkeysaudio_raw['nChannels'];
|
||||
$info['audio']['channels'] = $thisfile_monkeysaudio['channels'];
|
||||
$thisfile_monkeysaudio['sample_rate'] = $thisfile_monkeysaudio_raw['nSampleRate'];
|
||||
if ($thisfile_monkeysaudio['sample_rate'] == 0) {
|
||||
$info['error'][] = 'Corrupt MAC file: frequency == zero';
|
||||
return false;
|
||||
}
|
||||
$info['audio']['sample_rate'] = $thisfile_monkeysaudio['sample_rate'];
|
||||
if ($thisfile_monkeysaudio['flags']['peak_level']) {
|
||||
$thisfile_monkeysaudio['peak_level'] = $thisfile_monkeysaudio_raw['nPeakLevel'];
|
||||
$thisfile_monkeysaudio['peak_ratio'] = $thisfile_monkeysaudio['peak_level'] / pow(2, $thisfile_monkeysaudio['bits_per_sample'] - 1);
|
||||
}
|
||||
if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) {
|
||||
$thisfile_monkeysaudio['samples'] = (($thisfile_monkeysaudio_raw['nTotalFrames'] - 1) * $thisfile_monkeysaudio_raw['nBlocksPerFrame']) + $thisfile_monkeysaudio_raw['nFinalFrameBlocks'];
|
||||
} else {
|
||||
$thisfile_monkeysaudio['samples'] = (($thisfile_monkeysaudio_raw['nTotalFrames'] - 1) * $thisfile_monkeysaudio['samples_per_frame']) + $thisfile_monkeysaudio_raw['nFinalFrameSamples'];
|
||||
}
|
||||
$thisfile_monkeysaudio['playtime'] = $thisfile_monkeysaudio['samples'] / $thisfile_monkeysaudio['sample_rate'];
|
||||
if ($thisfile_monkeysaudio['playtime'] == 0) {
|
||||
$info['error'][] = 'Corrupt MAC file: playtime == zero';
|
||||
return false;
|
||||
}
|
||||
$info['playtime_seconds'] = $thisfile_monkeysaudio['playtime'];
|
||||
$thisfile_monkeysaudio['compressed_size'] = $info['avdataend'] - $info['avdataoffset'];
|
||||
$thisfile_monkeysaudio['uncompressed_size'] = $thisfile_monkeysaudio['samples'] * $thisfile_monkeysaudio['channels'] * ($thisfile_monkeysaudio['bits_per_sample'] / 8);
|
||||
if ($thisfile_monkeysaudio['uncompressed_size'] == 0) {
|
||||
$info['error'][] = 'Corrupt MAC file: uncompressed_size == zero';
|
||||
return false;
|
||||
}
|
||||
$thisfile_monkeysaudio['compression_ratio'] = $thisfile_monkeysaudio['compressed_size'] / ($thisfile_monkeysaudio['uncompressed_size'] + $thisfile_monkeysaudio_raw['nHeaderDataBytes']);
|
||||
$thisfile_monkeysaudio['bitrate'] = (($thisfile_monkeysaudio['samples'] * $thisfile_monkeysaudio['channels'] * $thisfile_monkeysaudio['bits_per_sample']) / $thisfile_monkeysaudio['playtime']) * $thisfile_monkeysaudio['compression_ratio'];
|
||||
$info['audio']['bitrate'] = $thisfile_monkeysaudio['bitrate'];
|
||||
|
||||
// add size of MAC header to avdataoffset
|
||||
if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) {
|
||||
$info['avdataoffset'] += $thisfile_monkeysaudio_raw['nDescriptorBytes'];
|
||||
$info['avdataoffset'] += $thisfile_monkeysaudio_raw['nHeaderBytes'];
|
||||
$info['avdataoffset'] += $thisfile_monkeysaudio_raw['nSeekTableBytes'];
|
||||
$info['avdataoffset'] += $thisfile_monkeysaudio_raw['nHeaderDataBytes'];
|
||||
|
||||
$info['avdataend'] -= $thisfile_monkeysaudio_raw['nTerminatingDataBytes'];
|
||||
} else {
|
||||
$info['avdataoffset'] += $offset;
|
||||
}
|
||||
|
||||
if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) {
|
||||
if ($thisfile_monkeysaudio_raw['cFileMD5'] === str_repeat("\x00", 16)) {
|
||||
//$info['warning'][] = 'cFileMD5 is null';
|
||||
} else {
|
||||
$info['md5_data_source'] = '';
|
||||
$md5 = $thisfile_monkeysaudio_raw['cFileMD5'];
|
||||
for ($i = 0; $i < strlen($md5); $i++) {
|
||||
$info['md5_data_source'] .= str_pad(dechex(ord($md5{$i})), 2, '00', STR_PAD_LEFT);
|
||||
}
|
||||
if (!preg_match('/^[0-9a-f]{32}$/', $info['md5_data_source'])) {
|
||||
unset($info['md5_data_source']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
$info['audio']['bits_per_sample'] = $thisfile_monkeysaudio['bits_per_sample'];
|
||||
$info['audio']['encoder'] = 'MAC v'.number_format($thisfile_monkeysaudio['version'], 2);
|
||||
$info['audio']['encoder_options'] = ucfirst($thisfile_monkeysaudio['compression']).' compression';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function MonkeyCompressionLevelNameLookup($compressionlevel) {
|
||||
static $MonkeyCompressionLevelNameLookup = array(
|
||||
0 => 'unknown',
|
||||
1000 => 'fast',
|
||||
2000 => 'normal',
|
||||
3000 => 'high',
|
||||
4000 => 'extra-high',
|
||||
5000 => 'insane'
|
||||
);
|
||||
return (isset($MonkeyCompressionLevelNameLookup[$compressionlevel]) ? $MonkeyCompressionLevelNameLookup[$compressionlevel] : 'invalid');
|
||||
}
|
||||
|
||||
function MonkeySamplesPerFrame($versionid, $compressionlevel) {
|
||||
if ($versionid >= 3950) {
|
||||
return 73728 * 4;
|
||||
} elseif ($versionid >= 3900) {
|
||||
return 73728;
|
||||
} elseif (($versionid >= 3800) && ($compressionlevel == 4000)) {
|
||||
return 73728;
|
||||
} else {
|
||||
return 9216;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
File diff suppressed because it is too large
Load Diff
@ -1,509 +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.mpc.php //
|
||||
// module for analyzing Musepack/MPEG+ Audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_mpc extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['mpc']['header'] = array();
|
||||
$thisfile_mpc_header = &$info['mpc']['header'];
|
||||
|
||||
$info['fileformat'] = 'mpc';
|
||||
$info['audio']['dataformat'] = 'mpc';
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
$info['audio']['channels'] = 2; // up to SV7 the format appears to have been hardcoded for stereo only
|
||||
$info['audio']['lossless'] = false;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$MPCheaderData = fread($this->getid3->fp, 4);
|
||||
$info['mpc']['header']['preamble'] = substr($MPCheaderData, 0, 4); // should be 'MPCK' (SV8) or 'MP+' (SV7), otherwise possible stream data (SV4-SV6)
|
||||
if (preg_match('#^MPCK#', $info['mpc']['header']['preamble'])) {
|
||||
|
||||
// this is SV8
|
||||
return $this->ParseMPCsv8();
|
||||
|
||||
} elseif (preg_match('#^MP\+#', $info['mpc']['header']['preamble'])) {
|
||||
|
||||
// this is SV7
|
||||
return $this->ParseMPCsv7();
|
||||
|
||||
} elseif (preg_match('/^[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0]/s', $MPCheaderData)) {
|
||||
|
||||
// this is SV4 - SV6, handle seperately
|
||||
return $this->ParseMPCsv6();
|
||||
|
||||
} else {
|
||||
|
||||
$info['error'][] = 'Expecting "MP+" or "MPCK" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($MPCheaderData, 0, 4)).'"';
|
||||
unset($info['fileformat']);
|
||||
unset($info['mpc']);
|
||||
return false;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function ParseMPCsv8() {
|
||||
// this is SV8
|
||||
// http://trac.musepack.net/trac/wiki/SV8Specification
|
||||
|
||||
$info = &$this->getid3->info;
|
||||
$thisfile_mpc_header = &$info['mpc']['header'];
|
||||
|
||||
$keyNameSize = 2;
|
||||
$maxHandledPacketLength = 9; // specs say: "n*8; 0 < n < 10"
|
||||
|
||||
$offset = ftell($this->getid3->fp);
|
||||
while ($offset < $info['avdataend']) {
|
||||
$thisPacket = array();
|
||||
$thisPacket['offset'] = $offset;
|
||||
$packet_offset = 0;
|
||||
|
||||
// Size is a variable-size field, could be 1-4 bytes (possibly more?)
|
||||
// read enough data in and figure out the exact size later
|
||||
$MPCheaderData = fread($this->getid3->fp, $keyNameSize + $maxHandledPacketLength);
|
||||
$packet_offset += $keyNameSize;
|
||||
$thisPacket['key'] = substr($MPCheaderData, 0, $keyNameSize);
|
||||
$thisPacket['key_name'] = $this->MPCsv8PacketName($thisPacket['key']);
|
||||
if ($thisPacket['key'] == $thisPacket['key_name']) {
|
||||
$info['error'][] = 'Found unexpected key value "'.$thisPacket['key'].'" at offset '.$thisPacket['offset'];
|
||||
return false;
|
||||
}
|
||||
$packetLength = 0;
|
||||
$thisPacket['packet_size'] = $this->SV8variableLengthInteger(substr($MPCheaderData, $keyNameSize), $packetLength); // includes keyname and packet_size field
|
||||
if ($thisPacket['packet_size'] === false) {
|
||||
$info['error'][] = 'Did not find expected packet length within '.$maxHandledPacketLength.' bytes at offset '.($thisPacket['offset'] + $keyNameSize);
|
||||
return false;
|
||||
}
|
||||
$packet_offset += $packetLength;
|
||||
$offset += $thisPacket['packet_size'];
|
||||
|
||||
switch ($thisPacket['key']) {
|
||||
case 'SH': // Stream Header
|
||||
$moreBytesToRead = $thisPacket['packet_size'] - $keyNameSize - $maxHandledPacketLength;
|
||||
if ($moreBytesToRead > 0) {
|
||||
$MPCheaderData .= fread($this->getid3->fp, $moreBytesToRead);
|
||||
}
|
||||
$thisPacket['crc'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 4));
|
||||
$packet_offset += 4;
|
||||
$thisPacket['stream_version'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1));
|
||||
$packet_offset += 1;
|
||||
|
||||
$packetLength = 0;
|
||||
$thisPacket['sample_count'] = $this->SV8variableLengthInteger(substr($MPCheaderData, $packet_offset, $maxHandledPacketLength), $packetLength);
|
||||
$packet_offset += $packetLength;
|
||||
|
||||
$packetLength = 0;
|
||||
$thisPacket['beginning_silence'] = $this->SV8variableLengthInteger(substr($MPCheaderData, $packet_offset, $maxHandledPacketLength), $packetLength);
|
||||
$packet_offset += $packetLength;
|
||||
|
||||
$otherUsefulData = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2));
|
||||
$packet_offset += 2;
|
||||
$thisPacket['sample_frequency_raw'] = (($otherUsefulData & 0xE000) >> 13);
|
||||
$thisPacket['max_bands_used'] = (($otherUsefulData & 0x1F00) >> 8);
|
||||
$thisPacket['channels'] = (($otherUsefulData & 0x00F0) >> 4) + 1;
|
||||
$thisPacket['ms_used'] = (bool) (($otherUsefulData & 0x0008) >> 3);
|
||||
$thisPacket['audio_block_frames'] = (($otherUsefulData & 0x0007) >> 0);
|
||||
$thisPacket['sample_frequency'] = $this->MPCfrequencyLookup($thisPacket['sample_frequency_raw']);
|
||||
|
||||
$thisfile_mpc_header['mid_side_stereo'] = $thisPacket['ms_used'];
|
||||
$thisfile_mpc_header['sample_rate'] = $thisPacket['sample_frequency'];
|
||||
$thisfile_mpc_header['samples'] = $thisPacket['sample_count'];
|
||||
$thisfile_mpc_header['stream_version_major'] = $thisPacket['stream_version'];
|
||||
|
||||
$info['audio']['channels'] = $thisPacket['channels'];
|
||||
$info['audio']['sample_rate'] = $thisPacket['sample_frequency'];
|
||||
$info['playtime_seconds'] = $thisPacket['sample_count'] / $thisPacket['sample_frequency'];
|
||||
$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
break;
|
||||
|
||||
case 'RG': // Replay Gain
|
||||
$moreBytesToRead = $thisPacket['packet_size'] - $keyNameSize - $maxHandledPacketLength;
|
||||
if ($moreBytesToRead > 0) {
|
||||
$MPCheaderData .= fread($this->getid3->fp, $moreBytesToRead);
|
||||
}
|
||||
$thisPacket['replaygain_version'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1));
|
||||
$packet_offset += 1;
|
||||
$thisPacket['replaygain_title_gain'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2));
|
||||
$packet_offset += 2;
|
||||
$thisPacket['replaygain_title_peak'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2));
|
||||
$packet_offset += 2;
|
||||
$thisPacket['replaygain_album_gain'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2));
|
||||
$packet_offset += 2;
|
||||
$thisPacket['replaygain_album_peak'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2));
|
||||
$packet_offset += 2;
|
||||
|
||||
if ($thisPacket['replaygain_title_gain']) { $info['replay_gain']['title']['gain'] = $thisPacket['replaygain_title_gain']; }
|
||||
if ($thisPacket['replaygain_title_peak']) { $info['replay_gain']['title']['peak'] = $thisPacket['replaygain_title_peak']; }
|
||||
if ($thisPacket['replaygain_album_gain']) { $info['replay_gain']['album']['gain'] = $thisPacket['replaygain_album_gain']; }
|
||||
if ($thisPacket['replaygain_album_peak']) { $info['replay_gain']['album']['peak'] = $thisPacket['replaygain_album_peak']; }
|
||||
break;
|
||||
|
||||
case 'EI': // Encoder Info
|
||||
$moreBytesToRead = $thisPacket['packet_size'] - $keyNameSize - $maxHandledPacketLength;
|
||||
if ($moreBytesToRead > 0) {
|
||||
$MPCheaderData .= fread($this->getid3->fp, $moreBytesToRead);
|
||||
}
|
||||
$profile_pns = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1));
|
||||
$packet_offset += 1;
|
||||
$quality_int = (($profile_pns & 0xF0) >> 4);
|
||||
$quality_dec = (($profile_pns & 0x0E) >> 3);
|
||||
$thisPacket['quality'] = (float) $quality_int + ($quality_dec / 8);
|
||||
$thisPacket['pns_tool'] = (bool) (($profile_pns & 0x01) >> 0);
|
||||
$thisPacket['version_major'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1));
|
||||
$packet_offset += 1;
|
||||
$thisPacket['version_minor'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1));
|
||||
$packet_offset += 1;
|
||||
$thisPacket['version_build'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1));
|
||||
$packet_offset += 1;
|
||||
$thisPacket['version'] = $thisPacket['version_major'].'.'.$thisPacket['version_minor'].'.'.$thisPacket['version_build'];
|
||||
|
||||
$info['audio']['encoder'] = 'MPC v'.$thisPacket['version'].' ('.(($thisPacket['version_minor'] % 2) ? 'unstable' : 'stable').')';
|
||||
$thisfile_mpc_header['encoder_version'] = $info['audio']['encoder'];
|
||||
//$thisfile_mpc_header['quality'] = (float) ($thisPacket['quality'] / 1.5875); // values can range from 0.000 to 15.875, mapped to qualities of 0.0 to 10.0
|
||||
$thisfile_mpc_header['quality'] = (float) ($thisPacket['quality'] - 5); // values can range from 0.000 to 15.875, of which 0..4 are "reserved/experimental", and 5..15 are mapped to qualities of 0.0 to 10.0
|
||||
break;
|
||||
|
||||
case 'SO': // Seek Table Offset
|
||||
$packetLength = 0;
|
||||
$thisPacket['seek_table_offset'] = $thisPacket['offset'] + $this->SV8variableLengthInteger(substr($MPCheaderData, $packet_offset, $maxHandledPacketLength), $packetLength);
|
||||
$packet_offset += $packetLength;
|
||||
break;
|
||||
|
||||
case 'ST': // Seek Table
|
||||
case 'SE': // Stream End
|
||||
case 'AP': // Audio Data
|
||||
// nothing useful here, just skip this packet
|
||||
$thisPacket = array();
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Found unhandled key type "'.$thisPacket['key'].'" at offset '.$thisPacket['offset'];
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
if (!empty($thisPacket)) {
|
||||
$info['mpc']['packets'][] = $thisPacket;
|
||||
}
|
||||
fseek($this->getid3->fp, $offset);
|
||||
}
|
||||
$thisfile_mpc_header['size'] = $offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
function ParseMPCsv7() {
|
||||
// this is SV7
|
||||
// http://www.uni-jena.de/~pfk/mpp/sv8/header.html
|
||||
|
||||
$info = &$this->getid3->info;
|
||||
$thisfile_mpc_header = &$info['mpc']['header'];
|
||||
$offset = 0;
|
||||
|
||||
$thisfile_mpc_header['size'] = 28;
|
||||
$MPCheaderData = $info['mpc']['header']['preamble'];
|
||||
$MPCheaderData .= fread($this->getid3->fp, $thisfile_mpc_header['size'] - strlen($info['mpc']['header']['preamble']));
|
||||
$offset = strlen('MP+');
|
||||
|
||||
$StreamVersionByte = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 1));
|
||||
$offset += 1;
|
||||
$thisfile_mpc_header['stream_version_major'] = ($StreamVersionByte & 0x0F) >> 0;
|
||||
$thisfile_mpc_header['stream_version_minor'] = ($StreamVersionByte & 0xF0) >> 4; // should always be 0, subversions no longer exist in SV8
|
||||
$thisfile_mpc_header['frame_count'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
if ($thisfile_mpc_header['stream_version_major'] != 7) {
|
||||
$info['error'][] = 'Only Musepack SV7 supported (this file claims to be v'.$thisfile_mpc_header['stream_version_major'].')';
|
||||
return false;
|
||||
}
|
||||
|
||||
$FlagsDWORD1 = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_mpc_header['intensity_stereo'] = (bool) (($FlagsDWORD1 & 0x80000000) >> 31);
|
||||
$thisfile_mpc_header['mid_side_stereo'] = (bool) (($FlagsDWORD1 & 0x40000000) >> 30);
|
||||
$thisfile_mpc_header['max_subband'] = ($FlagsDWORD1 & 0x3F000000) >> 24;
|
||||
$thisfile_mpc_header['raw']['profile'] = ($FlagsDWORD1 & 0x00F00000) >> 20;
|
||||
$thisfile_mpc_header['begin_loud'] = (bool) (($FlagsDWORD1 & 0x00080000) >> 19);
|
||||
$thisfile_mpc_header['end_loud'] = (bool) (($FlagsDWORD1 & 0x00040000) >> 18);
|
||||
$thisfile_mpc_header['raw']['sample_rate'] = ($FlagsDWORD1 & 0x00030000) >> 16;
|
||||
$thisfile_mpc_header['max_level'] = ($FlagsDWORD1 & 0x0000FFFF);
|
||||
|
||||
$thisfile_mpc_header['raw']['title_peak'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_mpc_header['raw']['title_gain'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 2), true);
|
||||
$offset += 2;
|
||||
|
||||
$thisfile_mpc_header['raw']['album_peak'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_mpc_header['raw']['album_gain'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 2), true);
|
||||
$offset += 2;
|
||||
|
||||
$FlagsDWORD2 = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_mpc_header['true_gapless'] = (bool) (($FlagsDWORD2 & 0x80000000) >> 31);
|
||||
$thisfile_mpc_header['last_frame_length'] = ($FlagsDWORD2 & 0x7FF00000) >> 20;
|
||||
|
||||
|
||||
$thisfile_mpc_header['raw']['not_sure_what'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 3));
|
||||
$offset += 3;
|
||||
$thisfile_mpc_header['raw']['encoder_version'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 1));
|
||||
$offset += 1;
|
||||
|
||||
$thisfile_mpc_header['profile'] = $this->MPCprofileNameLookup($thisfile_mpc_header['raw']['profile']);
|
||||
$thisfile_mpc_header['sample_rate'] = $this->MPCfrequencyLookup($thisfile_mpc_header['raw']['sample_rate']);
|
||||
if ($thisfile_mpc_header['sample_rate'] == 0) {
|
||||
$info['error'][] = 'Corrupt MPC file: frequency == zero';
|
||||
return false;
|
||||
}
|
||||
$info['audio']['sample_rate'] = $thisfile_mpc_header['sample_rate'];
|
||||
$thisfile_mpc_header['samples'] = ((($thisfile_mpc_header['frame_count'] - 1) * 1152) + $thisfile_mpc_header['last_frame_length']) * $info['audio']['channels'];
|
||||
|
||||
$info['playtime_seconds'] = ($thisfile_mpc_header['samples'] / $info['audio']['channels']) / $info['audio']['sample_rate'];
|
||||
if ($info['playtime_seconds'] == 0) {
|
||||
$info['error'][] = 'Corrupt MPC file: playtime_seconds == zero';
|
||||
return false;
|
||||
}
|
||||
|
||||
// add size of file header to avdataoffset - calc bitrate correctly + MD5 data
|
||||
$info['avdataoffset'] += $thisfile_mpc_header['size'];
|
||||
|
||||
$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
|
||||
$thisfile_mpc_header['title_peak'] = $thisfile_mpc_header['raw']['title_peak'];
|
||||
$thisfile_mpc_header['title_peak_db'] = $this->MPCpeakDBLookup($thisfile_mpc_header['title_peak']);
|
||||
if ($thisfile_mpc_header['raw']['title_gain'] < 0) {
|
||||
$thisfile_mpc_header['title_gain_db'] = (float) (32768 + $thisfile_mpc_header['raw']['title_gain']) / -100;
|
||||
} else {
|
||||
$thisfile_mpc_header['title_gain_db'] = (float) $thisfile_mpc_header['raw']['title_gain'] / 100;
|
||||
}
|
||||
|
||||
$thisfile_mpc_header['album_peak'] = $thisfile_mpc_header['raw']['album_peak'];
|
||||
$thisfile_mpc_header['album_peak_db'] = $this->MPCpeakDBLookup($thisfile_mpc_header['album_peak']);
|
||||
if ($thisfile_mpc_header['raw']['album_gain'] < 0) {
|
||||
$thisfile_mpc_header['album_gain_db'] = (float) (32768 + $thisfile_mpc_header['raw']['album_gain']) / -100;
|
||||
} else {
|
||||
$thisfile_mpc_header['album_gain_db'] = (float) $thisfile_mpc_header['raw']['album_gain'] / 100;;
|
||||
}
|
||||
$thisfile_mpc_header['encoder_version'] = $this->MPCencoderVersionLookup($thisfile_mpc_header['raw']['encoder_version']);
|
||||
|
||||
$info['replay_gain']['track']['adjustment'] = $thisfile_mpc_header['title_gain_db'];
|
||||
$info['replay_gain']['album']['adjustment'] = $thisfile_mpc_header['album_gain_db'];
|
||||
|
||||
if ($thisfile_mpc_header['title_peak'] > 0) {
|
||||
$info['replay_gain']['track']['peak'] = $thisfile_mpc_header['title_peak'];
|
||||
} elseif (round($thisfile_mpc_header['max_level'] * 1.18) > 0) {
|
||||
$info['replay_gain']['track']['peak'] = getid3_lib::CastAsInt(round($thisfile_mpc_header['max_level'] * 1.18)); // why? I don't know - see mppdec.c
|
||||
}
|
||||
if ($thisfile_mpc_header['album_peak'] > 0) {
|
||||
$info['replay_gain']['album']['peak'] = $thisfile_mpc_header['album_peak'];
|
||||
}
|
||||
|
||||
//$info['audio']['encoder'] = 'SV'.$thisfile_mpc_header['stream_version_major'].'.'.$thisfile_mpc_header['stream_version_minor'].', '.$thisfile_mpc_header['encoder_version'];
|
||||
$info['audio']['encoder'] = $thisfile_mpc_header['encoder_version'];
|
||||
$info['audio']['encoder_options'] = $thisfile_mpc_header['profile'];
|
||||
$thisfile_mpc_header['quality'] = (float) ($thisfile_mpc_header['raw']['profile'] - 5); // values can range from 0 to 15, of which 0..4 are "reserved/experimental", and 5..15 are mapped to qualities of 0.0 to 10.0
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function ParseMPCsv6() {
|
||||
// this is SV4 - SV6
|
||||
|
||||
$info = &$this->getid3->info;
|
||||
$thisfile_mpc_header = &$info['mpc']['header'];
|
||||
$offset = 0;
|
||||
|
||||
$thisfile_mpc_header['size'] = 8;
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$MPCheaderData = fread($this->getid3->fp, $thisfile_mpc_header['size']);
|
||||
|
||||
// add size of file header to avdataoffset - calc bitrate correctly + MD5 data
|
||||
$info['avdataoffset'] += $thisfile_mpc_header['size'];
|
||||
|
||||
// Most of this code adapted from Jurgen Faul's MPEGplus source code - thanks Jurgen! :)
|
||||
$HeaderDWORD[0] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, 0, 4));
|
||||
$HeaderDWORD[1] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, 4, 4));
|
||||
|
||||
|
||||
// DDDD DDDD CCCC CCCC BBBB BBBB AAAA AAAA
|
||||
// aaaa aaaa abcd dddd dddd deee eeff ffff
|
||||
//
|
||||
// a = bitrate = anything
|
||||
// b = IS = anything
|
||||
// c = MS = anything
|
||||
// d = streamversion = 0000000004 or 0000000005 or 0000000006
|
||||
// e = maxband = anything
|
||||
// f = blocksize = 000001 for SV5+, anything(?) for SV4
|
||||
|
||||
$thisfile_mpc_header['target_bitrate'] = (($HeaderDWORD[0] & 0xFF800000) >> 23);
|
||||
$thisfile_mpc_header['intensity_stereo'] = (bool) (($HeaderDWORD[0] & 0x00400000) >> 22);
|
||||
$thisfile_mpc_header['mid_side_stereo'] = (bool) (($HeaderDWORD[0] & 0x00200000) >> 21);
|
||||
$thisfile_mpc_header['stream_version_major'] = ($HeaderDWORD[0] & 0x001FF800) >> 11;
|
||||
$thisfile_mpc_header['stream_version_minor'] = 0; // no sub-version numbers before SV7
|
||||
$thisfile_mpc_header['max_band'] = ($HeaderDWORD[0] & 0x000007C0) >> 6; // related to lowpass frequency, not sure how it translates exactly
|
||||
$thisfile_mpc_header['block_size'] = ($HeaderDWORD[0] & 0x0000003F);
|
||||
|
||||
switch ($thisfile_mpc_header['stream_version_major']) {
|
||||
case 4:
|
||||
$thisfile_mpc_header['frame_count'] = ($HeaderDWORD[1] >> 16);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
case 6:
|
||||
$thisfile_mpc_header['frame_count'] = $HeaderDWORD[1];
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['error'] = 'Expecting 4, 5 or 6 in version field, found '.$thisfile_mpc_header['stream_version_major'].' instead';
|
||||
unset($info['mpc']);
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (($thisfile_mpc_header['stream_version_major'] > 4) && ($thisfile_mpc_header['block_size'] != 1)) {
|
||||
$info['warning'][] = 'Block size expected to be 1, actual value found: '.$thisfile_mpc_header['block_size'];
|
||||
}
|
||||
|
||||
$thisfile_mpc_header['sample_rate'] = 44100; // AB: used by all files up to SV7
|
||||
$info['audio']['sample_rate'] = $thisfile_mpc_header['sample_rate'];
|
||||
$thisfile_mpc_header['samples'] = $thisfile_mpc_header['frame_count'] * 1152 * $info['audio']['channels'];
|
||||
|
||||
if ($thisfile_mpc_header['target_bitrate'] == 0) {
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
} else {
|
||||
$info['audio']['bitrate_mode'] = 'cbr';
|
||||
}
|
||||
|
||||
$info['mpc']['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 * 44100 / $thisfile_mpc_header['frame_count'] / 1152;
|
||||
$info['audio']['bitrate'] = $info['mpc']['bitrate'];
|
||||
$info['audio']['encoder'] = 'SV'.$thisfile_mpc_header['stream_version_major'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function MPCprofileNameLookup($profileid) {
|
||||
static $MPCprofileNameLookup = array(
|
||||
0 => 'no profile',
|
||||
1 => 'Experimental',
|
||||
2 => 'unused',
|
||||
3 => 'unused',
|
||||
4 => 'unused',
|
||||
5 => 'below Telephone (q = 0.0)',
|
||||
6 => 'below Telephone (q = 1.0)',
|
||||
7 => 'Telephone (q = 2.0)',
|
||||
8 => 'Thumb (q = 3.0)',
|
||||
9 => 'Radio (q = 4.0)',
|
||||
10 => 'Standard (q = 5.0)',
|
||||
11 => 'Extreme (q = 6.0)',
|
||||
12 => 'Insane (q = 7.0)',
|
||||
13 => 'BrainDead (q = 8.0)',
|
||||
14 => 'above BrainDead (q = 9.0)',
|
||||
15 => 'above BrainDead (q = 10.0)'
|
||||
);
|
||||
return (isset($MPCprofileNameLookup[$profileid]) ? $MPCprofileNameLookup[$profileid] : 'invalid');
|
||||
}
|
||||
|
||||
function MPCfrequencyLookup($frequencyid) {
|
||||
static $MPCfrequencyLookup = array(
|
||||
0 => 44100,
|
||||
1 => 48000,
|
||||
2 => 37800,
|
||||
3 => 32000
|
||||
);
|
||||
return (isset($MPCfrequencyLookup[$frequencyid]) ? $MPCfrequencyLookup[$frequencyid] : 'invalid');
|
||||
}
|
||||
|
||||
function MPCpeakDBLookup($intvalue) {
|
||||
if ($intvalue > 0) {
|
||||
return ((log10($intvalue) / log10(2)) - 15) * 6;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function MPCencoderVersionLookup($encoderversion) {
|
||||
//Encoder version * 100 (106 = 1.06)
|
||||
//EncoderVersion % 10 == 0 Release (1.0)
|
||||
//EncoderVersion % 2 == 0 Beta (1.06)
|
||||
//EncoderVersion % 2 == 1 Alpha (1.05a...z)
|
||||
|
||||
if ($encoderversion == 0) {
|
||||
// very old version, not known exactly which
|
||||
return 'Buschmann v1.7.0-v1.7.9 or Klemm v0.90-v1.05';
|
||||
}
|
||||
|
||||
if (($encoderversion % 10) == 0) {
|
||||
|
||||
// release version
|
||||
return number_format($encoderversion / 100, 2);
|
||||
|
||||
} elseif (($encoderversion % 2) == 0) {
|
||||
|
||||
// beta version
|
||||
return number_format($encoderversion / 100, 2).' beta';
|
||||
|
||||
}
|
||||
|
||||
// alpha version
|
||||
return number_format($encoderversion / 100, 2).' alpha';
|
||||
}
|
||||
|
||||
function SV8variableLengthInteger($data, &$packetLength, $maxHandledPacketLength=9) {
|
||||
$packet_size = 0;
|
||||
for ($packetLength = 1; $packetLength <= $maxHandledPacketLength; $packetLength++) {
|
||||
// variable-length size field:
|
||||
// bits, big-endian
|
||||
// 0xxx xxxx - value 0 to 2^7-1
|
||||
// 1xxx xxxx 0xxx xxxx - value 0 to 2^14-1
|
||||
// 1xxx xxxx 1xxx xxxx 0xxx xxxx - value 0 to 2^21-1
|
||||
// 1xxx xxxx 1xxx xxxx 1xxx xxxx 0xxx xxxx - value 0 to 2^28-1
|
||||
// ...
|
||||
$thisbyte = ord(substr($data, ($packetLength - 1), 1));
|
||||
// look through bytes until find a byte with MSB==0
|
||||
$packet_size = ($packet_size << 7);
|
||||
$packet_size = ($packet_size | ($thisbyte & 0x7F));
|
||||
if (($thisbyte & 0x80) === 0) {
|
||||
break;
|
||||
}
|
||||
if ($packetLength >= $maxHandledPacketLength) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return $packet_size;
|
||||
}
|
||||
|
||||
function MPCsv8PacketName($packetKey) {
|
||||
static $MPCsv8PacketName = array();
|
||||
if (empty($MPCsv8PacketName)) {
|
||||
$MPCsv8PacketName = array(
|
||||
'AP' => 'Audio Packet',
|
||||
'CT' => 'Chapter Tag',
|
||||
'EI' => 'Encoder Info',
|
||||
'RG' => 'Replay Gain',
|
||||
'SE' => 'Stream End',
|
||||
'SH' => 'Stream Header',
|
||||
'SO' => 'Seek Table Offset',
|
||||
'ST' => 'Seek Table',
|
||||
);
|
||||
}
|
||||
return (isset($MPCsv8PacketName[$packetKey]) ? $MPCsv8PacketName[$packetKey] : $packetKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,705 +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 extends getid3_handler
|
||||
{
|
||||
var $inline_attachments = true; // true: return full data for all attachments; false: return no data for all attachments; integer: return data for attachments <= than this; string: save as file to this directory
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'ogg';
|
||||
|
||||
// Warn about illegal tags - only vorbiscomments are allowed
|
||||
if (isset($info['id3v2'])) {
|
||||
$info['warning'][] = 'Illegal ID3v2 tag present.';
|
||||
}
|
||||
if (isset($info['id3v1'])) {
|
||||
$info['warning'][] = 'Illegal ID3v1 tag present.';
|
||||
}
|
||||
if (isset($info['ape'])) {
|
||||
$info['warning'][] = 'Illegal APE tag present.';
|
||||
}
|
||||
|
||||
|
||||
// Page 1 - Stream Header
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
|
||||
$oggpageinfo = $this->ParseOggPageHeader();
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
|
||||
|
||||
if (ftell($this->getid3->fp) >= $this->getid3->fread_buffer_size()) {
|
||||
$info['error'][] = 'Could not find start of Ogg page in the first '.$this->getid3->fread_buffer_size().' bytes (this might not be an Ogg-Vorbis file?)';
|
||||
unset($info['fileformat']);
|
||||
unset($info['ogg']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$filedata = fread($this->getid3->fp, $oggpageinfo['page_length']);
|
||||
$filedataoffset = 0;
|
||||
|
||||
if (substr($filedata, 0, 4) == 'fLaC') {
|
||||
|
||||
$info['audio']['dataformat'] = 'flac';
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
$info['audio']['lossless'] = true;
|
||||
|
||||
} elseif (substr($filedata, 1, 6) == 'vorbis') {
|
||||
|
||||
$this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo);
|
||||
|
||||
} elseif (substr($filedata, 0, 8) == 'Speex ') {
|
||||
|
||||
// http://www.speex.org/manual/node10.html
|
||||
|
||||
$info['audio']['dataformat'] = 'speex';
|
||||
$info['mime_type'] = 'audio/speex';
|
||||
$info['audio']['bitrate_mode'] = 'abr';
|
||||
$info['audio']['lossless'] = false;
|
||||
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_string'] = substr($filedata, $filedataoffset, 8); // hard-coded to 'Speex '
|
||||
$filedataoffset += 8;
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version'] = substr($filedata, $filedataoffset, 20);
|
||||
$filedataoffset += 20;
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version_id'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['header_size'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode_bitstream_version'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['bitrate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['framesize'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['frames_per_packet'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['extra_headers'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved1'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved2'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
|
||||
$info['speex']['speex_version'] = trim($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version']);
|
||||
$info['speex']['sample_rate'] = $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate'];
|
||||
$info['speex']['channels'] = $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels'];
|
||||
$info['speex']['vbr'] = (bool) $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr'];
|
||||
$info['speex']['band_type'] = $this->SpeexBandModeLookup($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode']);
|
||||
|
||||
$info['audio']['sample_rate'] = $info['speex']['sample_rate'];
|
||||
$info['audio']['channels'] = $info['speex']['channels'];
|
||||
if ($info['speex']['vbr']) {
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
}
|
||||
|
||||
|
||||
} elseif (substr($filedata, 0, 8) == "fishead\x00") {
|
||||
|
||||
// Ogg Skeleton version 3.0 Format Specification
|
||||
// http://xiph.org/ogg/doc/skeleton.html
|
||||
$filedataoffset += 8;
|
||||
$info['ogg']['skeleton']['fishead']['raw']['version_major'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2));
|
||||
$filedataoffset += 2;
|
||||
$info['ogg']['skeleton']['fishead']['raw']['version_minor'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2));
|
||||
$filedataoffset += 2;
|
||||
$info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
|
||||
$filedataoffset += 8;
|
||||
$info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
|
||||
$filedataoffset += 8;
|
||||
$info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
|
||||
$filedataoffset += 8;
|
||||
$info['ogg']['skeleton']['fishead']['raw']['basetime_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
|
||||
$filedataoffset += 8;
|
||||
$info['ogg']['skeleton']['fishead']['raw']['utc'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 20));
|
||||
$filedataoffset += 20;
|
||||
|
||||
$info['ogg']['skeleton']['fishead']['version'] = $info['ogg']['skeleton']['fishead']['raw']['version_major'].'.'.$info['ogg']['skeleton']['fishead']['raw']['version_minor'];
|
||||
$info['ogg']['skeleton']['fishead']['presentationtime'] = $info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator'];
|
||||
$info['ogg']['skeleton']['fishead']['basetime'] = $info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['basetime_denominator'];
|
||||
$info['ogg']['skeleton']['fishead']['utc'] = $info['ogg']['skeleton']['fishead']['raw']['utc'];
|
||||
|
||||
|
||||
$counter = 0;
|
||||
do {
|
||||
$oggpageinfo = $this->ParseOggPageHeader();
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno'].'.'.$counter++] = $oggpageinfo;
|
||||
$filedata = fread($this->getid3->fp, $oggpageinfo['page_length']);
|
||||
fseek($this->getid3->fp, $oggpageinfo['page_end_offset'], SEEK_SET);
|
||||
|
||||
if (substr($filedata, 0, 8) == "fisbone\x00") {
|
||||
|
||||
$filedataoffset = 8;
|
||||
$info['ogg']['skeleton']['fisbone']['raw']['message_header_offset'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['skeleton']['fisbone']['raw']['serial_number'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['skeleton']['fisbone']['raw']['number_header_packets'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['skeleton']['fisbone']['raw']['granulerate_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
|
||||
$filedataoffset += 8;
|
||||
$info['ogg']['skeleton']['fisbone']['raw']['granulerate_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
|
||||
$filedataoffset += 8;
|
||||
$info['ogg']['skeleton']['fisbone']['raw']['basegranule'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
|
||||
$filedataoffset += 8;
|
||||
$info['ogg']['skeleton']['fisbone']['raw']['preroll'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['skeleton']['fisbone']['raw']['granuleshift'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
|
||||
$filedataoffset += 1;
|
||||
$info['ogg']['skeleton']['fisbone']['raw']['padding'] = substr($filedata, $filedataoffset, 3);
|
||||
$filedataoffset += 3;
|
||||
|
||||
} elseif (substr($filedata, 1, 6) == 'theora') {
|
||||
|
||||
$info['video']['dataformat'] = 'theora';
|
||||
$info['error'][] = 'Ogg Theora not correctly handled in this version of getID3 ['.$this->getid3->version().']';
|
||||
//break;
|
||||
|
||||
} elseif (substr($filedata, 1, 6) == 'vorbis') {
|
||||
|
||||
$this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo);
|
||||
|
||||
} else {
|
||||
$info['error'][] = 'unexpected';
|
||||
//break;
|
||||
}
|
||||
//} while ($oggpageinfo['page_seqno'] == 0);
|
||||
} while (($oggpageinfo['page_seqno'] == 0) && (substr($filedata, 0, 8) != "fisbone\x00"));
|
||||
fseek($this->getid3->fp, $oggpageinfo['page_start_offset'], SEEK_SET);
|
||||
|
||||
|
||||
$info['error'][] = 'Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().']';
|
||||
//return false;
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
$info['error'][] = 'Expecting either "Speex " or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"';
|
||||
unset($info['ogg']);
|
||||
unset($info['mime_type']);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// Page 2 - Comment Header
|
||||
$oggpageinfo = $this->ParseOggPageHeader();
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
|
||||
|
||||
switch ($info['audio']['dataformat']) {
|
||||
case 'vorbis':
|
||||
$filedata = fread($this->getid3->fp, $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, 0, 1));
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, 1, 6); // hard-coded to 'vorbis'
|
||||
|
||||
$this->ParseVorbisCommentsFilepointer();
|
||||
break;
|
||||
|
||||
case 'flac':
|
||||
$getid3_flac = new getid3_flac($this->getid3);
|
||||
if (!$getid3_flac->FLACparseMETAdata()) {
|
||||
$info['error'][] = 'Failed to parse FLAC headers';
|
||||
return false;
|
||||
}
|
||||
unset($getid3_flac);
|
||||
break;
|
||||
|
||||
case 'speex':
|
||||
fseek($this->getid3->fp, $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length'], SEEK_CUR);
|
||||
$this->ParseVorbisCommentsFilepointer();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Last Page - Number of Samples
|
||||
|
||||
if (!getid3_lib::intValueSupported($info['avdataend'])) {
|
||||
|
||||
$info['warning'][] = 'Unable to parse Ogg end chunk file (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)';
|
||||
|
||||
} else {
|
||||
|
||||
fseek($this->getid3->fp, max($info['avdataend'] - $this->getid3->fread_buffer_size(), 0), SEEK_SET);
|
||||
$LastChunkOfOgg = strrev(fread($this->getid3->fp, $this->getid3->fread_buffer_size()));
|
||||
if ($LastOggSpostion = strpos($LastChunkOfOgg, 'SggO')) {
|
||||
fseek($this->getid3->fp, $info['avdataend'] - ($LastOggSpostion + strlen('SggO')), SEEK_SET);
|
||||
$info['avdataend'] = ftell($this->getid3->fp);
|
||||
$info['ogg']['pageheader']['eos'] = $this->ParseOggPageHeader();
|
||||
$info['ogg']['samples'] = $info['ogg']['pageheader']['eos']['pcm_abs_position'];
|
||||
if ($info['ogg']['samples'] == 0) {
|
||||
$info['error'][] = 'Corrupt Ogg file: eos.number of samples == zero';
|
||||
return false;
|
||||
}
|
||||
if (!empty($info['audio']['sample_rate'])) {
|
||||
$info['ogg']['bitrate_average'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($info['ogg']['samples'] / $info['audio']['sample_rate']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!empty($info['ogg']['bitrate_average'])) {
|
||||
$info['audio']['bitrate'] = $info['ogg']['bitrate_average'];
|
||||
} elseif (!empty($info['ogg']['bitrate_nominal'])) {
|
||||
$info['audio']['bitrate'] = $info['ogg']['bitrate_nominal'];
|
||||
} elseif (!empty($info['ogg']['bitrate_min']) && !empty($info['ogg']['bitrate_max'])) {
|
||||
$info['audio']['bitrate'] = ($info['ogg']['bitrate_min'] + $info['ogg']['bitrate_max']) / 2;
|
||||
}
|
||||
if (isset($info['audio']['bitrate']) && !isset($info['playtime_seconds'])) {
|
||||
if ($info['audio']['bitrate'] == 0) {
|
||||
$info['error'][] = 'Corrupt Ogg file: bitrate_audio == zero';
|
||||
return false;
|
||||
}
|
||||
$info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate']);
|
||||
}
|
||||
|
||||
if (isset($info['ogg']['vendor'])) {
|
||||
$info['audio']['encoder'] = preg_replace('/^Encoded with /', '', $info['ogg']['vendor']);
|
||||
|
||||
// Vorbis only
|
||||
if ($info['audio']['dataformat'] == 'vorbis') {
|
||||
|
||||
// Vorbis 1.0 starts with Xiph.Org
|
||||
if (preg_match('/^Xiph.Org/', $info['audio']['encoder'])) {
|
||||
|
||||
if ($info['audio']['bitrate_mode'] == 'abr') {
|
||||
|
||||
// Set -b 128 on abr files
|
||||
$info['audio']['encoder_options'] = '-b '.round($info['ogg']['bitrate_nominal'] / 1000);
|
||||
|
||||
} elseif (($info['audio']['bitrate_mode'] == 'vbr') && ($info['audio']['channels'] == 2) && ($info['audio']['sample_rate'] >= 44100) && ($info['audio']['sample_rate'] <= 48000)) {
|
||||
// Set -q N on vbr files
|
||||
$info['audio']['encoder_options'] = '-q '.$this->get_quality_from_nominal_bitrate($info['ogg']['bitrate_nominal']);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($info['audio']['encoder_options']) && !empty($info['ogg']['bitrate_nominal'])) {
|
||||
$info['audio']['encoder_options'] = 'Nominal bitrate: '.intval(round($info['ogg']['bitrate_nominal'] / 1000)).'kbps';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function ParseVorbisPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) {
|
||||
$info = &$this->getid3->info;
|
||||
$info['audio']['dataformat'] = 'vorbis';
|
||||
$info['audio']['lossless'] = false;
|
||||
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
|
||||
$filedataoffset += 1;
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, $filedataoffset, 6); // hard-coded to 'vorbis'
|
||||
$filedataoffset += 6;
|
||||
$info['ogg']['bitstreamversion'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['numberofchannels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
|
||||
$filedataoffset += 1;
|
||||
$info['audio']['channels'] = $info['ogg']['numberofchannels'];
|
||||
$info['ogg']['samplerate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
if ($info['ogg']['samplerate'] == 0) {
|
||||
$info['error'][] = 'Corrupt Ogg file: sample rate == zero';
|
||||
return false;
|
||||
}
|
||||
$info['audio']['sample_rate'] = $info['ogg']['samplerate'];
|
||||
$info['ogg']['samples'] = 0; // filled in later
|
||||
$info['ogg']['bitrate_average'] = 0; // filled in later
|
||||
$info['ogg']['bitrate_max'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['bitrate_nominal'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['bitrate_min'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
|
||||
$filedataoffset += 4;
|
||||
$info['ogg']['blocksize_small'] = pow(2, getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0x0F);
|
||||
$info['ogg']['blocksize_large'] = pow(2, (getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0xF0) >> 4);
|
||||
$info['ogg']['stop_bit'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); // must be 1, marks end of packet
|
||||
|
||||
$info['audio']['bitrate_mode'] = 'vbr'; // overridden if actually abr
|
||||
if ($info['ogg']['bitrate_max'] == 0xFFFFFFFF) {
|
||||
unset($info['ogg']['bitrate_max']);
|
||||
$info['audio']['bitrate_mode'] = 'abr';
|
||||
}
|
||||
if ($info['ogg']['bitrate_nominal'] == 0xFFFFFFFF) {
|
||||
unset($info['ogg']['bitrate_nominal']);
|
||||
}
|
||||
if ($info['ogg']['bitrate_min'] == 0xFFFFFFFF) {
|
||||
unset($info['ogg']['bitrate_min']);
|
||||
$info['audio']['bitrate_mode'] = 'abr';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function ParseOggPageHeader() {
|
||||
// http://xiph.org/ogg/vorbis/doc/framing.html
|
||||
$oggheader['page_start_offset'] = ftell($this->getid3->fp); // where we started from in the file
|
||||
|
||||
$filedata = fread($this->getid3->fp, $this->getid3->fread_buffer_size());
|
||||
$filedataoffset = 0;
|
||||
while ((substr($filedata, $filedataoffset++, 4) != 'OggS')) {
|
||||
if ((ftell($this->getid3->fp) - $oggheader['page_start_offset']) >= $this->getid3->fread_buffer_size()) {
|
||||
// should be found before here
|
||||
return false;
|
||||
}
|
||||
if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) {
|
||||
if (feof($this->getid3->fp) || (($filedata .= fread($this->getid3->fp, $this->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($this->getid3->fp, $oggheader['header_end_offset'], SEEK_SET);
|
||||
|
||||
return $oggheader;
|
||||
}
|
||||
|
||||
|
||||
function ParseVorbisCommentsFilepointer() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$OriginalOffset = ftell($this->getid3->fp);
|
||||
$commentdataoffset = 0;
|
||||
$VorbisCommentPage = 1;
|
||||
|
||||
switch ($info['audio']['dataformat']) {
|
||||
case 'vorbis':
|
||||
$CommentStartOffset = $info['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset']; // Second Ogg page, after header block
|
||||
fseek($this->getid3->fp, $CommentStartOffset, SEEK_SET);
|
||||
$commentdataoffset = 27 + $info['ogg']['pageheader'][$VorbisCommentPage]['page_segments'];
|
||||
$commentdata = fread($this->getid3->fp, getid3_ogg::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset);
|
||||
|
||||
$commentdataoffset += (strlen('vorbis') + 1);
|
||||
break;
|
||||
|
||||
case 'flac':
|
||||
$CommentStartOffset = $info['flac']['VORBIS_COMMENT']['raw']['offset'] + 4;
|
||||
fseek($this->getid3->fp, $CommentStartOffset, SEEK_SET);
|
||||
$commentdata = fread($this->getid3->fp, $info['flac']['VORBIS_COMMENT']['raw']['block_length']);
|
||||
break;
|
||||
|
||||
case 'speex':
|
||||
$CommentStartOffset = $info['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset']; // Second Ogg page, after header block
|
||||
fseek($this->getid3->fp, $CommentStartOffset, SEEK_SET);
|
||||
$commentdataoffset = 27 + $info['ogg']['pageheader'][$VorbisCommentPage]['page_segments'];
|
||||
$commentdata = fread($this->getid3->fp, getid3_ogg::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
$VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
|
||||
$commentdataoffset += 4;
|
||||
|
||||
$info['ogg']['vendor'] = substr($commentdata, $commentdataoffset, $VendorSize);
|
||||
$commentdataoffset += $VendorSize;
|
||||
|
||||
$CommentsCount = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
|
||||
$commentdataoffset += 4;
|
||||
$info['avdataoffset'] = $CommentStartOffset + $commentdataoffset;
|
||||
|
||||
$basicfields = array('TITLE', 'ARTIST', 'ALBUM', 'TRACKNUMBER', 'GENRE', 'DATE', 'DESCRIPTION', 'COMMENT');
|
||||
$ThisFileInfo_ogg_comments_raw = &$info['ogg']['comments_raw'];
|
||||
for ($i = 0; $i < $CommentsCount; $i++) {
|
||||
|
||||
$ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] = $CommentStartOffset + $commentdataoffset;
|
||||
|
||||
if (ftell($this->getid3->fp) < ($ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + 4)) {
|
||||
if ($oggpageinfo = $this->ParseOggPageHeader()) {
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
|
||||
|
||||
$VorbisCommentPage++;
|
||||
|
||||
// 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 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
|
||||
$commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
|
||||
|
||||
// Finally, stick the unused data back on the end
|
||||
$commentdata .= $AsYetUnusedData;
|
||||
|
||||
//$commentdata .= fread($this->getid3->fp, $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
|
||||
$commentdata .= fread($this->getid3->fp, $this->OggPageSegmentLength($info['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
|
||||
$info['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'] > $info['avdataend']) || ($ThisFileInfo_ogg_comments_raw[$i]['size'] < 0)) {
|
||||
$info['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 = $this->ParseOggPageHeader();
|
||||
$info['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 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
|
||||
$commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
|
||||
|
||||
// Finally, stick the unused data back on the end
|
||||
$commentdata .= $AsYetUnusedData;
|
||||
|
||||
//$commentdata .= fread($this->getid3->fp, $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
|
||||
if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) {
|
||||
$info['warning'][] = 'undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.ftell($this->getid3->fp);
|
||||
break;
|
||||
}
|
||||
$readlength = getid3_ogg::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1);
|
||||
if ($readlength <= 0) {
|
||||
$info['warning'][] = 'invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.ftell($this->getid3->fp);
|
||||
break;
|
||||
}
|
||||
$commentdata .= fread($this->getid3->fp, $readlength);
|
||||
|
||||
//$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];
|
||||
}
|
||||
$ThisFileInfo_ogg_comments_raw[$i]['offset'] = $commentdataoffset;
|
||||
$commentstring = substr($commentdata, $commentdataoffset, $ThisFileInfo_ogg_comments_raw[$i]['size']);
|
||||
$commentdataoffset += $ThisFileInfo_ogg_comments_raw[$i]['size'];
|
||||
|
||||
if (!$commentstring) {
|
||||
|
||||
// no comment?
|
||||
$info['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']);
|
||||
$ThisFileInfo_ogg_comments_raw[$i]['data_length'] = strlen($ThisFileInfo_ogg_comments_raw[$i]['data']);
|
||||
|
||||
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']);
|
||||
$info['ogg']['comments'][strtolower($ThisFileInfo_ogg_comments_raw[$i]['key'])][] = $ThisFileInfo_ogg_comments_raw[$i]['value'];
|
||||
} else {
|
||||
do {
|
||||
if ($this->inline_attachments === false) {
|
||||
// skip entirely
|
||||
unset($ThisFileInfo_ogg_comments_raw[$i]['data']);
|
||||
break;
|
||||
}
|
||||
if ($this->inline_attachments === true) {
|
||||
// great
|
||||
} elseif (is_int($this->inline_attachments)) {
|
||||
if ($this->inline_attachments < $ThisFileInfo_ogg_comments_raw[$i]['data_length']) {
|
||||
// too big, skip
|
||||
$info['warning'][] = 'attachment at '.$ThisFileInfo_ogg_comments_raw[$i]['offset'].' is too large to process inline ('.number_format($ThisFileInfo_ogg_comments_raw[$i]['data_length']).' bytes)';
|
||||
unset($ThisFileInfo_ogg_comments_raw[$i]['data']);
|
||||
break;
|
||||
}
|
||||
} elseif (is_string($this->inline_attachments)) {
|
||||
$this->inline_attachments = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->inline_attachments), DIRECTORY_SEPARATOR);
|
||||
if (!is_dir($this->inline_attachments) || !is_writable($this->inline_attachments)) {
|
||||
// cannot write, skip
|
||||
$info['warning'][] = 'attachment at '.$ThisFileInfo_ogg_comments_raw[$i]['offset'].' cannot be saved to "'.$this->inline_attachments.'" (not writable)';
|
||||
unset($ThisFileInfo_ogg_comments_raw[$i]['data']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if we get this far, must be OK
|
||||
if (is_string($this->inline_attachments)) {
|
||||
$destination_filename = $this->inline_attachments.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$ThisFileInfo_ogg_comments_raw[$i]['offset'];
|
||||
if (!file_exists($destination_filename) || is_writable($destination_filename)) {
|
||||
file_put_contents($destination_filename, $ThisFileInfo_ogg_comments_raw[$i]['data']);
|
||||
} else {
|
||||
$info['warning'][] = 'attachment at '.$ThisFileInfo_ogg_comments_raw[$i]['offset'].' cannot be saved to "'.$destination_filename.'" (not writable)';
|
||||
}
|
||||
$ThisFileInfo_ogg_comments_raw[$i]['data_filename'] = $destination_filename;
|
||||
unset($ThisFileInfo_ogg_comments_raw[$i]['data']);
|
||||
} else {
|
||||
$info['ogg']['comments']['picture'][] = array('data'=>$ThisFileInfo_ogg_comments_raw[$i]['data'], 'image_mime'=>$ThisFileInfo_ogg_comments_raw[$i]['image_mime']);
|
||||
}
|
||||
} while (false);
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
$info['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($info['ogg']['comments']) && is_array($info['ogg']['comments'])) {
|
||||
foreach ($info['ogg']['comments'] as $index => $commentvalue) {
|
||||
switch ($index) {
|
||||
case 'rg_audiophile':
|
||||
case 'replaygain_album_gain':
|
||||
$info['replay_gain']['album']['adjustment'] = (double) $commentvalue[0];
|
||||
unset($info['ogg']['comments'][$index]);
|
||||
break;
|
||||
|
||||
case 'rg_radio':
|
||||
case 'replaygain_track_gain':
|
||||
$info['replay_gain']['track']['adjustment'] = (double) $commentvalue[0];
|
||||
unset($info['ogg']['comments'][$index]);
|
||||
break;
|
||||
|
||||
case 'replaygain_album_peak':
|
||||
$info['replay_gain']['album']['peak'] = (double) $commentvalue[0];
|
||||
unset($info['ogg']['comments'][$index]);
|
||||
break;
|
||||
|
||||
case 'rg_peak':
|
||||
case 'replaygain_track_peak':
|
||||
$info['replay_gain']['track']['peak'] = (double) $commentvalue[0];
|
||||
unset($info['ogg']['comments'][$index]);
|
||||
break;
|
||||
|
||||
case 'replaygain_reference_loudness':
|
||||
$info['replay_gain']['reference_volume'] = (double) $commentvalue[0];
|
||||
unset($info['ogg']['comments'][$index]);
|
||||
break;
|
||||
|
||||
default:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fseek($this->getid3->fp, $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,429 +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.optimfrog.php //
|
||||
// module for analyzing OptimFROG audio files //
|
||||
// dependencies: module.audio.riff.php //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
|
||||
|
||||
class getid3_optimfrog extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'ofr';
|
||||
$info['audio']['dataformat'] = 'ofr';
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
$info['audio']['lossless'] = true;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$OFRheader = fread($this->getid3->fp, 8);
|
||||
if (substr($OFRheader, 0, 5) == '*RIFF') {
|
||||
|
||||
return $this->ParseOptimFROGheader42();
|
||||
|
||||
} elseif (substr($OFRheader, 0, 3) == 'OFR') {
|
||||
|
||||
return $this->ParseOptimFROGheader45();
|
||||
|
||||
}
|
||||
|
||||
$info['error'][] = 'Expecting "*RIFF" or "OFR " at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($OFRheader).'"';
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function ParseOptimFROGheader42() {
|
||||
// for fileformat of v4.21 and older
|
||||
|
||||
$info = &$this->getid3->info;
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$OptimFROGheaderData = fread($this->getid3->fp, 45);
|
||||
$info['avdataoffset'] = 45;
|
||||
|
||||
$OptimFROGencoderVersion_raw = getid3_lib::LittleEndian2Int(substr($OptimFROGheaderData, 0, 1));
|
||||
$OptimFROGencoderVersion_major = floor($OptimFROGencoderVersion_raw / 10);
|
||||
$OptimFROGencoderVersion_minor = $OptimFROGencoderVersion_raw - ($OptimFROGencoderVersion_major * 10);
|
||||
$RIFFdata = substr($OptimFROGheaderData, 1, 44);
|
||||
$OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8;
|
||||
$OrignalRIFFdataSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44;
|
||||
|
||||
if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
|
||||
$info['avdataend'] -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
|
||||
fseek($this->getid3->fp, $info['avdataend'], SEEK_SET);
|
||||
$RIFFdata .= fread($this->getid3->fp, $OrignalRIFFheaderSize - $OrignalRIFFdataSize);
|
||||
}
|
||||
|
||||
// move the data chunk after all other chunks (if any)
|
||||
// so that the RIFF parser doesn't see EOF when trying
|
||||
// to skip over the data chunk
|
||||
$RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8);
|
||||
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
|
||||
$getid3_temp->info['avdataend'] = $info['avdataend'];
|
||||
$getid3_riff = new getid3_riff($getid3_temp);
|
||||
$getid3_riff->ParseRIFFdata($RIFFdata);
|
||||
$info['riff'] = $getid3_temp->info['riff'];
|
||||
|
||||
$info['audio']['encoder'] = 'OptimFROG '.$OptimFROGencoderVersion_major.'.'.$OptimFROGencoderVersion_minor;
|
||||
$info['audio']['channels'] = $info['riff']['audio'][0]['channels'];
|
||||
$info['audio']['sample_rate'] = $info['riff']['audio'][0]['sample_rate'];
|
||||
$info['audio']['bits_per_sample'] = $info['riff']['audio'][0]['bits_per_sample'];
|
||||
$info['playtime_seconds'] = $OrignalRIFFdataSize / ($info['audio']['channels'] * $info['audio']['sample_rate'] * ($info['audio']['bits_per_sample'] / 8));
|
||||
$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
|
||||
unset($getid3_riff, $getid3_temp, $RIFFdata);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function ParseOptimFROGheader45() {
|
||||
// for fileformat of v4.50a and higher
|
||||
|
||||
$info = &$this->getid3->info;
|
||||
$RIFFdata = '';
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
while (!feof($this->getid3->fp) && (ftell($this->getid3->fp) < $info['avdataend'])) {
|
||||
$BlockOffset = ftell($this->getid3->fp);
|
||||
$BlockData = fread($this->getid3->fp, 8);
|
||||
$offset = 8;
|
||||
$BlockName = substr($BlockData, 0, 4);
|
||||
$BlockSize = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 4));
|
||||
|
||||
if ($BlockName == 'OFRX') {
|
||||
$BlockName = 'OFR ';
|
||||
}
|
||||
if (!isset($info['ofr'][$BlockName])) {
|
||||
$info['ofr'][$BlockName] = array();
|
||||
}
|
||||
$thisfile_ofr_thisblock = &$info['ofr'][$BlockName];
|
||||
|
||||
switch ($BlockName) {
|
||||
case 'OFR ':
|
||||
|
||||
// shortcut
|
||||
$thisfile_ofr_thisblock['offset'] = $BlockOffset;
|
||||
$thisfile_ofr_thisblock['size'] = $BlockSize;
|
||||
|
||||
$info['audio']['encoder'] = 'OptimFROG 4.50 alpha';
|
||||
switch ($BlockSize) {
|
||||
case 12:
|
||||
case 15:
|
||||
// good
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = '"'.$BlockName.'" contains more data than expected (expected 12 or 15 bytes, found '.$BlockSize.' bytes)';
|
||||
break;
|
||||
}
|
||||
$BlockData .= fread($this->getid3->fp, $BlockSize);
|
||||
|
||||
$thisfile_ofr_thisblock['total_samples'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 6));
|
||||
$offset += 6;
|
||||
$thisfile_ofr_thisblock['raw']['sample_type'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1));
|
||||
$thisfile_ofr_thisblock['sample_type'] = $this->OptimFROGsampleTypeLookup($thisfile_ofr_thisblock['raw']['sample_type']);
|
||||
$offset += 1;
|
||||
$thisfile_ofr_thisblock['channel_config'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1));
|
||||
$thisfile_ofr_thisblock['channels'] = $thisfile_ofr_thisblock['channel_config'];
|
||||
$offset += 1;
|
||||
$thisfile_ofr_thisblock['sample_rate'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
if ($BlockSize > 12) {
|
||||
|
||||
// OFR 4.504b or higher
|
||||
$thisfile_ofr_thisblock['channels'] = $this->OptimFROGchannelConfigNumChannelsLookup($thisfile_ofr_thisblock['channel_config']);
|
||||
$thisfile_ofr_thisblock['raw']['encoder_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 2));
|
||||
$thisfile_ofr_thisblock['encoder'] = $this->OptimFROGencoderNameLookup($thisfile_ofr_thisblock['raw']['encoder_id']);
|
||||
$offset += 2;
|
||||
$thisfile_ofr_thisblock['raw']['compression'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1));
|
||||
$thisfile_ofr_thisblock['compression'] = $this->OptimFROGcompressionLookup($thisfile_ofr_thisblock['raw']['compression']);
|
||||
$thisfile_ofr_thisblock['speedup'] = $this->OptimFROGspeedupLookup($thisfile_ofr_thisblock['raw']['compression']);
|
||||
$offset += 1;
|
||||
|
||||
$info['audio']['encoder'] = 'OptimFROG '.$thisfile_ofr_thisblock['encoder'];
|
||||
$info['audio']['encoder_options'] = '--mode '.$thisfile_ofr_thisblock['compression'];
|
||||
|
||||
if ((($thisfile_ofr_thisblock['raw']['encoder_id'] & 0xF0) >> 4) == 7) { // v4.507
|
||||
if (strtolower(getid3_lib::fileextension($info['filename'])) == 'ofs') {
|
||||
// OptimFROG DualStream format is lossy, but as of v4.507 there is no way to tell the difference
|
||||
// between lossless and lossy other than the file extension.
|
||||
$info['audio']['dataformat'] = 'ofs';
|
||||
$info['audio']['lossless'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$info['audio']['channels'] = $thisfile_ofr_thisblock['channels'];
|
||||
$info['audio']['sample_rate'] = $thisfile_ofr_thisblock['sample_rate'];
|
||||
$info['audio']['bits_per_sample'] = $this->OptimFROGbitsPerSampleTypeLookup($thisfile_ofr_thisblock['raw']['sample_type']);
|
||||
break;
|
||||
|
||||
|
||||
case 'COMP':
|
||||
// unlike other block types, there CAN be multiple COMP blocks
|
||||
|
||||
$COMPdata['offset'] = $BlockOffset;
|
||||
$COMPdata['size'] = $BlockSize;
|
||||
|
||||
if ($info['avdataoffset'] == 0) {
|
||||
$info['avdataoffset'] = $BlockOffset;
|
||||
}
|
||||
|
||||
// Only interested in first 14 bytes (only first 12 needed for v4.50 alpha), not actual audio data
|
||||
$BlockData .= fread($this->getid3->fp, 14);
|
||||
fseek($this->getid3->fp, $BlockSize - 14, SEEK_CUR);
|
||||
|
||||
$COMPdata['crc_32'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 4));
|
||||
$offset += 4;
|
||||
$COMPdata['sample_count'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 4));
|
||||
$offset += 4;
|
||||
$COMPdata['raw']['sample_type'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1));
|
||||
$COMPdata['sample_type'] = $this->OptimFROGsampleTypeLookup($COMPdata['raw']['sample_type']);
|
||||
$offset += 1;
|
||||
$COMPdata['raw']['channel_configuration'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1));
|
||||
$COMPdata['channel_configuration'] = $this->OptimFROGchannelConfigurationLookup($COMPdata['raw']['channel_configuration']);
|
||||
$offset += 1;
|
||||
$COMPdata['raw']['algorithm_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 2));
|
||||
//$COMPdata['algorithm'] = OptimFROGalgorithmNameLookup($COMPdata['raw']['algorithm_id']);
|
||||
$offset += 2;
|
||||
|
||||
if ($info['ofr']['OFR ']['size'] > 12) {
|
||||
|
||||
// OFR 4.504b or higher
|
||||
$COMPdata['raw']['encoder_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 2));
|
||||
$COMPdata['encoder'] = $this->OptimFROGencoderNameLookup($COMPdata['raw']['encoder_id']);
|
||||
$offset += 2;
|
||||
|
||||
}
|
||||
|
||||
if ($COMPdata['crc_32'] == 0x454E4F4E) {
|
||||
// ASCII value of 'NONE' - placeholder value in v4.50a
|
||||
$COMPdata['crc_32'] = false;
|
||||
}
|
||||
|
||||
$thisfile_ofr_thisblock[] = $COMPdata;
|
||||
break;
|
||||
|
||||
case 'HEAD':
|
||||
$thisfile_ofr_thisblock['offset'] = $BlockOffset;
|
||||
$thisfile_ofr_thisblock['size'] = $BlockSize;
|
||||
|
||||
$RIFFdata .= fread($this->getid3->fp, $BlockSize);
|
||||
break;
|
||||
|
||||
case 'TAIL':
|
||||
$thisfile_ofr_thisblock['offset'] = $BlockOffset;
|
||||
$thisfile_ofr_thisblock['size'] = $BlockSize;
|
||||
|
||||
if ($BlockSize > 0) {
|
||||
$RIFFdata .= fread($this->getid3->fp, $BlockSize);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'RECV':
|
||||
// block contains no useful meta data - simply note and skip
|
||||
|
||||
$thisfile_ofr_thisblock['offset'] = $BlockOffset;
|
||||
$thisfile_ofr_thisblock['size'] = $BlockSize;
|
||||
|
||||
fseek($this->getid3->fp, $BlockSize, SEEK_CUR);
|
||||
break;
|
||||
|
||||
|
||||
case 'APET':
|
||||
// APEtag v2
|
||||
|
||||
$thisfile_ofr_thisblock['offset'] = $BlockOffset;
|
||||
$thisfile_ofr_thisblock['size'] = $BlockSize;
|
||||
$info['warning'][] = 'APEtag processing inside OptimFROG not supported in this version ('.$this->getid3->version().') of getID3()';
|
||||
|
||||
fseek($this->getid3->fp, $BlockSize, SEEK_CUR);
|
||||
break;
|
||||
|
||||
|
||||
case 'MD5 ':
|
||||
// APEtag v2
|
||||
|
||||
$thisfile_ofr_thisblock['offset'] = $BlockOffset;
|
||||
$thisfile_ofr_thisblock['size'] = $BlockSize;
|
||||
|
||||
if ($BlockSize == 16) {
|
||||
|
||||
$thisfile_ofr_thisblock['md5_binary'] = fread($this->getid3->fp, $BlockSize);
|
||||
$thisfile_ofr_thisblock['md5_string'] = getid3_lib::PrintHexBytes($thisfile_ofr_thisblock['md5_binary'], true, false, false);
|
||||
$info['md5_data_source'] = $thisfile_ofr_thisblock['md5_string'];
|
||||
|
||||
} else {
|
||||
|
||||
$info['warning'][] = 'Expecting block size of 16 in "MD5 " chunk, found '.$BlockSize.' instead';
|
||||
fseek($this->getid3->fp, $BlockSize, SEEK_CUR);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
$thisfile_ofr_thisblock['offset'] = $BlockOffset;
|
||||
$thisfile_ofr_thisblock['size'] = $BlockSize;
|
||||
|
||||
$info['warning'][] = 'Unhandled OptimFROG block type "'.$BlockName.'" at offset '.$thisfile_ofr_thisblock['offset'];
|
||||
fseek($this->getid3->fp, $BlockSize, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isset($info['ofr']['TAIL']['offset'])) {
|
||||
$info['avdataend'] = $info['ofr']['TAIL']['offset'];
|
||||
}
|
||||
|
||||
$info['playtime_seconds'] = (float) $info['ofr']['OFR ']['total_samples'] / ($info['audio']['channels'] * $info['audio']['sample_rate']);
|
||||
$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
|
||||
// move the data chunk after all other chunks (if any)
|
||||
// so that the RIFF parser doesn't see EOF when trying
|
||||
// to skip over the data chunk
|
||||
$RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8);
|
||||
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
|
||||
$getid3_temp->info['avdataend'] = $info['avdataend'];
|
||||
$getid3_riff = new getid3_riff($getid3_temp);
|
||||
$getid3_riff->ParseRIFFdata($RIFFdata);
|
||||
$info['riff'] = $getid3_temp->info['riff'];
|
||||
|
||||
unset($getid3_riff, $getid3_temp, $RIFFdata);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static function OptimFROGsampleTypeLookup($SampleType) {
|
||||
static $OptimFROGsampleTypeLookup = array(
|
||||
0 => 'unsigned int (8-bit)',
|
||||
1 => 'signed int (8-bit)',
|
||||
2 => 'unsigned int (16-bit)',
|
||||
3 => 'signed int (16-bit)',
|
||||
4 => 'unsigned int (24-bit)',
|
||||
5 => 'signed int (24-bit)',
|
||||
6 => 'unsigned int (32-bit)',
|
||||
7 => 'signed int (32-bit)',
|
||||
8 => 'float 0.24 (32-bit)',
|
||||
9 => 'float 16.8 (32-bit)',
|
||||
10 => 'float 24.0 (32-bit)'
|
||||
);
|
||||
return (isset($OptimFROGsampleTypeLookup[$SampleType]) ? $OptimFROGsampleTypeLookup[$SampleType] : false);
|
||||
}
|
||||
|
||||
static function OptimFROGbitsPerSampleTypeLookup($SampleType) {
|
||||
static $OptimFROGbitsPerSampleTypeLookup = array(
|
||||
0 => 8,
|
||||
1 => 8,
|
||||
2 => 16,
|
||||
3 => 16,
|
||||
4 => 24,
|
||||
5 => 24,
|
||||
6 => 32,
|
||||
7 => 32,
|
||||
8 => 32,
|
||||
9 => 32,
|
||||
10 => 32
|
||||
);
|
||||
return (isset($OptimFROGbitsPerSampleTypeLookup[$SampleType]) ? $OptimFROGbitsPerSampleTypeLookup[$SampleType] : false);
|
||||
}
|
||||
|
||||
static function OptimFROGchannelConfigurationLookup($ChannelConfiguration) {
|
||||
static $OptimFROGchannelConfigurationLookup = array(
|
||||
0 => 'mono',
|
||||
1 => 'stereo'
|
||||
);
|
||||
return (isset($OptimFROGchannelConfigurationLookup[$ChannelConfiguration]) ? $OptimFROGchannelConfigurationLookup[$ChannelConfiguration] : false);
|
||||
}
|
||||
|
||||
static function OptimFROGchannelConfigNumChannelsLookup($ChannelConfiguration) {
|
||||
static $OptimFROGchannelConfigNumChannelsLookup = array(
|
||||
0 => 1,
|
||||
1 => 2
|
||||
);
|
||||
return (isset($OptimFROGchannelConfigNumChannelsLookup[$ChannelConfiguration]) ? $OptimFROGchannelConfigNumChannelsLookup[$ChannelConfiguration] : false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// static function OptimFROGalgorithmNameLookup($AlgorithID) {
|
||||
// static $OptimFROGalgorithmNameLookup = array();
|
||||
// return (isset($OptimFROGalgorithmNameLookup[$AlgorithID]) ? $OptimFROGalgorithmNameLookup[$AlgorithID] : false);
|
||||
// }
|
||||
|
||||
|
||||
static function OptimFROGencoderNameLookup($EncoderID) {
|
||||
// version = (encoderID >> 4) + 4500
|
||||
// system = encoderID & 0xF
|
||||
|
||||
$EncoderVersion = number_format(((($EncoderID & 0xF0) >> 4) + 4500) / 1000, 3);
|
||||
$EncoderSystemID = ($EncoderID & 0x0F);
|
||||
|
||||
static $OptimFROGencoderSystemLookup = array(
|
||||
0x00 => 'Windows console',
|
||||
0x01 => 'Linux console',
|
||||
0x0F => 'unknown'
|
||||
);
|
||||
return $EncoderVersion.' ('.(isset($OptimFROGencoderSystemLookup[$EncoderSystemID]) ? $OptimFROGencoderSystemLookup[$EncoderSystemID] : 'undefined encoder type (0x'.dechex($EncoderSystemID).')').')';
|
||||
}
|
||||
|
||||
static function OptimFROGcompressionLookup($CompressionID) {
|
||||
// mode = compression >> 3
|
||||
// speedup = compression & 0x07
|
||||
|
||||
$CompressionModeID = ($CompressionID & 0xF8) >> 3;
|
||||
//$CompressionSpeedupID = ($CompressionID & 0x07);
|
||||
|
||||
static $OptimFROGencoderModeLookup = array(
|
||||
0x00 => 'fast',
|
||||
0x01 => 'normal',
|
||||
0x02 => 'high',
|
||||
0x03 => 'extra', // extranew (some versions)
|
||||
0x04 => 'best', // bestnew (some versions)
|
||||
0x05 => 'ultra',
|
||||
0x06 => 'insane',
|
||||
0x07 => 'highnew',
|
||||
0x08 => 'extranew',
|
||||
0x09 => 'bestnew'
|
||||
);
|
||||
return (isset($OptimFROGencoderModeLookup[$CompressionModeID]) ? $OptimFROGencoderModeLookup[$CompressionModeID] : 'undefined mode (0x'.str_pad(dechex($CompressionModeID), 2, '0', STR_PAD_LEFT).')');
|
||||
}
|
||||
|
||||
static function OptimFROGspeedupLookup($CompressionID) {
|
||||
// mode = compression >> 3
|
||||
// speedup = compression & 0x07
|
||||
|
||||
//$CompressionModeID = ($CompressionID & 0xF8) >> 3;
|
||||
$CompressionSpeedupID = ($CompressionID & 0x07);
|
||||
|
||||
static $OptimFROGencoderSpeedupLookup = array(
|
||||
0x00 => '1x',
|
||||
0x01 => '2x',
|
||||
0x02 => '4x'
|
||||
);
|
||||
return (isset($OptimFROGencoderSpeedupLookup[$CompressionSpeedupID]) ? $OptimFROGencoderSpeedupLookup[$CompressionSpeedupID] : 'undefined mode (0x'.dechex($CompressionSpeedupID));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,94 +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 extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$RKAUHeader = fread($this->getid3->fp, 20);
|
||||
$magic = 'RKA';
|
||||
if (substr($RKAUHeader, 0, 3) != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($RKAUHeader, 0, 3)).'"';
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['fileformat'] = 'rkau';
|
||||
$info['audio']['dataformat'] = 'rkau';
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
|
||||
$info['rkau']['raw']['version'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 3, 1));
|
||||
$info['rkau']['version'] = '1.'.str_pad($info['rkau']['raw']['version'] & 0x0F, 2, '0', STR_PAD_LEFT);
|
||||
if (($info['rkau']['version'] > 1.07) || ($info['rkau']['version'] < 1.06)) {
|
||||
$info['error'][] = 'This version of getID3() ['.$this->getid3->version().'] can only parse RKAU files v1.06 and 1.07 (this file is v'.$info['rkau']['version'].')';
|
||||
unset($info['rkau']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['rkau']['source_bytes'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 4, 4));
|
||||
$info['rkau']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 8, 4));
|
||||
$info['rkau']['channels'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 12, 1));
|
||||
$info['rkau']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 13, 1));
|
||||
|
||||
$info['rkau']['raw']['quality'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 14, 1));
|
||||
$this->RKAUqualityLookup($info['rkau']);
|
||||
|
||||
$info['rkau']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 15, 1));
|
||||
$info['rkau']['flags']['joint_stereo'] = (bool) (!($info['rkau']['raw']['flags'] & 0x01));
|
||||
$info['rkau']['flags']['streaming'] = (bool) ($info['rkau']['raw']['flags'] & 0x02);
|
||||
$info['rkau']['flags']['vrq_lossy_mode'] = (bool) ($info['rkau']['raw']['flags'] & 0x04);
|
||||
|
||||
if ($info['rkau']['flags']['streaming']) {
|
||||
$info['avdataoffset'] += 20;
|
||||
$info['rkau']['compressed_bytes'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 16, 4));
|
||||
} else {
|
||||
$info['avdataoffset'] += 16;
|
||||
$info['rkau']['compressed_bytes'] = $info['avdataend'] - $info['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(?)
|
||||
|
||||
$info['audio']['lossless'] = $info['rkau']['lossless'];
|
||||
$info['audio']['channels'] = $info['rkau']['channels'];
|
||||
$info['audio']['bits_per_sample'] = $info['rkau']['bits_per_sample'];
|
||||
$info['audio']['sample_rate'] = $info['rkau']['sample_rate'];
|
||||
|
||||
$info['playtime_seconds'] = $info['rkau']['source_bytes'] / ($info['rkau']['sample_rate'] * $info['rkau']['channels'] * ($info['rkau']['bits_per_sample'] / 8));
|
||||
$info['audio']['bitrate'] = ($info['rkau']['compressed_bytes'] * 8) / $info['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,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.audio.shorten.php //
|
||||
// module for analyzing Shorten Audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_shorten extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
|
||||
$ShortenHeader = fread($this->getid3->fp, 8);
|
||||
$magic = 'ajkg';
|
||||
if (substr($ShortenHeader, 0, 4) != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($ShortenHeader, 0, 4)).'"';
|
||||
return false;
|
||||
}
|
||||
$info['fileformat'] = 'shn';
|
||||
$info['audio']['dataformat'] = 'shn';
|
||||
$info['audio']['lossless'] = true;
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
|
||||
$info['shn']['version'] = getid3_lib::LittleEndian2Int(substr($ShortenHeader, 4, 1));
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataend'] - 12, SEEK_SET);
|
||||
$SeekTableSignatureTest = fread($this->getid3->fp, 12);
|
||||
$info['shn']['seektable']['present'] = (bool) (substr($SeekTableSignatureTest, 4, 8) == 'SHNAMPSK');
|
||||
if ($info['shn']['seektable']['present']) {
|
||||
$info['shn']['seektable']['length'] = getid3_lib::LittleEndian2Int(substr($SeekTableSignatureTest, 0, 4));
|
||||
$info['shn']['seektable']['offset'] = $info['avdataend'] - $info['shn']['seektable']['length'];
|
||||
fseek($this->getid3->fp, $info['shn']['seektable']['offset'], SEEK_SET);
|
||||
$SeekTableMagic = fread($this->getid3->fp, 4);
|
||||
$magic = 'SEEK';
|
||||
if ($SeekTableMagic != $magic) {
|
||||
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['shn']['seektable']['offset'].', found "'.getid3_lib::PrintHexBytes($SeekTableMagic).'"';
|
||||
return false;
|
||||
|
||||
} else {
|
||||
|
||||
// typedef struct tag_TSeekEntry
|
||||
// {
|
||||
// unsigned long SampleNumber;
|
||||
// unsigned long SHNFileByteOffset;
|
||||
// unsigned long SHNLastBufferReadPosition;
|
||||
// unsigned short SHNByteGet;
|
||||
// unsigned short SHNBufferOffset;
|
||||
// unsigned short SHNFileBitOffset;
|
||||
// unsigned long SHNGBuffer;
|
||||
// unsigned short SHNBitShift;
|
||||
// long CBuf0[3];
|
||||
// long CBuf1[3];
|
||||
// long Offset0[4];
|
||||
// long Offset1[4];
|
||||
// }TSeekEntry;
|
||||
|
||||
$SeekTableData = fread($this->getid3->fp, $info['shn']['seektable']['length'] - 16);
|
||||
$info['shn']['seektable']['entry_count'] = floor(strlen($SeekTableData) / 80);
|
||||
//$info['shn']['seektable']['entries'] = array();
|
||||
//$SeekTableOffset = 0;
|
||||
//for ($i = 0; $i < $info['shn']['seektable']['entry_count']; $i++) {
|
||||
// $SeekTableEntry['sample_number'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
|
||||
// $SeekTableOffset += 4;
|
||||
// $SeekTableEntry['shn_file_byte_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
|
||||
// $SeekTableOffset += 4;
|
||||
// $SeekTableEntry['shn_last_buffer_read_position'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
|
||||
// $SeekTableOffset += 4;
|
||||
// $SeekTableEntry['shn_byte_get'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
|
||||
// $SeekTableOffset += 2;
|
||||
// $SeekTableEntry['shn_buffer_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
|
||||
// $SeekTableOffset += 2;
|
||||
// $SeekTableEntry['shn_file_bit_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
|
||||
// $SeekTableOffset += 2;
|
||||
// $SeekTableEntry['shn_gbuffer'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
|
||||
// $SeekTableOffset += 4;
|
||||
// $SeekTableEntry['shn_bit_shift'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
|
||||
// $SeekTableOffset += 2;
|
||||
// for ($j = 0; $j < 3; $j++) {
|
||||
// $SeekTableEntry['cbuf0'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
|
||||
// $SeekTableOffset += 4;
|
||||
// }
|
||||
// for ($j = 0; $j < 3; $j++) {
|
||||
// $SeekTableEntry['cbuf1'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
|
||||
// $SeekTableOffset += 4;
|
||||
// }
|
||||
// for ($j = 0; $j < 4; $j++) {
|
||||
// $SeekTableEntry['offset0'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
|
||||
// $SeekTableOffset += 4;
|
||||
// }
|
||||
// for ($j = 0; $j < 4; $j++) {
|
||||
// $SeekTableEntry['offset1'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
|
||||
// $SeekTableOffset += 4;
|
||||
// }
|
||||
//
|
||||
// $info['shn']['seektable']['entries'][] = $SeekTableEntry;
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
|
||||
$info['error'][] = 'PHP running in Safe Mode - backtick operator not available, cannot run shntool to analyze Shorten files';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GETID3_OS_ISWINDOWS) {
|
||||
|
||||
$RequiredFiles = array('shorten.exe', 'cygwin1.dll', 'head.exe');
|
||||
foreach ($RequiredFiles as $required_file) {
|
||||
if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) {
|
||||
$info['error'][] = GETID3_HELPERAPPSDIR.$required_file.' does not exist';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$commandline = GETID3_HELPERAPPSDIR.'shorten.exe -x "'.$info['filenamepath'].'" - | '.GETID3_HELPERAPPSDIR.'head.exe -c 64';
|
||||
$commandline = str_replace('/', '\\', $commandline);
|
||||
|
||||
} else {
|
||||
|
||||
static $shorten_present;
|
||||
if (!isset($shorten_present)) {
|
||||
$shorten_present = file_exists('/usr/local/bin/shorten') || `which shorten`;
|
||||
}
|
||||
if (!$shorten_present) {
|
||||
$info['error'][] = 'shorten binary was not found in path or /usr/local/bin';
|
||||
return false;
|
||||
}
|
||||
$commandline = (file_exists('/usr/local/bin/shorten') ? '/usr/local/bin/' : '' ) . 'shorten -x '.escapeshellarg($info['filenamepath']).' - | head -c 64';
|
||||
|
||||
}
|
||||
|
||||
$output = `$commandline`;
|
||||
|
||||
if (!empty($output) && (substr($output, 12, 4) == 'fmt ')) {
|
||||
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
|
||||
|
||||
$fmt_size = getid3_lib::LittleEndian2Int(substr($output, 16, 4));
|
||||
$DecodedWAVFORMATEX = getid3_riff::RIFFparseWAVEFORMATex(substr($output, 20, $fmt_size));
|
||||
$info['audio']['channels'] = $DecodedWAVFORMATEX['channels'];
|
||||
$info['audio']['bits_per_sample'] = $DecodedWAVFORMATEX['bits_per_sample'];
|
||||
$info['audio']['sample_rate'] = $DecodedWAVFORMATEX['sample_rate'];
|
||||
|
||||
if (substr($output, 20 + $fmt_size, 4) == 'data') {
|
||||
|
||||
$info['playtime_seconds'] = getid3_lib::LittleEndian2Int(substr($output, 20 + 4 + $fmt_size, 4)) / $DecodedWAVFORMATEX['raw']['nAvgBytesPerSec'];
|
||||
|
||||
} else {
|
||||
|
||||
$info['error'][] = 'shorten failed to decode DATA chunk to expected location, cannot determine playtime';
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8;
|
||||
|
||||
} else {
|
||||
|
||||
$info['error'][] = 'shorten failed to decode file to WAV for parsing';
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,109 +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 extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'tta';
|
||||
$info['audio']['dataformat'] = 'tta';
|
||||
$info['audio']['lossless'] = true;
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$ttaheader = fread($this->getid3->fp, 26);
|
||||
|
||||
$info['tta']['magic'] = substr($ttaheader, 0, 3);
|
||||
$magic = 'TTA';
|
||||
if ($info['tta']['magic'] != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['tta']['magic']).'"';
|
||||
unset($info['fileformat']);
|
||||
unset($info['audio']);
|
||||
unset($info['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."
|
||||
$info['tta']['major_version'] = 1;
|
||||
$info['avdataoffset'] += 16;
|
||||
|
||||
$info['tta']['compression_level'] = ord($ttaheader{3});
|
||||
$info['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2));
|
||||
$info['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2));
|
||||
$info['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 4));
|
||||
$info['tta']['samples_per_channel'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 12, 4));
|
||||
|
||||
$info['audio']['encoder_options'] = '-e'.$info['tta']['compression_level'];
|
||||
$info['playtime_seconds'] = $info['tta']['samples_per_channel'] / $info['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."
|
||||
$info['tta']['major_version'] = 2;
|
||||
$info['avdataoffset'] += 20;
|
||||
|
||||
$info['tta']['compression_level'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2));
|
||||
$info['tta']['audio_format'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2));
|
||||
$info['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 2));
|
||||
$info['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 10, 2));
|
||||
$info['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 12, 4));
|
||||
$info['tta']['data_length'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 16, 4));
|
||||
|
||||
$info['audio']['encoder_options'] = '-e'.$info['tta']['compression_level'];
|
||||
$info['playtime_seconds'] = $info['tta']['data_length'] / $info['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."
|
||||
$info['tta']['major_version'] = 3;
|
||||
$info['avdataoffset'] += 26;
|
||||
|
||||
$info['tta']['audio_format'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2)); // getid3_riff::RIFFwFormatTagLookup()
|
||||
$info['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2));
|
||||
$info['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 2));
|
||||
$info['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 10, 4));
|
||||
$info['tta']['data_length'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 14, 4));
|
||||
$info['tta']['crc32_footer'] = substr($ttaheader, 18, 4);
|
||||
$info['tta']['seek_point'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 22, 4));
|
||||
|
||||
$info['playtime_seconds'] = $info['tta']['data_length'] / $info['tta']['sample_rate'];
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'This version of getID3() ['.$this->getid3->version().'] 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;
|
||||
}
|
||||
|
||||
$info['audio']['encoder'] = 'TTA v'.$info['tta']['major_version'];
|
||||
$info['audio']['bits_per_sample'] = $info['tta']['bits_per_sample'];
|
||||
$info['audio']['sample_rate'] = $info['tta']['sample_rate'];
|
||||
$info['audio']['channels'] = $info['tta']['channels'];
|
||||
$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,207 +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.voc.php //
|
||||
// module for analyzing Creative VOC Audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_voc extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$OriginalAVdataOffset = $info['avdataoffset'];
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$VOCheader = fread($this->getid3->fp, 26);
|
||||
|
||||
$magic = 'Creative Voice File';
|
||||
if (substr($VOCheader, 0, 19) != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($VOCheader, 0, 19)).'"';
|
||||
return false;
|
||||
}
|
||||
|
||||
// shortcuts
|
||||
$thisfile_audio = &$info['audio'];
|
||||
$info['voc'] = array();
|
||||
$thisfile_voc = &$info['voc'];
|
||||
|
||||
$info['fileformat'] = 'voc';
|
||||
$thisfile_audio['dataformat'] = 'voc';
|
||||
$thisfile_audio['bitrate_mode'] = 'cbr';
|
||||
$thisfile_audio['lossless'] = true;
|
||||
$thisfile_audio['channels'] = 1; // might be overriden below
|
||||
$thisfile_audio['bits_per_sample'] = 8; // might be overriden below
|
||||
|
||||
// byte # Description
|
||||
// ------ ------------------------------------------
|
||||
// 00-12 'Creative Voice File'
|
||||
// 13 1A (eof to abort printing of file)
|
||||
// 14-15 Offset of first datablock in .voc file (std 1A 00 in Intel Notation)
|
||||
// 16-17 Version number (minor,major) (VOC-HDR puts 0A 01)
|
||||
// 18-19 2's Comp of Ver. # + 1234h (VOC-HDR puts 29 11)
|
||||
|
||||
$thisfile_voc['header']['datablock_offset'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 20, 2));
|
||||
$thisfile_voc['header']['minor_version'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 22, 1));
|
||||
$thisfile_voc['header']['major_version'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 23, 1));
|
||||
|
||||
do {
|
||||
|
||||
$BlockOffset = ftell($this->getid3->fp);
|
||||
$BlockData = fread($this->getid3->fp, 4);
|
||||
$BlockType = ord($BlockData{0});
|
||||
$BlockSize = getid3_lib::LittleEndian2Int(substr($BlockData, 1, 3));
|
||||
$ThisBlock = array();
|
||||
|
||||
getid3_lib::safe_inc($thisfile_voc['blocktypes'][$BlockType], 1);
|
||||
switch ($BlockType) {
|
||||
case 0: // Terminator
|
||||
// do nothing, we'll break out of the loop down below
|
||||
break;
|
||||
|
||||
case 1: // Sound data
|
||||
$BlockData .= fread($this->getid3->fp, 2);
|
||||
if ($info['avdataoffset'] <= $OriginalAVdataOffset) {
|
||||
$info['avdataoffset'] = ftell($this->getid3->fp);
|
||||
}
|
||||
fseek($this->getid3->fp, $BlockSize - 2, SEEK_CUR);
|
||||
|
||||
$ThisBlock['sample_rate_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 1));
|
||||
$ThisBlock['compression_type'] = getid3_lib::LittleEndian2Int(substr($BlockData, 5, 1));
|
||||
|
||||
$ThisBlock['compression_name'] = $this->VOCcompressionTypeLookup($ThisBlock['compression_type']);
|
||||
if ($ThisBlock['compression_type'] <= 3) {
|
||||
$thisfile_voc['compressed_bits_per_sample'] = getid3_lib::CastAsInt(str_replace('-bit', '', $ThisBlock['compression_name']));
|
||||
}
|
||||
|
||||
// Less accurate sample_rate calculation than the Extended block (#8) data (but better than nothing if Extended Block is not available)
|
||||
if (empty($thisfile_audio['sample_rate'])) {
|
||||
// SR byte = 256 - (1000000 / sample_rate)
|
||||
$thisfile_audio['sample_rate'] = getid3_lib::trunc((1000000 / (256 - $ThisBlock['sample_rate_id'])) / $thisfile_audio['channels']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // Sound continue
|
||||
case 3: // Silence
|
||||
case 4: // Marker
|
||||
case 6: // Repeat
|
||||
case 7: // End repeat
|
||||
// nothing useful, just skip
|
||||
fseek($this->getid3->fp, $BlockSize, SEEK_CUR);
|
||||
break;
|
||||
|
||||
case 8: // Extended
|
||||
$BlockData .= fread($this->getid3->fp, 4);
|
||||
|
||||
//00-01 Time Constant:
|
||||
// Mono: 65536 - (256000000 / sample_rate)
|
||||
// Stereo: 65536 - (256000000 / (sample_rate * 2))
|
||||
$ThisBlock['time_constant'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 2));
|
||||
$ThisBlock['pack_method'] = getid3_lib::LittleEndian2Int(substr($BlockData, 6, 1));
|
||||
$ThisBlock['stereo'] = (bool) getid3_lib::LittleEndian2Int(substr($BlockData, 7, 1));
|
||||
|
||||
$thisfile_audio['channels'] = ($ThisBlock['stereo'] ? 2 : 1);
|
||||
$thisfile_audio['sample_rate'] = getid3_lib::trunc((256000000 / (65536 - $ThisBlock['time_constant'])) / $thisfile_audio['channels']);
|
||||
break;
|
||||
|
||||
case 9: // data block that supersedes blocks 1 and 8. Used for stereo, 16 bit
|
||||
$BlockData .= fread($this->getid3->fp, 12);
|
||||
if ($info['avdataoffset'] <= $OriginalAVdataOffset) {
|
||||
$info['avdataoffset'] = ftell($this->getid3->fp);
|
||||
}
|
||||
fseek($this->getid3->fp, $BlockSize - 12, SEEK_CUR);
|
||||
|
||||
$ThisBlock['sample_rate'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 4));
|
||||
$ThisBlock['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($BlockData, 8, 1));
|
||||
$ThisBlock['channels'] = getid3_lib::LittleEndian2Int(substr($BlockData, 9, 1));
|
||||
$ThisBlock['wFormat'] = getid3_lib::LittleEndian2Int(substr($BlockData, 10, 2));
|
||||
|
||||
$ThisBlock['compression_name'] = $this->VOCwFormatLookup($ThisBlock['wFormat']);
|
||||
if ($this->VOCwFormatActualBitsPerSampleLookup($ThisBlock['wFormat'])) {
|
||||
$thisfile_voc['compressed_bits_per_sample'] = $this->VOCwFormatActualBitsPerSampleLookup($ThisBlock['wFormat']);
|
||||
}
|
||||
|
||||
$thisfile_audio['sample_rate'] = $ThisBlock['sample_rate'];
|
||||
$thisfile_audio['bits_per_sample'] = $ThisBlock['bits_per_sample'];
|
||||
$thisfile_audio['channels'] = $ThisBlock['channels'];
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unhandled block type "'.$BlockType.'" at offset '.$BlockOffset;
|
||||
fseek($this->getid3->fp, $BlockSize, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($ThisBlock)) {
|
||||
$ThisBlock['block_offset'] = $BlockOffset;
|
||||
$ThisBlock['block_size'] = $BlockSize;
|
||||
$ThisBlock['block_type_id'] = $BlockType;
|
||||
$thisfile_voc['blocks'][] = $ThisBlock;
|
||||
}
|
||||
|
||||
} while (!feof($this->getid3->fp) && ($BlockType != 0));
|
||||
|
||||
// Terminator block doesn't have size field, so seek back 3 spaces
|
||||
fseek($this->getid3->fp, -3, SEEK_CUR);
|
||||
|
||||
ksort($thisfile_voc['blocktypes']);
|
||||
|
||||
if (!empty($thisfile_voc['compressed_bits_per_sample'])) {
|
||||
$info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($thisfile_voc['compressed_bits_per_sample'] * $thisfile_audio['channels'] * $thisfile_audio['sample_rate']);
|
||||
$thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function VOCcompressionTypeLookup($index) {
|
||||
static $VOCcompressionTypeLookup = array(
|
||||
0 => '8-bit',
|
||||
1 => '4-bit',
|
||||
2 => '2.6-bit',
|
||||
3 => '2-bit'
|
||||
);
|
||||
return (isset($VOCcompressionTypeLookup[$index]) ? $VOCcompressionTypeLookup[$index] : 'Multi DAC ('.($index - 3).') channels');
|
||||
}
|
||||
|
||||
function VOCwFormatLookup($index) {
|
||||
static $VOCwFormatLookup = array(
|
||||
0x0000 => '8-bit unsigned PCM',
|
||||
0x0001 => 'Creative 8-bit to 4-bit ADPCM',
|
||||
0x0002 => 'Creative 8-bit to 3-bit ADPCM',
|
||||
0x0003 => 'Creative 8-bit to 2-bit ADPCM',
|
||||
0x0004 => '16-bit signed PCM',
|
||||
0x0006 => 'CCITT a-Law',
|
||||
0x0007 => 'CCITT u-Law',
|
||||
0x2000 => 'Creative 16-bit to 4-bit ADPCM'
|
||||
);
|
||||
return (isset($VOCwFormatLookup[$index]) ? $VOCwFormatLookup[$index] : false);
|
||||
}
|
||||
|
||||
function VOCwFormatActualBitsPerSampleLookup($index) {
|
||||
static $VOCwFormatLookup = array(
|
||||
0x0000 => 8,
|
||||
0x0001 => 4,
|
||||
0x0002 => 3,
|
||||
0x0003 => 2,
|
||||
0x0004 => 16,
|
||||
0x0006 => 8,
|
||||
0x0007 => 8,
|
||||
0x2000 => 4
|
||||
);
|
||||
return (isset($VOCwFormatLookup[$index]) ? $VOCwFormatLookup[$index] : false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,162 +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 extends getid3_handler
|
||||
{
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// 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
|
||||
|
||||
$info['fileformat'] = 'vqf';
|
||||
$info['audio']['dataformat'] = 'vqf';
|
||||
$info['audio']['bitrate_mode'] = 'cbr';
|
||||
$info['audio']['lossless'] = false;
|
||||
|
||||
// shortcut
|
||||
$info['vqf']['raw'] = array();
|
||||
$thisfile_vqf = &$info['vqf'];
|
||||
$thisfile_vqf_raw = &$thisfile_vqf['raw'];
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$VQFheaderData = fread($this->getid3->fp, 16);
|
||||
|
||||
$offset = 0;
|
||||
$thisfile_vqf_raw['header_tag'] = substr($VQFheaderData, $offset, 4);
|
||||
$magic = 'TWIN';
|
||||
if ($thisfile_vqf_raw['header_tag'] != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_vqf_raw['header_tag']).'"';
|
||||
unset($info['vqf']);
|
||||
unset($info['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($this->getid3->fp) < $info['avdataend']) {
|
||||
|
||||
$ChunkBaseOffset = ftell($this->getid3->fp);
|
||||
$chunkoffset = 0;
|
||||
$ChunkData = fread($this->getid3->fp, 8);
|
||||
$ChunkName = substr($ChunkData, $chunkoffset, 4);
|
||||
if ($ChunkName == 'DATA') {
|
||||
$info['avdataoffset'] = $ChunkBaseOffset;
|
||||
break;
|
||||
}
|
||||
$chunkoffset += 4;
|
||||
$ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
|
||||
$chunkoffset += 4;
|
||||
if ($ChunkSize > ($info['avdataend'] - ftell($this->getid3->fp))) {
|
||||
$info['error'][] = 'Invalid chunk size ('.$ChunkSize.') for chunk "'.$ChunkName.'" at offset '.$ChunkBaseOffset;
|
||||
break;
|
||||
}
|
||||
if ($ChunkSize > 0) {
|
||||
$ChunkData .= fread($this->getid3->fp, $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;
|
||||
|
||||
$info['audio']['channels'] = $thisfile_vqf_COMM['channel_mode'] + 1;
|
||||
$info['audio']['sample_rate'] = $this->VQFchannelFrequencyLookup($thisfile_vqf_COMM['sample_rate']);
|
||||
$info['audio']['bitrate'] = $thisfile_vqf_COMM['bitrate'] * 1000;
|
||||
$info['audio']['encoder_options'] = 'CBR' . ceil($info['audio']['bitrate']/1000);
|
||||
|
||||
if ($info['audio']['bitrate'] == 0) {
|
||||
$info['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:
|
||||
$info['warning'][] = 'Unhandled chunk type "'.$ChunkName.'" at offset '.$ChunkBaseOffset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate'];
|
||||
|
||||
if (isset($thisfile_vqf['DSIZ']) && (($thisfile_vqf['DSIZ'] != ($info['avdataend'] - $info['avdataoffset'] - strlen('DATA'))))) {
|
||||
switch ($thisfile_vqf['DSIZ']) {
|
||||
case 0:
|
||||
case 1:
|
||||
$info['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';
|
||||
$info['audio']['encoder'] = 'Ahead Nero';
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Probable corrupted file - should be '.$thisfile_vqf['DSIZ'].' bytes, actually '.($info['avdataend'] - $info['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,400 +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 extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
|
||||
while (true) {
|
||||
|
||||
$wavpackheader = fread($this->getid3->fp, 32);
|
||||
|
||||
if (ftell($this->getid3->fp) >= $info['avdataend']) {
|
||||
break;
|
||||
} elseif (feof($this->getid3->fp)) {
|
||||
break;
|
||||
} elseif (
|
||||
isset($info['wavpack']['blockheader']['total_samples']) &&
|
||||
isset($info['wavpack']['blockheader']['block_samples']) &&
|
||||
($info['wavpack']['blockheader']['total_samples'] > 0) &&
|
||||
($info['wavpack']['blockheader']['block_samples'] > 0) &&
|
||||
(!isset($info['wavpack']['riff_trailer_size']) || ($info['wavpack']['riff_trailer_size'] <= 0)) &&
|
||||
((isset($info['wavpack']['config_flags']['md5_checksum']) && ($info['wavpack']['config_flags']['md5_checksum'] === false)) || !empty($info['md5_data_source']))) {
|
||||
break;
|
||||
}
|
||||
|
||||
$blockheader_offset = ftell($this->getid3->fp) - 32;
|
||||
$blockheader_magic = substr($wavpackheader, 0, 4);
|
||||
$blockheader_size = getid3_lib::LittleEndian2Int(substr($wavpackheader, 4, 4));
|
||||
|
||||
$magic = 'wvpk';
|
||||
if ($blockheader_magic != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$blockheader_offset.', found "'.getid3_lib::PrintHexBytes($blockheader_magic).'"';
|
||||
switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') {
|
||||
case 'wavpack':
|
||||
case 'wvc':
|
||||
break;
|
||||
default:
|
||||
unset($info['fileformat']);
|
||||
unset($info['audio']);
|
||||
unset($info['wavpack']);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($info['wavpack']['blockheader']['block_samples']) ||
|
||||
empty($info['wavpack']['blockheader']['total_samples']) ||
|
||||
($info['wavpack']['blockheader']['block_samples'] <= 0) ||
|
||||
($info['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.
|
||||
|
||||
|
||||
$info['audio']['dataformat'] = 'wavpack';
|
||||
$info['fileformat'] = 'wavpack';
|
||||
$info['audio']['lossless'] = true;
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
|
||||
$info['wavpack']['blockheader']['offset'] = $blockheader_offset;
|
||||
$info['wavpack']['blockheader']['magic'] = $blockheader_magic;
|
||||
$info['wavpack']['blockheader']['size'] = $blockheader_size;
|
||||
|
||||
if ($info['wavpack']['blockheader']['size'] >= 0x100000) {
|
||||
$info['error'][] = 'Expecting WavPack block size less than "0x100000", found "'.$info['wavpack']['blockheader']['size'].'" at offset '.$info['wavpack']['blockheader']['offset'];
|
||||
switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') {
|
||||
case 'wavpack':
|
||||
case 'wvc':
|
||||
break;
|
||||
default:
|
||||
unset($info['fileformat']);
|
||||
unset($info['audio']);
|
||||
unset($info['wavpack']);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['wavpack']['blockheader']['minor_version'] = ord($wavpackheader{8});
|
||||
$info['wavpack']['blockheader']['major_version'] = ord($wavpackheader{9});
|
||||
|
||||
if (($info['wavpack']['blockheader']['major_version'] != 4) ||
|
||||
(($info['wavpack']['blockheader']['minor_version'] < 4) &&
|
||||
($info['wavpack']['blockheader']['minor_version'] > 16))) {
|
||||
$info['error'][] = 'Expecting WavPack version between "4.2" and "4.16", found version "'.$info['wavpack']['blockheader']['major_version'].'.'.$info['wavpack']['blockheader']['minor_version'].'" at offset '.$info['wavpack']['blockheader']['offset'];
|
||||
switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') {
|
||||
case 'wavpack':
|
||||
case 'wvc':
|
||||
break;
|
||||
default:
|
||||
unset($info['fileformat']);
|
||||
unset($info['audio']);
|
||||
unset($info['wavpack']);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['wavpack']['blockheader']['track_number'] = ord($wavpackheader{10}); // unused
|
||||
$info['wavpack']['blockheader']['index_number'] = ord($wavpackheader{11}); // unused
|
||||
$info['wavpack']['blockheader']['total_samples'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 12, 4));
|
||||
$info['wavpack']['blockheader']['block_index'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 16, 4));
|
||||
$info['wavpack']['blockheader']['block_samples'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 20, 4));
|
||||
$info['wavpack']['blockheader']['flags_raw'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 24, 4));
|
||||
$info['wavpack']['blockheader']['crc'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 28, 4));
|
||||
|
||||
$info['wavpack']['blockheader']['flags']['bytes_per_sample'] = 1 + ($info['wavpack']['blockheader']['flags_raw'] & 0x00000003);
|
||||
$info['wavpack']['blockheader']['flags']['mono'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000004);
|
||||
$info['wavpack']['blockheader']['flags']['hybrid'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000008);
|
||||
$info['wavpack']['blockheader']['flags']['joint_stereo'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000010);
|
||||
$info['wavpack']['blockheader']['flags']['cross_decorrelation'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000020);
|
||||
$info['wavpack']['blockheader']['flags']['hybrid_noiseshape'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000040);
|
||||
$info['wavpack']['blockheader']['flags']['ieee_32bit_float'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000080);
|
||||
$info['wavpack']['blockheader']['flags']['int_32bit'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000100);
|
||||
$info['wavpack']['blockheader']['flags']['hybrid_bitrate_noise'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000200);
|
||||
$info['wavpack']['blockheader']['flags']['hybrid_balance_noise'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000400);
|
||||
$info['wavpack']['blockheader']['flags']['multichannel_initial'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000800);
|
||||
$info['wavpack']['blockheader']['flags']['multichannel_final'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00001000);
|
||||
|
||||
$info['audio']['lossless'] = !$info['wavpack']['blockheader']['flags']['hybrid'];
|
||||
}
|
||||
|
||||
while (!feof($this->getid3->fp) && (ftell($this->getid3->fp) < ($blockheader_offset + $blockheader_size + 8))) {
|
||||
|
||||
$metablock = array('offset'=>ftell($this->getid3->fp));
|
||||
$metablockheader = fread($this->getid3->fp, 2);
|
||||
if (feof($this->getid3->fp)) {
|
||||
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($this->getid3->fp, 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($this->getid3->fp, $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($this->getid3->fp, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET);
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unexpected metablock type "0x'.str_pad(dechex($metablock['function_id']), 2, '0', STR_PAD_LEFT).'" at offset '.$metablock['offset'];
|
||||
fseek($this->getid3->fp, $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_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_riff = new getid3_riff($getid3_temp);
|
||||
$getid3_riff->ParseRIFFdata($metablock['data']);
|
||||
$metablock['riff'] = $getid3_temp->info['riff'];
|
||||
$info['audio']['sample_rate'] = $getid3_temp->info['riff']['raw']['fmt ']['nSamplesPerSec'];
|
||||
unset($getid3_riff, $getid3_temp);
|
||||
|
||||
$metablock['riff']['original_filesize'] = $original_wav_filesize;
|
||||
$info['wavpack']['riff_trailer_size'] = $original_wav_filesize - $metablock['riff']['WAVE']['data'][0]['size'] - $metablock['riff']['header_size'];
|
||||
$info['playtime_seconds'] = $info['wavpack']['blockheader']['total_samples'] / $info['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);
|
||||
|
||||
$startoffset = $metablock['offset'] + ($metablock['large_block'] ? 4 : 2);
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->info['avdataend'] = $info['avdataend'];
|
||||
$getid3_temp->info['fileformat'] = 'riff';
|
||||
$getid3_riff = new getid3_riff($getid3_temp);
|
||||
$metablock['riff'] = $getid3_riff->ParseRIFF($startoffset, $startoffset + $metablock['size']);
|
||||
|
||||
if (!empty($metablock['riff']['INFO'])) {
|
||||
$getid3_riff->RIFFcommentsParse($metablock['riff']['INFO'], $metablock['comments']);
|
||||
$info['tags']['riff'] = $metablock['comments'];
|
||||
}
|
||||
unset($getid3_temp, $getid3_riff);
|
||||
break;
|
||||
|
||||
|
||||
case 0x23: // ID_REPLAY_GAIN
|
||||
$info['warning'][] = 'WavPack "Replay Gain" contents not yet handled by getID3() in metablock at offset '.$metablock['offset'];
|
||||
break;
|
||||
|
||||
|
||||
case 0x24: // ID_CUESHEET
|
||||
$info['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 %
|
||||
|
||||
$info['wavpack']['config_flags'] = $metablock['flags'];
|
||||
|
||||
|
||||
$info['audio']['encoder_options'] = '';
|
||||
if ($info['wavpack']['blockheader']['flags']['hybrid']) {
|
||||
$info['audio']['encoder_options'] .= ' -b???';
|
||||
}
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['adobe_mode'] ? ' -a' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['optimize_wvc'] ? ' -cc' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['create_exe'] ? ' -e' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['fast_flag'] ? ' -f' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['joint_override'] ? ' -j?' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['high_flag'] ? ' -h' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['md5_checksum'] ? ' -m' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['calc_noise'] ? ' -n' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['shape_override'] ? ' -s?' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['extra_mode'] ? ' -x?' : '');
|
||||
if (!empty($info['audio']['encoder_options'])) {
|
||||
$info['audio']['encoder_options'] = trim($info['audio']['encoder_options']);
|
||||
} elseif (isset($info['audio']['encoder_options'])) {
|
||||
unset($info['audio']['encoder_options']);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0x26: // ID_MD5_CHECKSUM
|
||||
if (strlen($metablock['data']) == 16) {
|
||||
$info['md5_data_source'] = strtolower(getid3_lib::PrintHexBytes($metablock['data'], true, false, false));
|
||||
} else {
|
||||
$info['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)) {
|
||||
$info['wavpack']['metablocks'][] = $metablock;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$info['audio']['encoder'] = 'WavPack v'.$info['wavpack']['blockheader']['major_version'].'.'.str_pad($info['wavpack']['blockheader']['minor_version'], 2, '0', STR_PAD_LEFT);
|
||||
$info['audio']['bits_per_sample'] = $info['wavpack']['blockheader']['flags']['bytes_per_sample'] * 8;
|
||||
$info['audio']['channels'] = ($info['wavpack']['blockheader']['flags']['mono'] ? 1 : 2);
|
||||
|
||||
if (!empty($info['playtime_seconds'])) {
|
||||
|
||||
$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
|
||||
} else {
|
||||
|
||||
$info['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,690 +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.bmp.php //
|
||||
// module for analyzing BMP Image files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_bmp extends getid3_handler
|
||||
{
|
||||
var $ExtractPalette = false;
|
||||
var $ExtractData = false;
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// shortcuts
|
||||
$info['bmp']['header']['raw'] = array();
|
||||
$thisfile_bmp = &$info['bmp'];
|
||||
$thisfile_bmp_header = &$thisfile_bmp['header'];
|
||||
$thisfile_bmp_header_raw = &$thisfile_bmp_header['raw'];
|
||||
|
||||
// BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp
|
||||
// all versions
|
||||
// WORD bfType;
|
||||
// DWORD bfSize;
|
||||
// WORD bfReserved1;
|
||||
// WORD bfReserved2;
|
||||
// DWORD bfOffBits;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$offset = 0;
|
||||
$BMPheader = fread($this->getid3->fp, 14 + 40);
|
||||
|
||||
$thisfile_bmp_header_raw['identifier'] = substr($BMPheader, $offset, 2);
|
||||
$offset += 2;
|
||||
|
||||
$magic = 'BM';
|
||||
if ($thisfile_bmp_header_raw['identifier'] != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_bmp_header_raw['identifier']).'"';
|
||||
unset($info['fileformat']);
|
||||
unset($info['bmp']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$thisfile_bmp_header_raw['filesize'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['reserved1'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['reserved2'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['data_offset'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['header_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
|
||||
// check if the hardcoded-to-1 "planes" is at offset 22 or 26
|
||||
$planes22 = getid3_lib::LittleEndian2Int(substr($BMPheader, 22, 2));
|
||||
$planes26 = getid3_lib::LittleEndian2Int(substr($BMPheader, 26, 2));
|
||||
if (($planes22 == 1) && ($planes26 != 1)) {
|
||||
$thisfile_bmp['type_os'] = 'OS/2';
|
||||
$thisfile_bmp['type_version'] = 1;
|
||||
} elseif (($planes26 == 1) && ($planes22 != 1)) {
|
||||
$thisfile_bmp['type_os'] = 'Windows';
|
||||
$thisfile_bmp['type_version'] = 1;
|
||||
} elseif ($thisfile_bmp_header_raw['header_size'] == 12) {
|
||||
$thisfile_bmp['type_os'] = 'OS/2';
|
||||
$thisfile_bmp['type_version'] = 1;
|
||||
} elseif ($thisfile_bmp_header_raw['header_size'] == 40) {
|
||||
$thisfile_bmp['type_os'] = 'Windows';
|
||||
$thisfile_bmp['type_version'] = 1;
|
||||
} elseif ($thisfile_bmp_header_raw['header_size'] == 84) {
|
||||
$thisfile_bmp['type_os'] = 'Windows';
|
||||
$thisfile_bmp['type_version'] = 4;
|
||||
} elseif ($thisfile_bmp_header_raw['header_size'] == 100) {
|
||||
$thisfile_bmp['type_os'] = 'Windows';
|
||||
$thisfile_bmp['type_version'] = 5;
|
||||
} else {
|
||||
$info['error'][] = 'Unknown BMP subtype (or not a BMP file)';
|
||||
unset($info['fileformat']);
|
||||
unset($info['bmp']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['fileformat'] = 'bmp';
|
||||
$info['video']['dataformat'] = 'bmp';
|
||||
$info['video']['lossless'] = true;
|
||||
$info['video']['pixel_aspect_ratio'] = (float) 1;
|
||||
|
||||
if ($thisfile_bmp['type_os'] == 'OS/2') {
|
||||
|
||||
// OS/2-format BMP
|
||||
// http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm
|
||||
|
||||
// DWORD Size; /* Size of this structure in bytes */
|
||||
// DWORD Width; /* Bitmap width in pixels */
|
||||
// DWORD Height; /* Bitmap height in pixel */
|
||||
// WORD NumPlanes; /* Number of bit planes (color depth) */
|
||||
// WORD BitsPerPixel; /* Number of bits per pixel per plane */
|
||||
|
||||
$thisfile_bmp_header_raw['width'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['height'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['planes'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['bits_per_pixel'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
|
||||
$info['video']['resolution_x'] = $thisfile_bmp_header_raw['width'];
|
||||
$info['video']['resolution_y'] = $thisfile_bmp_header_raw['height'];
|
||||
$info['video']['codec'] = 'BI_RGB '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit';
|
||||
$info['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel'];
|
||||
|
||||
if ($thisfile_bmp['type_version'] >= 2) {
|
||||
// DWORD Compression; /* Bitmap compression scheme */
|
||||
// DWORD ImageDataSize; /* Size of bitmap data in bytes */
|
||||
// DWORD XResolution; /* X resolution of display device */
|
||||
// DWORD YResolution; /* Y resolution of display device */
|
||||
// DWORD ColorsUsed; /* Number of color table indices used */
|
||||
// DWORD ColorsImportant; /* Number of important color indices */
|
||||
// WORD Units; /* Type of units used to measure resolution */
|
||||
// WORD Reserved; /* Pad structure to 4-byte boundary */
|
||||
// WORD Recording; /* Recording algorithm */
|
||||
// WORD Rendering; /* Halftoning algorithm used */
|
||||
// DWORD Size1; /* Reserved for halftoning algorithm use */
|
||||
// DWORD Size2; /* Reserved for halftoning algorithm use */
|
||||
// DWORD ColorEncoding; /* Color model used in bitmap */
|
||||
// DWORD Identifier; /* Reserved for application use */
|
||||
|
||||
$thisfile_bmp_header_raw['compression'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['bmp_data_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['resolution_h'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['resolution_v'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['colors_used'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['colors_important'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['resolution_units'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['reserved1'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['recording'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['rendering'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['size1'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['size2'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['color_encoding'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['identifier'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$thisfile_bmp_header['compression'] = $this->BMPcompressionOS2Lookup($thisfile_bmp_header_raw['compression']);
|
||||
|
||||
$info['video']['codec'] = $thisfile_bmp_header['compression'].' '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit';
|
||||
}
|
||||
|
||||
} elseif ($thisfile_bmp['type_os'] == 'Windows') {
|
||||
|
||||
// Windows-format BMP
|
||||
|
||||
// BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp
|
||||
// all versions
|
||||
// DWORD biSize;
|
||||
// LONG biWidth;
|
||||
// LONG biHeight;
|
||||
// WORD biPlanes;
|
||||
// WORD biBitCount;
|
||||
// DWORD biCompression;
|
||||
// DWORD biSizeImage;
|
||||
// LONG biXPelsPerMeter;
|
||||
// LONG biYPelsPerMeter;
|
||||
// DWORD biClrUsed;
|
||||
// DWORD biClrImportant;
|
||||
|
||||
// possibly integrate this section and module.audio-video.riff.php::ParseBITMAPINFOHEADER() ?
|
||||
|
||||
$thisfile_bmp_header_raw['width'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['height'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['planes'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['bits_per_pixel'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['compression'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['bmp_data_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['resolution_h'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['resolution_v'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['colors_used'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['colors_important'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$thisfile_bmp_header['compression'] = $this->BMPcompressionWindowsLookup($thisfile_bmp_header_raw['compression']);
|
||||
$info['video']['resolution_x'] = $thisfile_bmp_header_raw['width'];
|
||||
$info['video']['resolution_y'] = $thisfile_bmp_header_raw['height'];
|
||||
$info['video']['codec'] = $thisfile_bmp_header['compression'].' '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit';
|
||||
$info['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel'];
|
||||
|
||||
if (($thisfile_bmp['type_version'] >= 4) || ($thisfile_bmp_header_raw['compression'] == 3)) {
|
||||
// should only be v4+, but BMPs with type_version==1 and BI_BITFIELDS compression have been seen
|
||||
$BMPheader .= fread($this->getid3->fp, 44);
|
||||
|
||||
// BITMAPV4HEADER - [44 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_2k1e.asp
|
||||
// Win95+, WinNT4.0+
|
||||
// DWORD bV4RedMask;
|
||||
// DWORD bV4GreenMask;
|
||||
// DWORD bV4BlueMask;
|
||||
// DWORD bV4AlphaMask;
|
||||
// DWORD bV4CSType;
|
||||
// CIEXYZTRIPLE bV4Endpoints;
|
||||
// DWORD bV4GammaRed;
|
||||
// DWORD bV4GammaGreen;
|
||||
// DWORD bV4GammaBlue;
|
||||
$thisfile_bmp_header_raw['red_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['green_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['blue_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['alpha_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['cs_type'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['ciexyz_red'] = substr($BMPheader, $offset, 4);
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['ciexyz_green'] = substr($BMPheader, $offset, 4);
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['ciexyz_blue'] = substr($BMPheader, $offset, 4);
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['gamma_red'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['gamma_green'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['gamma_blue'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$thisfile_bmp_header['ciexyz_red'] = getid3_lib::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_red']));
|
||||
$thisfile_bmp_header['ciexyz_green'] = getid3_lib::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_green']));
|
||||
$thisfile_bmp_header['ciexyz_blue'] = getid3_lib::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_blue']));
|
||||
}
|
||||
|
||||
if ($thisfile_bmp['type_version'] >= 5) {
|
||||
$BMPheader .= fread($this->getid3->fp, 16);
|
||||
|
||||
// BITMAPV5HEADER - [16 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_7c36.asp
|
||||
// Win98+, Win2000+
|
||||
// DWORD bV5Intent;
|
||||
// DWORD bV5ProfileData;
|
||||
// DWORD bV5ProfileSize;
|
||||
// DWORD bV5Reserved;
|
||||
$thisfile_bmp_header_raw['intent'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['profile_data_offset'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['profile_data_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['reserved3'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$info['error'][] = 'Unknown BMP format in header.';
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
if ($this->ExtractPalette || $this->ExtractData) {
|
||||
$PaletteEntries = 0;
|
||||
if ($thisfile_bmp_header_raw['bits_per_pixel'] < 16) {
|
||||
$PaletteEntries = pow(2, $thisfile_bmp_header_raw['bits_per_pixel']);
|
||||
} elseif (isset($thisfile_bmp_header_raw['colors_used']) && ($thisfile_bmp_header_raw['colors_used'] > 0) && ($thisfile_bmp_header_raw['colors_used'] <= 256)) {
|
||||
$PaletteEntries = $thisfile_bmp_header_raw['colors_used'];
|
||||
}
|
||||
if ($PaletteEntries > 0) {
|
||||
$BMPpalette = fread($this->getid3->fp, 4 * $PaletteEntries);
|
||||
$paletteoffset = 0;
|
||||
for ($i = 0; $i < $PaletteEntries; $i++) {
|
||||
// RGBQUAD - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_5f8y.asp
|
||||
// BYTE rgbBlue;
|
||||
// BYTE rgbGreen;
|
||||
// BYTE rgbRed;
|
||||
// BYTE rgbReserved;
|
||||
$blue = getid3_lib::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
|
||||
$green = getid3_lib::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
|
||||
$red = getid3_lib::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
|
||||
if (($thisfile_bmp['type_os'] == 'OS/2') && ($thisfile_bmp['type_version'] == 1)) {
|
||||
// no padding byte
|
||||
} else {
|
||||
$paletteoffset++; // padding byte
|
||||
}
|
||||
$thisfile_bmp['palette'][$i] = (($red << 16) | ($green << 8) | $blue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->ExtractData) {
|
||||
fseek($this->getid3->fp, $thisfile_bmp_header_raw['data_offset'], SEEK_SET);
|
||||
$RowByteLength = ceil(($thisfile_bmp_header_raw['width'] * ($thisfile_bmp_header_raw['bits_per_pixel'] / 8)) / 4) * 4; // round up to nearest DWORD boundry
|
||||
$BMPpixelData = fread($this->getid3->fp, $thisfile_bmp_header_raw['height'] * $RowByteLength);
|
||||
$pixeldataoffset = 0;
|
||||
$thisfile_bmp_header_raw['compression'] = (isset($thisfile_bmp_header_raw['compression']) ? $thisfile_bmp_header_raw['compression'] : '');
|
||||
switch ($thisfile_bmp_header_raw['compression']) {
|
||||
|
||||
case 0: // BI_RGB
|
||||
switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
|
||||
case 1:
|
||||
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
|
||||
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
|
||||
$paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++});
|
||||
for ($i = 7; $i >= 0; $i--) {
|
||||
$paletteindex = ($paletteindexbyte & (0x01 << $i)) >> $i;
|
||||
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
|
||||
$col++;
|
||||
}
|
||||
}
|
||||
while (($pixeldataoffset % 4) != 0) {
|
||||
// lines are padded to nearest DWORD
|
||||
$pixeldataoffset++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
|
||||
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
|
||||
$paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++});
|
||||
for ($i = 1; $i >= 0; $i--) {
|
||||
$paletteindex = ($paletteindexbyte & (0x0F << (4 * $i))) >> (4 * $i);
|
||||
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
|
||||
$col++;
|
||||
}
|
||||
}
|
||||
while (($pixeldataoffset % 4) != 0) {
|
||||
// lines are padded to nearest DWORD
|
||||
$pixeldataoffset++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
|
||||
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
|
||||
$paletteindex = ord($BMPpixelData{$pixeldataoffset++});
|
||||
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
|
||||
}
|
||||
while (($pixeldataoffset % 4) != 0) {
|
||||
// lines are padded to nearest DWORD
|
||||
$pixeldataoffset++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 24:
|
||||
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
|
||||
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
|
||||
$thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData{$pixeldataoffset+2}) << 16) | (ord($BMPpixelData{$pixeldataoffset+1}) << 8) | ord($BMPpixelData{$pixeldataoffset});
|
||||
$pixeldataoffset += 3;
|
||||
}
|
||||
while (($pixeldataoffset % 4) != 0) {
|
||||
// lines are padded to nearest DWORD
|
||||
$pixeldataoffset++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 32:
|
||||
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
|
||||
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
|
||||
$thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData{$pixeldataoffset+3}) << 24) | (ord($BMPpixelData{$pixeldataoffset+2}) << 16) | (ord($BMPpixelData{$pixeldataoffset+1}) << 8) | ord($BMPpixelData{$pixeldataoffset});
|
||||
$pixeldataoffset += 4;
|
||||
}
|
||||
while (($pixeldataoffset % 4) != 0) {
|
||||
// lines are padded to nearest DWORD
|
||||
$pixeldataoffset++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 16:
|
||||
// ?
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 1: // BI_RLE8 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp
|
||||
switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
|
||||
case 8:
|
||||
$pixelcounter = 0;
|
||||
while ($pixeldataoffset < strlen($BMPpixelData)) {
|
||||
$firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
$secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
if ($firstbyte == 0) {
|
||||
|
||||
// escaped/absolute mode - the first byte of the pair can be set to zero to
|
||||
// indicate an escape character that denotes the end of a line, the end of
|
||||
// a bitmap, or a delta, depending on the value of the second byte.
|
||||
switch ($secondbyte) {
|
||||
case 0:
|
||||
// end of line
|
||||
// no need for special processing, just ignore
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// end of bitmap
|
||||
$pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// delta - The 2 bytes following the escape contain unsigned values
|
||||
// indicating the horizontal and vertical offsets of the next pixel
|
||||
// from the current position.
|
||||
$colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
$rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
$col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement;
|
||||
$row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement;
|
||||
$pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col;
|
||||
break;
|
||||
|
||||
default:
|
||||
// In absolute mode, the first byte is zero and the second byte is a
|
||||
// value in the range 03H through FFH. The second byte represents the
|
||||
// number of bytes that follow, each of which contains the color index
|
||||
// of a single pixel. Each run must be aligned on a word boundary.
|
||||
for ($i = 0; $i < $secondbyte; $i++) {
|
||||
$paletteindex = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
$col = $pixelcounter % $thisfile_bmp_header_raw['width'];
|
||||
$row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
|
||||
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
|
||||
$pixelcounter++;
|
||||
}
|
||||
while (($pixeldataoffset % 2) != 0) {
|
||||
// Each run must be aligned on a word boundary.
|
||||
$pixeldataoffset++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// encoded mode - the first byte specifies the number of consecutive pixels
|
||||
// to be drawn using the color index contained in the second byte.
|
||||
for ($i = 0; $i < $firstbyte; $i++) {
|
||||
$col = $pixelcounter % $thisfile_bmp_header_raw['width'];
|
||||
$row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
|
||||
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$secondbyte];
|
||||
$pixelcounter++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case 2: // BI_RLE4 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp
|
||||
switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
|
||||
case 4:
|
||||
$pixelcounter = 0;
|
||||
while ($pixeldataoffset < strlen($BMPpixelData)) {
|
||||
$firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
$secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
if ($firstbyte == 0) {
|
||||
|
||||
// escaped/absolute mode - the first byte of the pair can be set to zero to
|
||||
// indicate an escape character that denotes the end of a line, the end of
|
||||
// a bitmap, or a delta, depending on the value of the second byte.
|
||||
switch ($secondbyte) {
|
||||
case 0:
|
||||
// end of line
|
||||
// no need for special processing, just ignore
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// end of bitmap
|
||||
$pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// delta - The 2 bytes following the escape contain unsigned values
|
||||
// indicating the horizontal and vertical offsets of the next pixel
|
||||
// from the current position.
|
||||
$colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
$rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
$col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement;
|
||||
$row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement;
|
||||
$pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col;
|
||||
break;
|
||||
|
||||
default:
|
||||
// In absolute mode, the first byte is zero. The second byte contains the number
|
||||
// of color indexes that follow. Subsequent bytes contain color indexes in their
|
||||
// high- and low-order 4 bits, one color index for each pixel. In absolute mode,
|
||||
// each run must be aligned on a word boundary.
|
||||
unset($paletteindexes);
|
||||
for ($i = 0; $i < ceil($secondbyte / 2); $i++) {
|
||||
$paletteindexbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
$paletteindexes[] = ($paletteindexbyte & 0xF0) >> 4;
|
||||
$paletteindexes[] = ($paletteindexbyte & 0x0F);
|
||||
}
|
||||
while (($pixeldataoffset % 2) != 0) {
|
||||
// Each run must be aligned on a word boundary.
|
||||
$pixeldataoffset++;
|
||||
}
|
||||
|
||||
foreach ($paletteindexes as $paletteindex) {
|
||||
$col = $pixelcounter % $thisfile_bmp_header_raw['width'];
|
||||
$row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
|
||||
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
|
||||
$pixelcounter++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// encoded mode - the first byte of the pair contains the number of pixels to be
|
||||
// drawn using the color indexes in the second byte. The second byte contains two
|
||||
// color indexes, one in its high-order 4 bits and one in its low-order 4 bits.
|
||||
// The first of the pixels is drawn using the color specified by the high-order
|
||||
// 4 bits, the second is drawn using the color in the low-order 4 bits, the third
|
||||
// is drawn using the color in the high-order 4 bits, and so on, until all the
|
||||
// pixels specified by the first byte have been drawn.
|
||||
$paletteindexes[0] = ($secondbyte & 0xF0) >> 4;
|
||||
$paletteindexes[1] = ($secondbyte & 0x0F);
|
||||
for ($i = 0; $i < $firstbyte; $i++) {
|
||||
$col = $pixelcounter % $thisfile_bmp_header_raw['width'];
|
||||
$row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
|
||||
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindexes[($i % 2)]];
|
||||
$pixelcounter++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 3: // BI_BITFIELDS
|
||||
switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
|
||||
case 16:
|
||||
case 32:
|
||||
$redshift = 0;
|
||||
$greenshift = 0;
|
||||
$blueshift = 0;
|
||||
while ((($thisfile_bmp_header_raw['red_mask'] >> $redshift) & 0x01) == 0) {
|
||||
$redshift++;
|
||||
}
|
||||
while ((($thisfile_bmp_header_raw['green_mask'] >> $greenshift) & 0x01) == 0) {
|
||||
$greenshift++;
|
||||
}
|
||||
while ((($thisfile_bmp_header_raw['blue_mask'] >> $blueshift) & 0x01) == 0) {
|
||||
$blueshift++;
|
||||
}
|
||||
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
|
||||
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
|
||||
$pixelvalue = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset, $thisfile_bmp_header_raw['bits_per_pixel'] / 8));
|
||||
$pixeldataoffset += $thisfile_bmp_header_raw['bits_per_pixel'] / 8;
|
||||
|
||||
$red = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['red_mask']) >> $redshift) / ($thisfile_bmp_header_raw['red_mask'] >> $redshift)) * 255));
|
||||
$green = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['green_mask']) >> $greenshift) / ($thisfile_bmp_header_raw['green_mask'] >> $greenshift)) * 255));
|
||||
$blue = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['blue_mask']) >> $blueshift) / ($thisfile_bmp_header_raw['blue_mask'] >> $blueshift)) * 255));
|
||||
$thisfile_bmp['data'][$row][$col] = (($red << 16) | ($green << 8) | ($blue));
|
||||
}
|
||||
while (($pixeldataoffset % 4) != 0) {
|
||||
// lines are padded to nearest DWORD
|
||||
$pixeldataoffset++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default: // unhandled compression type
|
||||
$info['error'][] = 'Unknown/unhandled compression type value ('.$thisfile_bmp_header_raw['compression'].') - cannot decompress pixel data';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function PlotBMP(&$BMPinfo) {
|
||||
$starttime = time();
|
||||
if (!isset($BMPinfo['bmp']['data']) || !is_array($BMPinfo['bmp']['data'])) {
|
||||
echo 'ERROR: no pixel data<BR>';
|
||||
return false;
|
||||
}
|
||||
set_time_limit(intval(round($BMPinfo['resolution_x'] * $BMPinfo['resolution_y'] / 10000)));
|
||||
if ($im = ImageCreateTrueColor($BMPinfo['resolution_x'], $BMPinfo['resolution_y'])) {
|
||||
for ($row = 0; $row < $BMPinfo['resolution_y']; $row++) {
|
||||
for ($col = 0; $col < $BMPinfo['resolution_x']; $col++) {
|
||||
if (isset($BMPinfo['bmp']['data'][$row][$col])) {
|
||||
$red = ($BMPinfo['bmp']['data'][$row][$col] & 0x00FF0000) >> 16;
|
||||
$green = ($BMPinfo['bmp']['data'][$row][$col] & 0x0000FF00) >> 8;
|
||||
$blue = ($BMPinfo['bmp']['data'][$row][$col] & 0x000000FF);
|
||||
$pixelcolor = ImageColorAllocate($im, $red, $green, $blue);
|
||||
ImageSetPixel($im, $col, $row, $pixelcolor);
|
||||
} else {
|
||||
//echo 'ERROR: no data for pixel '.$row.' x '.$col.'<BR>';
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (headers_sent()) {
|
||||
echo 'plotted '.($BMPinfo['resolution_x'] * $BMPinfo['resolution_y']).' pixels in '.(time() - $starttime).' seconds<BR>';
|
||||
ImageDestroy($im);
|
||||
exit;
|
||||
} else {
|
||||
header('Content-type: image/png');
|
||||
ImagePNG($im);
|
||||
ImageDestroy($im);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function BMPcompressionWindowsLookup($compressionid) {
|
||||
static $BMPcompressionWindowsLookup = array(
|
||||
0 => 'BI_RGB',
|
||||
1 => 'BI_RLE8',
|
||||
2 => 'BI_RLE4',
|
||||
3 => 'BI_BITFIELDS',
|
||||
4 => 'BI_JPEG',
|
||||
5 => 'BI_PNG'
|
||||
);
|
||||
return (isset($BMPcompressionWindowsLookup[$compressionid]) ? $BMPcompressionWindowsLookup[$compressionid] : 'invalid');
|
||||
}
|
||||
|
||||
function BMPcompressionOS2Lookup($compressionid) {
|
||||
static $BMPcompressionOS2Lookup = array(
|
||||
0 => 'BI_RGB',
|
||||
1 => 'BI_RLE8',
|
||||
2 => 'BI_RLE4',
|
||||
3 => 'Huffman 1D',
|
||||
4 => 'BI_RLE24',
|
||||
);
|
||||
return (isset($BMPcompressionOS2Lookup[$compressionid]) ? $BMPcompressionOS2Lookup[$compressionid] : 'invalid');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,53 +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.efax.php //
|
||||
// module for analyzing eFax files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_efax extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$efaxheader = fread($this->getid3->fp, 1024);
|
||||
|
||||
$info['efax']['header']['magic'] = substr($efaxheader, 0, 2);
|
||||
if ($info['efax']['header']['magic'] != "\xDC\xFE") {
|
||||
$info['error'][] = 'Invalid eFax byte order identifier (expecting DC FE, found '.getid3_lib::PrintHexBytes($info['efax']['header']['magic']).') at offset '.$info['avdataoffset'];
|
||||
return false;
|
||||
}
|
||||
$info['fileformat'] = 'efax';
|
||||
|
||||
$info['efax']['header']['filesize'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 2, 4));
|
||||
if ($info['efax']['header']['filesize'] != $info['filesize']) {
|
||||
$info['error'][] = 'Probable '.(($info['efax']['header']['filesize'] > $info['filesize']) ? 'truncated' : 'corrupt').' file, expecting '.$info['efax']['header']['filesize'].' bytes, found '.$info['filesize'].' bytes';
|
||||
}
|
||||
$info['efax']['header']['software1'] = rtrim(substr($efaxheader, 26, 32), "\x00");
|
||||
$info['efax']['header']['software2'] = rtrim(substr($efaxheader, 58, 32), "\x00");
|
||||
$info['efax']['header']['software3'] = rtrim(substr($efaxheader, 90, 32), "\x00");
|
||||
|
||||
$info['efax']['header']['pages'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 198, 2));
|
||||
$info['efax']['header']['data_bytes'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 202, 4));
|
||||
|
||||
$info['error'][] = 'eFax parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,184 +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 extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'gif';
|
||||
$info['video']['dataformat'] = 'gif';
|
||||
$info['video']['lossless'] = true;
|
||||
$info['video']['pixel_aspect_ratio'] = (float) 1;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$GIFheader = fread($this->getid3->fp, 13);
|
||||
$offset = 0;
|
||||
|
||||
$info['gif']['header']['raw']['identifier'] = substr($GIFheader, $offset, 3);
|
||||
$offset += 3;
|
||||
|
||||
$magic = 'GIF';
|
||||
if ($info['gif']['header']['raw']['identifier'] != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['gif']['header']['raw']['identifier']).'"';
|
||||
unset($info['fileformat']);
|
||||
unset($info['gif']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['gif']['header']['raw']['version'] = substr($GIFheader, $offset, 3);
|
||||
$offset += 3;
|
||||
$info['gif']['header']['raw']['width'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$info['gif']['header']['raw']['height'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$info['gif']['header']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1));
|
||||
$offset += 1;
|
||||
$info['gif']['header']['raw']['bg_color_index'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1));
|
||||
$offset += 1;
|
||||
$info['gif']['header']['raw']['aspect_ratio'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1));
|
||||
$offset += 1;
|
||||
|
||||
$info['video']['resolution_x'] = $info['gif']['header']['raw']['width'];
|
||||
$info['video']['resolution_y'] = $info['gif']['header']['raw']['height'];
|
||||
$info['gif']['version'] = $info['gif']['header']['raw']['version'];
|
||||
$info['gif']['header']['flags']['global_color_table'] = (bool) ($info['gif']['header']['raw']['flags'] & 0x80);
|
||||
if ($info['gif']['header']['raw']['flags'] & 0x80) {
|
||||
// Number of bits per primary color available to the original image, minus 1
|
||||
$info['gif']['header']['bits_per_pixel'] = 3 * ((($info['gif']['header']['raw']['flags'] & 0x70) >> 4) + 1);
|
||||
} else {
|
||||
$info['gif']['header']['bits_per_pixel'] = 0;
|
||||
}
|
||||
$info['gif']['header']['flags']['global_color_sorted'] = (bool) ($info['gif']['header']['raw']['flags'] & 0x40);
|
||||
if ($info['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]
|
||||
$info['gif']['header']['global_color_size'] = pow(2, ($info['gif']['header']['raw']['flags'] & 0x07) + 1);
|
||||
$info['video']['bits_per_sample'] = ($info['gif']['header']['raw']['flags'] & 0x07) + 1;
|
||||
} else {
|
||||
$info['gif']['header']['global_color_size'] = 0;
|
||||
}
|
||||
if ($info['gif']['header']['raw']['aspect_ratio'] != 0) {
|
||||
// Aspect Ratio = (Pixel Aspect Ratio + 15) / 64
|
||||
$info['gif']['header']['aspect_ratio'] = ($info['gif']['header']['raw']['aspect_ratio'] + 15) / 64;
|
||||
}
|
||||
|
||||
// if ($info['gif']['header']['flags']['global_color_table']) {
|
||||
// $GIFcolorTable = fread($this->getid3->fp, 3 * $info['gif']['header']['global_color_size']);
|
||||
// $offset = 0;
|
||||
// for ($i = 0; $i < $info['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));
|
||||
// $info['gif']['global_color_table'][$i] = (($red << 16) | ($green << 8) | ($blue));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Image Descriptor
|
||||
// while (!feof($this->getid3->fp)) {
|
||||
// $NextBlockTest = fread($this->getid3->fp, 1);
|
||||
// switch ($NextBlockTest) {
|
||||
//
|
||||
// case ',': // ',' - Image separator character
|
||||
//
|
||||
// $ImageDescriptorData = $NextBlockTest.fread($this->getid3->fp, 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);
|
||||
// $info['gif']['image_descriptor'][] = $ImageDescriptor;
|
||||
//
|
||||
// if ($ImageDescriptor['flags']['use_local_color_map']) {
|
||||
//
|
||||
// $info['warning'][] = 'This version of getID3() cannot parse local color maps for GIFs';
|
||||
// return true;
|
||||
//
|
||||
// }
|
||||
//echo 'Start of raster data: '.ftell($this->getid3->fp).'<BR>';
|
||||
// $RasterData = array();
|
||||
// $RasterData['code_size'] = getid3_lib::LittleEndian2Int(fread($this->getid3->fp, 1));
|
||||
// $RasterData['block_byte_count'] = getid3_lib::LittleEndian2Int(fread($this->getid3->fp, 1));
|
||||
// $info['gif']['raster_data'][count($info['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($CurrentCodeSize);
|
||||
// echo 'Clear Code: '.$NextValue.'<BR>';
|
||||
//
|
||||
// $NextValue = $this->GetLSBits($CurrentCodeSize);
|
||||
// echo 'First Color: '.$NextValue.'<BR>';
|
||||
//
|
||||
// $Prefix = $NextValue;
|
||||
//$i = 0;
|
||||
// while ($i++ < 20) {
|
||||
// $NextValue = $this->GetLSBits($CurrentCodeSize);
|
||||
// echo $NextValue.'<BR>';
|
||||
// }
|
||||
//return true;
|
||||
// break;
|
||||
//
|
||||
// case '!':
|
||||
// // GIF Extension Block
|
||||
// $ExtensionBlockData = $NextBlockTest.fread($this->getid3->fp, 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($this->getid3->fp, $ExtensionBlock['byte_length']);
|
||||
// $info['gif']['extension_blocks'][] = $ExtensionBlock;
|
||||
// break;
|
||||
//
|
||||
// case ';':
|
||||
// $info['gif']['terminator_offset'] = ftell($this->getid3->fp) - 1;
|
||||
// // GIF Terminator
|
||||
// break;
|
||||
//
|
||||
// default:
|
||||
// break;
|
||||
//
|
||||
//
|
||||
// }
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function GetLSBits($bits) {
|
||||
static $bitbuffer = '';
|
||||
while (strlen($bitbuffer) < $bits) {
|
||||
$bitbuffer = str_pad(decbin(ord(fread($this->getid3->fp, 1))), 8, '0', STR_PAD_LEFT).$bitbuffer;
|
||||
}
|
||||
$value = bindec(substr($bitbuffer, 0 - $bits));
|
||||
$bitbuffer = substr($bitbuffer, 0, 0 - $bits);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,338 +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.jpg.php //
|
||||
// module for analyzing JPEG Image files //
|
||||
// dependencies: PHP compiled with --enable-exif (optional) //
|
||||
// module.tag.xmp.php (optional) //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_jpg extends getid3_handler
|
||||
{
|
||||
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'jpg';
|
||||
$info['video']['dataformat'] = 'jpg';
|
||||
$info['video']['lossless'] = false;
|
||||
$info['video']['bits_per_sample'] = 24;
|
||||
$info['video']['pixel_aspect_ratio'] = (float) 1;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
|
||||
$imageinfo = array();
|
||||
list($width, $height, $type) = getid3_lib::GetDataImageSize(fread($this->getid3->fp, $info['filesize']), $imageinfo);
|
||||
|
||||
|
||||
if (isset($imageinfo['APP13'])) {
|
||||
// http://php.net/iptcparse
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
|
||||
$iptc_parsed = iptcparse($imageinfo['APP13']);
|
||||
if (is_array($iptc_parsed)) {
|
||||
foreach ($iptc_parsed as $iptc_key_raw => $iptc_values) {
|
||||
list($iptc_record, $iptc_tagkey) = explode('#', $iptc_key_raw);
|
||||
$iptc_tagkey = intval(ltrim($iptc_tagkey, '0'));
|
||||
foreach ($iptc_values as $key => $value) {
|
||||
$IPTCrecordName = $this->IPTCrecordName($iptc_record);
|
||||
$IPTCrecordTagName = $this->IPTCrecordTagName($iptc_record, $iptc_tagkey);
|
||||
if (isset($info['iptc'][$IPTCrecordName][$IPTCrecordTagName])) {
|
||||
$info['iptc'][$IPTCrecordName][$IPTCrecordTagName][] = $value;
|
||||
} else {
|
||||
$info['iptc'][$IPTCrecordName][$IPTCrecordTagName] = array($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$returnOK = false;
|
||||
switch ($type) {
|
||||
case IMG_JPG:
|
||||
$info['video']['resolution_x'] = $width;
|
||||
$info['video']['resolution_y'] = $height;
|
||||
|
||||
if (isset($imageinfo['APP1'])) {
|
||||
if (function_exists('exif_read_data')) {
|
||||
if (substr($imageinfo['APP1'], 0, 4) == 'Exif') {
|
||||
$info['jpg']['exif'] = @exif_read_data($info['filenamepath'], '', true, false);
|
||||
} else {
|
||||
$info['warning'][] = 'exif_read_data() cannot parse non-EXIF data in APP1 (expected "Exif", found "'.substr($imageinfo['APP1'], 0, 4).'")';
|
||||
}
|
||||
} else {
|
||||
$info['warning'][] = 'EXIF parsing only available when '.(GETID3_OS_ISWINDOWS ? 'php_exif.dll enabled' : 'compiled with --enable-exif');
|
||||
}
|
||||
}
|
||||
$returnOK = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
$cast_as_appropriate_keys = array('EXIF', 'IFD0', 'THUMBNAIL');
|
||||
foreach ($cast_as_appropriate_keys as $exif_key) {
|
||||
if (isset($info['jpg']['exif'][$exif_key])) {
|
||||
foreach ($info['jpg']['exif'][$exif_key] as $key => $value) {
|
||||
$info['jpg']['exif'][$exif_key][$key] = $this->CastAsAppropriate($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isset($info['jpg']['exif']['GPS'])) {
|
||||
|
||||
if (isset($info['jpg']['exif']['GPS']['GPSVersion'])) {
|
||||
for ($i = 0; $i < 4; $i++) {
|
||||
$version_subparts[$i] = ord(substr($info['jpg']['exif']['GPS']['GPSVersion'], $i, 1));
|
||||
}
|
||||
$info['jpg']['exif']['GPS']['computed']['version'] = 'v'.implode('.', $version_subparts);
|
||||
}
|
||||
|
||||
if (isset($info['jpg']['exif']['GPS']['GPSDateStamp'])) {
|
||||
$explodedGPSDateStamp = explode(':', $info['jpg']['exif']['GPS']['GPSDateStamp']);
|
||||
$computed_time[5] = (isset($explodedGPSDateStamp[0]) ? $explodedGPSDateStamp[0] : '');
|
||||
$computed_time[3] = (isset($explodedGPSDateStamp[1]) ? $explodedGPSDateStamp[1] : '');
|
||||
$computed_time[4] = (isset($explodedGPSDateStamp[2]) ? $explodedGPSDateStamp[2] : '');
|
||||
|
||||
if (function_exists('date_default_timezone_set')) {
|
||||
date_default_timezone_set('UTC');
|
||||
} else {
|
||||
ini_set('date.timezone', 'UTC');
|
||||
}
|
||||
|
||||
$computed_time = array(0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0);
|
||||
if (isset($info['jpg']['exif']['GPS']['GPSTimeStamp']) && is_array($info['jpg']['exif']['GPS']['GPSTimeStamp'])) {
|
||||
foreach ($info['jpg']['exif']['GPS']['GPSTimeStamp'] as $key => $value) {
|
||||
$computed_time[$key] = getid3_lib::DecimalizeFraction($value);
|
||||
}
|
||||
}
|
||||
$info['jpg']['exif']['GPS']['computed']['timestamp'] = mktime($computed_time[0], $computed_time[1], $computed_time[2], $computed_time[3], $computed_time[4], $computed_time[5]);
|
||||
}
|
||||
|
||||
if (isset($info['jpg']['exif']['GPS']['GPSLatitude']) && is_array($info['jpg']['exif']['GPS']['GPSLatitude'])) {
|
||||
$direction_multiplier = ((isset($info['jpg']['exif']['GPS']['GPSLatitudeRef']) && ($info['jpg']['exif']['GPS']['GPSLatitudeRef'] == 'S')) ? -1 : 1);
|
||||
foreach ($info['jpg']['exif']['GPS']['GPSLatitude'] as $key => $value) {
|
||||
$computed_latitude[$key] = getid3_lib::DecimalizeFraction($value);
|
||||
}
|
||||
$info['jpg']['exif']['GPS']['computed']['latitude'] = $direction_multiplier * ($computed_latitude[0] + ($computed_latitude[1] / 60) + ($computed_latitude[2] / 3600));
|
||||
}
|
||||
|
||||
if (isset($info['jpg']['exif']['GPS']['GPSLongitude']) && is_array($info['jpg']['exif']['GPS']['GPSLongitude'])) {
|
||||
$direction_multiplier = ((isset($info['jpg']['exif']['GPS']['GPSLongitudeRef']) && ($info['jpg']['exif']['GPS']['GPSLongitudeRef'] == 'W')) ? -1 : 1);
|
||||
foreach ($info['jpg']['exif']['GPS']['GPSLongitude'] as $key => $value) {
|
||||
$computed_longitude[$key] = getid3_lib::DecimalizeFraction($value);
|
||||
}
|
||||
$info['jpg']['exif']['GPS']['computed']['longitude'] = $direction_multiplier * ($computed_longitude[0] + ($computed_longitude[1] / 60) + ($computed_longitude[2] / 3600));
|
||||
}
|
||||
|
||||
if (isset($info['jpg']['exif']['GPS']['GPSAltitude'])) {
|
||||
$direction_multiplier = ((isset($info['jpg']['exif']['GPS']['GPSAltitudeRef']) && ($info['jpg']['exif']['GPS']['GPSAltitudeRef'] === chr(1))) ? -1 : 1);
|
||||
$info['jpg']['exif']['GPS']['computed']['altitude'] = $direction_multiplier * getid3_lib::DecimalizeFraction($info['jpg']['exif']['GPS']['GPSAltitude']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.xmp.php', __FILE__, false)) {
|
||||
if (isset($info['filenamepath'])) {
|
||||
$image_xmp = new Image_XMP($info['filenamepath']);
|
||||
$xmp_raw = $image_xmp->getAllTags();
|
||||
foreach ($xmp_raw as $key => $value) {
|
||||
list($subsection, $tagname) = explode(':', $key);
|
||||
$info['xmp'][$subsection][$tagname] = $this->CastAsAppropriate($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$returnOK) {
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function CastAsAppropriate($value) {
|
||||
if (is_array($value)) {
|
||||
return $value;
|
||||
} elseif (preg_match('#^[0-9]+/[0-9]+$#', $value)) {
|
||||
return getid3_lib::DecimalizeFraction($value);
|
||||
} elseif (preg_match('#^[0-9]+$#', $value)) {
|
||||
return getid3_lib::CastAsInt($value);
|
||||
} elseif (preg_match('#^[0-9\.]+$#', $value)) {
|
||||
return (float) $value;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
function IPTCrecordName($iptc_record) {
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
|
||||
static $IPTCrecordName = array();
|
||||
if (empty($IPTCrecordName)) {
|
||||
$IPTCrecordName = array(
|
||||
1 => 'IPTCEnvelope',
|
||||
2 => 'IPTCApplication',
|
||||
3 => 'IPTCNewsPhoto',
|
||||
7 => 'IPTCPreObjectData',
|
||||
8 => 'IPTCObjectData',
|
||||
9 => 'IPTCPostObjectData',
|
||||
);
|
||||
}
|
||||
return (isset($IPTCrecordName[$iptc_record]) ? $IPTCrecordName[$iptc_record] : '');
|
||||
}
|
||||
|
||||
|
||||
function IPTCrecordTagName($iptc_record, $iptc_tagkey) {
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
|
||||
static $IPTCrecordTagName = array();
|
||||
if (empty($IPTCrecordTagName)) {
|
||||
$IPTCrecordTagName = array(
|
||||
1 => array( // IPTC EnvelopeRecord Tags
|
||||
0 => 'EnvelopeRecordVersion',
|
||||
5 => 'Destination',
|
||||
20 => 'FileFormat',
|
||||
22 => 'FileVersion',
|
||||
30 => 'ServiceIdentifier',
|
||||
40 => 'EnvelopeNumber',
|
||||
50 => 'ProductID',
|
||||
60 => 'EnvelopePriority',
|
||||
70 => 'DateSent',
|
||||
80 => 'TimeSent',
|
||||
90 => 'CodedCharacterSet',
|
||||
100 => 'UniqueObjectName',
|
||||
120 => 'ARMIdentifier',
|
||||
122 => 'ARMVersion',
|
||||
),
|
||||
2 => array( // IPTC ApplicationRecord Tags
|
||||
0 => 'ApplicationRecordVersion',
|
||||
3 => 'ObjectTypeReference',
|
||||
4 => 'ObjectAttributeReference',
|
||||
5 => 'ObjectName',
|
||||
7 => 'EditStatus',
|
||||
8 => 'EditorialUpdate',
|
||||
10 => 'Urgency',
|
||||
12 => 'SubjectReference',
|
||||
15 => 'Category',
|
||||
20 => 'SupplementalCategories',
|
||||
22 => 'FixtureIdentifier',
|
||||
25 => 'Keywords',
|
||||
26 => 'ContentLocationCode',
|
||||
27 => 'ContentLocationName',
|
||||
30 => 'ReleaseDate',
|
||||
35 => 'ReleaseTime',
|
||||
37 => 'ExpirationDate',
|
||||
38 => 'ExpirationTime',
|
||||
40 => 'SpecialInstructions',
|
||||
42 => 'ActionAdvised',
|
||||
45 => 'ReferenceService',
|
||||
47 => 'ReferenceDate',
|
||||
50 => 'ReferenceNumber',
|
||||
55 => 'DateCreated',
|
||||
60 => 'TimeCreated',
|
||||
62 => 'DigitalCreationDate',
|
||||
63 => 'DigitalCreationTime',
|
||||
65 => 'OriginatingProgram',
|
||||
70 => 'ProgramVersion',
|
||||
75 => 'ObjectCycle',
|
||||
80 => 'By-line',
|
||||
85 => 'By-lineTitle',
|
||||
90 => 'City',
|
||||
92 => 'Sub-location',
|
||||
95 => 'Province-State',
|
||||
100 => 'Country-PrimaryLocationCode',
|
||||
101 => 'Country-PrimaryLocationName',
|
||||
103 => 'OriginalTransmissionReference',
|
||||
105 => 'Headline',
|
||||
110 => 'Credit',
|
||||
115 => 'Source',
|
||||
116 => 'CopyrightNotice',
|
||||
118 => 'Contact',
|
||||
120 => 'Caption-Abstract',
|
||||
121 => 'LocalCaption',
|
||||
122 => 'Writer-Editor',
|
||||
125 => 'RasterizedCaption',
|
||||
130 => 'ImageType',
|
||||
131 => 'ImageOrientation',
|
||||
135 => 'LanguageIdentifier',
|
||||
150 => 'AudioType',
|
||||
151 => 'AudioSamplingRate',
|
||||
152 => 'AudioSamplingResolution',
|
||||
153 => 'AudioDuration',
|
||||
154 => 'AudioOutcue',
|
||||
184 => 'JobID',
|
||||
185 => 'MasterDocumentID',
|
||||
186 => 'ShortDocumentID',
|
||||
187 => 'UniqueDocumentID',
|
||||
188 => 'OwnerID',
|
||||
200 => 'ObjectPreviewFileFormat',
|
||||
201 => 'ObjectPreviewFileVersion',
|
||||
202 => 'ObjectPreviewData',
|
||||
221 => 'Prefs',
|
||||
225 => 'ClassifyState',
|
||||
228 => 'SimilarityIndex',
|
||||
230 => 'DocumentNotes',
|
||||
231 => 'DocumentHistory',
|
||||
232 => 'ExifCameraInfo',
|
||||
),
|
||||
3 => array( // IPTC NewsPhoto Tags
|
||||
0 => 'NewsPhotoVersion',
|
||||
10 => 'IPTCPictureNumber',
|
||||
20 => 'IPTCImageWidth',
|
||||
30 => 'IPTCImageHeight',
|
||||
40 => 'IPTCPixelWidth',
|
||||
50 => 'IPTCPixelHeight',
|
||||
55 => 'SupplementalType',
|
||||
60 => 'ColorRepresentation',
|
||||
64 => 'InterchangeColorSpace',
|
||||
65 => 'ColorSequence',
|
||||
66 => 'ICC_Profile',
|
||||
70 => 'ColorCalibrationMatrix',
|
||||
80 => 'LookupTable',
|
||||
84 => 'NumIndexEntries',
|
||||
85 => 'ColorPalette',
|
||||
86 => 'IPTCBitsPerSample',
|
||||
90 => 'SampleStructure',
|
||||
100 => 'ScanningDirection',
|
||||
102 => 'IPTCImageRotation',
|
||||
110 => 'DataCompressionMethod',
|
||||
120 => 'QuantizationMethod',
|
||||
125 => 'EndPoints',
|
||||
130 => 'ExcursionTolerance',
|
||||
135 => 'BitsPerComponent',
|
||||
140 => 'MaximumDensityRange',
|
||||
145 => 'GammaCompensatedValue',
|
||||
),
|
||||
7 => array( // IPTC PreObjectData Tags
|
||||
10 => 'SizeMode',
|
||||
20 => 'MaxSubfileSize',
|
||||
90 => 'ObjectSizeAnnounced',
|
||||
95 => 'MaximumObjectSize',
|
||||
),
|
||||
8 => array( // IPTC ObjectData Tags
|
||||
10 => 'SubFile',
|
||||
),
|
||||
9 => array( // IPTC PostObjectData Tags
|
||||
10 => 'ConfirmedObjectSize',
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
return (isset($IPTCrecordTagName[$iptc_record][$iptc_tagkey]) ? $IPTCrecordTagName[$iptc_record][$iptc_tagkey] : $iptc_tagkey);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,134 +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.pcd.php //
|
||||
// module for analyzing PhotoCD (PCD) Image files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_pcd extends getid3_handler
|
||||
{
|
||||
var $ExtractData = 0;
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'pcd';
|
||||
$info['video']['dataformat'] = 'pcd';
|
||||
$info['video']['lossless'] = false;
|
||||
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'] + 72, SEEK_SET);
|
||||
|
||||
$PCDflags = fread($this->getid3->fp, 1);
|
||||
$PCDisVertical = ((ord($PCDflags) & 0x01) ? true : false);
|
||||
|
||||
|
||||
if ($PCDisVertical) {
|
||||
$info['video']['resolution_x'] = 3072;
|
||||
$info['video']['resolution_y'] = 2048;
|
||||
} else {
|
||||
$info['video']['resolution_x'] = 2048;
|
||||
$info['video']['resolution_y'] = 3072;
|
||||
}
|
||||
|
||||
|
||||
if ($this->ExtractData > 3) {
|
||||
|
||||
$info['error'][] = 'Cannot extract PSD image data for detail levels above BASE (level-3) because encrypted with Kodak-proprietary compression/encryption.';
|
||||
|
||||
} elseif ($this->ExtractData > 0) {
|
||||
|
||||
$PCD_levels[1] = array( 192, 128, 0x02000); // BASE/16
|
||||
$PCD_levels[2] = array( 384, 256, 0x0B800); // BASE/4
|
||||
$PCD_levels[3] = array( 768, 512, 0x30000); // BASE
|
||||
//$PCD_levels[4] = array(1536, 1024, ??); // BASE*4 - encrypted with Kodak-proprietary compression/encryption
|
||||
//$PCD_levels[5] = array(3072, 2048, ??); // BASE*16 - encrypted with Kodak-proprietary compression/encryption
|
||||
//$PCD_levels[6] = array(6144, 4096, ??); // BASE*64 - encrypted with Kodak-proprietary compression/encryption; PhotoCD-Pro only
|
||||
|
||||
list($PCD_width, $PCD_height, $PCD_dataOffset) = $PCD_levels[3];
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'] + $PCD_dataOffset, SEEK_SET);
|
||||
|
||||
for ($y = 0; $y < $PCD_height; $y += 2) {
|
||||
// The image-data of these subtypes start at the respective offsets of 02000h, 0b800h and 30000h.
|
||||
// To decode the YcbYr to the more usual RGB-code, three lines of data have to be read, each
|
||||
// consisting of ‘w’ bytes, where ‘w’ is the width of the image-subtype. The first ‘w’ bytes and
|
||||
// the first half of the third ‘w’ bytes contain data for the first RGB-line, the second ‘w’ bytes
|
||||
// and the second half of the third ‘w’ bytes contain data for a second RGB-line.
|
||||
|
||||
$PCD_data_Y1 = fread($this->getid3->fp, $PCD_width);
|
||||
$PCD_data_Y2 = fread($this->getid3->fp, $PCD_width);
|
||||
$PCD_data_Cb = fread($this->getid3->fp, intval(round($PCD_width / 2)));
|
||||
$PCD_data_Cr = fread($this->getid3->fp, intval(round($PCD_width / 2)));
|
||||
|
||||
for ($x = 0; $x < $PCD_width; $x++) {
|
||||
if ($PCDisVertical) {
|
||||
$info['pcd']['data'][$PCD_width - $x][$y] = $this->YCbCr2RGB(ord($PCD_data_Y1{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)}));
|
||||
$info['pcd']['data'][$PCD_width - $x][$y + 1] = $this->YCbCr2RGB(ord($PCD_data_Y2{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)}));
|
||||
} else {
|
||||
$info['pcd']['data'][$y][$x] = $this->YCbCr2RGB(ord($PCD_data_Y1{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)}));
|
||||
$info['pcd']['data'][$y + 1][$x] = $this->YCbCr2RGB(ord($PCD_data_Y2{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example for plotting extracted data
|
||||
//getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
|
||||
//if ($PCDisVertical) {
|
||||
// $BMPinfo['resolution_x'] = $PCD_height;
|
||||
// $BMPinfo['resolution_y'] = $PCD_width;
|
||||
//} else {
|
||||
// $BMPinfo['resolution_x'] = $PCD_width;
|
||||
// $BMPinfo['resolution_y'] = $PCD_height;
|
||||
//}
|
||||
//$BMPinfo['bmp']['data'] = $info['pcd']['data'];
|
||||
//getid3_bmp::PlotBMP($BMPinfo);
|
||||
//exit;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function YCbCr2RGB($Y, $Cb, $Cr) {
|
||||
static $YCbCr_constants = array();
|
||||
if (empty($YCbCr_constants)) {
|
||||
$YCbCr_constants['red']['Y'] = 0.0054980 * 256;
|
||||
$YCbCr_constants['red']['Cb'] = 0.0000000 * 256;
|
||||
$YCbCr_constants['red']['Cr'] = 0.0051681 * 256;
|
||||
$YCbCr_constants['green']['Y'] = 0.0054980 * 256;
|
||||
$YCbCr_constants['green']['Cb'] = -0.0015446 * 256;
|
||||
$YCbCr_constants['green']['Cr'] = -0.0026325 * 256;
|
||||
$YCbCr_constants['blue']['Y'] = 0.0054980 * 256;
|
||||
$YCbCr_constants['blue']['Cb'] = 0.0079533 * 256;
|
||||
$YCbCr_constants['blue']['Cr'] = 0.0000000 * 256;
|
||||
}
|
||||
|
||||
$RGBcolor = array('red'=>0, 'green'=>0, 'blue'=>0);
|
||||
foreach ($RGBcolor as $rgbname => $dummy) {
|
||||
$RGBcolor[$rgbname] = max(0,
|
||||
min(255,
|
||||
intval(
|
||||
round(
|
||||
($YCbCr_constants[$rgbname]['Y'] * $Y) +
|
||||
($YCbCr_constants[$rgbname]['Cb'] * ($Cb - 156)) +
|
||||
($YCbCr_constants[$rgbname]['Cr'] * ($Cr - 137))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
return (($RGBcolor['red'] * 65536) + ($RGBcolor['green'] * 256) + $RGBcolor['blue']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,520 +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.png.php //
|
||||
// module for analyzing PNG Image files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_png extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// shortcut
|
||||
$info['png'] = array();
|
||||
$thisfile_png = &$info['png'];
|
||||
|
||||
$info['fileformat'] = 'png';
|
||||
$info['video']['dataformat'] = 'png';
|
||||
$info['video']['lossless'] = false;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$PNGfiledata = fread($this->getid3->fp, $this->getid3->fread_buffer_size());
|
||||
$offset = 0;
|
||||
|
||||
$PNGidentifier = substr($PNGfiledata, $offset, 8); // $89 $50 $4E $47 $0D $0A $1A $0A
|
||||
$offset += 8;
|
||||
|
||||
if ($PNGidentifier != "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") {
|
||||
$info['error'][] = 'First 8 bytes of file ('.getid3_lib::PrintHexBytes($PNGidentifier).') did not match expected PNG identifier';
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (((ftell($this->getid3->fp) - (strlen($PNGfiledata) - $offset)) < $info['filesize'])) {
|
||||
$chunk['data_length'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4));
|
||||
$offset += 4;
|
||||
while (((strlen($PNGfiledata) - $offset) < ($chunk['data_length'] + 4)) && (ftell($this->getid3->fp) < $info['filesize'])) {
|
||||
$PNGfiledata .= fread($this->getid3->fp, $this->getid3->fread_buffer_size());
|
||||
}
|
||||
$chunk['type_text'] = substr($PNGfiledata, $offset, 4);
|
||||
$offset += 4;
|
||||
$chunk['type_raw'] = getid3_lib::BigEndian2Int($chunk['type_text']);
|
||||
$chunk['data'] = substr($PNGfiledata, $offset, $chunk['data_length']);
|
||||
$offset += $chunk['data_length'];
|
||||
$chunk['crc'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$chunk['flags']['ancilliary'] = (bool) ($chunk['type_raw'] & 0x20000000);
|
||||
$chunk['flags']['private'] = (bool) ($chunk['type_raw'] & 0x00200000);
|
||||
$chunk['flags']['reserved'] = (bool) ($chunk['type_raw'] & 0x00002000);
|
||||
$chunk['flags']['safe_to_copy'] = (bool) ($chunk['type_raw'] & 0x00000020);
|
||||
|
||||
// shortcut
|
||||
$thisfile_png[$chunk['type_text']] = array();
|
||||
$thisfile_png_chunk_type_text = &$thisfile_png[$chunk['type_text']];
|
||||
|
||||
switch ($chunk['type_text']) {
|
||||
|
||||
case 'IHDR': // Image Header
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text['width'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4));
|
||||
$thisfile_png_chunk_type_text['height'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4));
|
||||
$thisfile_png_chunk_type_text['raw']['bit_depth'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1));
|
||||
$thisfile_png_chunk_type_text['raw']['color_type'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 9, 1));
|
||||
$thisfile_png_chunk_type_text['raw']['compression_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 10, 1));
|
||||
$thisfile_png_chunk_type_text['raw']['filter_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 11, 1));
|
||||
$thisfile_png_chunk_type_text['raw']['interlace_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 12, 1));
|
||||
|
||||
$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['raw']['compression_method']);
|
||||
$thisfile_png_chunk_type_text['color_type']['palette'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x01);
|
||||
$thisfile_png_chunk_type_text['color_type']['true_color'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x02);
|
||||
$thisfile_png_chunk_type_text['color_type']['alpha'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x04);
|
||||
|
||||
$info['video']['resolution_x'] = $thisfile_png_chunk_type_text['width'];
|
||||
$info['video']['resolution_y'] = $thisfile_png_chunk_type_text['height'];
|
||||
|
||||
$info['video']['bits_per_sample'] = $this->IHDRcalculateBitsPerSample($thisfile_png_chunk_type_text['raw']['color_type'], $thisfile_png_chunk_type_text['raw']['bit_depth']);
|
||||
break;
|
||||
|
||||
|
||||
case 'PLTE': // Palette
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$paletteoffset = 0;
|
||||
for ($i = 0; $i <= 255; $i++) {
|
||||
//$thisfile_png_chunk_type_text['red'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
|
||||
//$thisfile_png_chunk_type_text['green'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
|
||||
//$thisfile_png_chunk_type_text['blue'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
|
||||
$red = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
|
||||
$green = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
|
||||
$blue = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
|
||||
$thisfile_png_chunk_type_text[$i] = (($red << 16) | ($green << 8) | ($blue));
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'tRNS': // Transparency
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
switch ($thisfile_png['IHDR']['raw']['color_type']) {
|
||||
case 0:
|
||||
$thisfile_png_chunk_type_text['transparent_color_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2));
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$thisfile_png_chunk_type_text['transparent_color_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2));
|
||||
$thisfile_png_chunk_type_text['transparent_color_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 2));
|
||||
$thisfile_png_chunk_type_text['transparent_color_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 2));
|
||||
break;
|
||||
|
||||
case 3:
|
||||
for ($i = 0; $i < strlen($chunk['data']); $i++) {
|
||||
$thisfile_png_chunk_type_text['palette_opacity'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $i, 1));
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 6:
|
||||
$info['error'][] = 'Invalid color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type'];
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unhandled color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type'];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'gAMA': // Image Gamma
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text['gamma'] = getid3_lib::BigEndian2Int($chunk['data']) / 100000;
|
||||
break;
|
||||
|
||||
|
||||
case 'cHRM': // Primary Chromaticities
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text['white_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4)) / 100000;
|
||||
$thisfile_png_chunk_type_text['white_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4)) / 100000;
|
||||
$thisfile_png_chunk_type_text['red_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 4)) / 100000;
|
||||
$thisfile_png_chunk_type_text['red_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 12, 4)) / 100000;
|
||||
$thisfile_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 16, 4)) / 100000;
|
||||
$thisfile_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 20, 4)) / 100000;
|
||||
$thisfile_png_chunk_type_text['blue_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 24, 4)) / 100000;
|
||||
$thisfile_png_chunk_type_text['blue_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 28, 4)) / 100000;
|
||||
break;
|
||||
|
||||
|
||||
case 'sRGB': // Standard RGB Color Space
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text['reindering_intent'] = getid3_lib::BigEndian2Int($chunk['data']);
|
||||
$thisfile_png_chunk_type_text['reindering_intent_text'] = $this->PNGsRGBintentLookup($thisfile_png_chunk_type_text['reindering_intent']);
|
||||
break;
|
||||
|
||||
|
||||
case 'iCCP': // Embedded ICC Profile
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($profilename, $compressiondata) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['profile_name'] = $profilename;
|
||||
$thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($compressiondata, 0, 1));
|
||||
$thisfile_png_chunk_type_text['compression_profile'] = substr($compressiondata, 1);
|
||||
|
||||
$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
|
||||
break;
|
||||
|
||||
|
||||
case 'tEXt': // Textual Data
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($keyword, $text) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['keyword'] = $keyword;
|
||||
$thisfile_png_chunk_type_text['text'] = $text;
|
||||
|
||||
$thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
|
||||
break;
|
||||
|
||||
|
||||
case 'zTXt': // Compressed Textual Data
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($keyword, $otherdata) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['keyword'] = $keyword;
|
||||
$thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($otherdata, 0, 1));
|
||||
$thisfile_png_chunk_type_text['compressed_text'] = substr($otherdata, 1);
|
||||
$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
|
||||
switch ($thisfile_png_chunk_type_text['compression_method']) {
|
||||
case 0:
|
||||
$thisfile_png_chunk_type_text['text'] = gzuncompress($thisfile_png_chunk_type_text['compressed_text']);
|
||||
break;
|
||||
|
||||
default:
|
||||
// unknown compression method
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset($thisfile_png_chunk_type_text['text'])) {
|
||||
$thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'iTXt': // International Textual Data
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($keyword, $otherdata) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['keyword'] = $keyword;
|
||||
$thisfile_png_chunk_type_text['compression'] = (bool) getid3_lib::BigEndian2Int(substr($otherdata, 0, 1));
|
||||
$thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($otherdata, 1, 1));
|
||||
$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
|
||||
list($languagetag, $translatedkeyword, $text) = explode("\x00", substr($otherdata, 2), 3);
|
||||
$thisfile_png_chunk_type_text['language_tag'] = $languagetag;
|
||||
$thisfile_png_chunk_type_text['translated_keyword'] = $translatedkeyword;
|
||||
|
||||
if ($thisfile_png_chunk_type_text['compression']) {
|
||||
|
||||
switch ($thisfile_png_chunk_type_text['compression_method']) {
|
||||
case 0:
|
||||
$thisfile_png_chunk_type_text['text'] = gzuncompress($text);
|
||||
break;
|
||||
|
||||
default:
|
||||
// unknown compression method
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$thisfile_png_chunk_type_text['text'] = $text;
|
||||
|
||||
}
|
||||
|
||||
if (isset($thisfile_png_chunk_type_text['text'])) {
|
||||
$thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'bKGD': // Background Color
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
switch ($thisfile_png['IHDR']['raw']['color_type']) {
|
||||
case 0:
|
||||
case 4:
|
||||
$thisfile_png_chunk_type_text['background_gray'] = getid3_lib::BigEndian2Int($chunk['data']);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 6:
|
||||
$thisfile_png_chunk_type_text['background_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
|
||||
$thisfile_png_chunk_type_text['background_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
|
||||
$thisfile_png_chunk_type_text['background_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$thisfile_png_chunk_type_text['background_index'] = getid3_lib::BigEndian2Int($chunk['data']);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'pHYs': // Physical Pixel Dimensions
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text['pixels_per_unit_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4));
|
||||
$thisfile_png_chunk_type_text['pixels_per_unit_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4));
|
||||
$thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1));
|
||||
$thisfile_png_chunk_type_text['unit'] = $this->PNGpHYsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
|
||||
break;
|
||||
|
||||
|
||||
case 'sBIT': // Significant Bits
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
switch ($thisfile_png['IHDR']['raw']['color_type']) {
|
||||
case 0:
|
||||
$thisfile_png_chunk_type_text['significant_bits_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
$thisfile_png_chunk_type_text['significant_bits_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
|
||||
$thisfile_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
|
||||
$thisfile_png_chunk_type_text['significant_bits_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
$thisfile_png_chunk_type_text['significant_bits_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
|
||||
$thisfile_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
|
||||
break;
|
||||
|
||||
case 6:
|
||||
$thisfile_png_chunk_type_text['significant_bits_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
|
||||
$thisfile_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
|
||||
$thisfile_png_chunk_type_text['significant_bits_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1));
|
||||
$thisfile_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 3, 1));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'sPLT': // Suggested Palette
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($palettename, $otherdata) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['palette_name'] = $palettename;
|
||||
$sPLToffset = 0;
|
||||
$thisfile_png_chunk_type_text['sample_depth_bits'] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, 1));
|
||||
$sPLToffset += 1;
|
||||
$thisfile_png_chunk_type_text['sample_depth_bytes'] = $thisfile_png_chunk_type_text['sample_depth_bits'] / 8;
|
||||
$paletteCounter = 0;
|
||||
while ($sPLToffset < strlen($otherdata)) {
|
||||
$thisfile_png_chunk_type_text['red'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
|
||||
$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
|
||||
$thisfile_png_chunk_type_text['green'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
|
||||
$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
|
||||
$thisfile_png_chunk_type_text['blue'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
|
||||
$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
|
||||
$thisfile_png_chunk_type_text['alpha'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
|
||||
$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
|
||||
$thisfile_png_chunk_type_text['frequency'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, 2));
|
||||
$sPLToffset += 2;
|
||||
$paletteCounter++;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'hIST': // Palette Histogram
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$hISTcounter = 0;
|
||||
while ($hISTcounter < strlen($chunk['data'])) {
|
||||
$thisfile_png_chunk_type_text[$hISTcounter] = getid3_lib::BigEndian2Int(substr($chunk['data'], $hISTcounter / 2, 2));
|
||||
$hISTcounter += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'tIME': // Image Last-Modification Time
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text['year'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2));
|
||||
$thisfile_png_chunk_type_text['month'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1));
|
||||
$thisfile_png_chunk_type_text['day'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 3, 1));
|
||||
$thisfile_png_chunk_type_text['hour'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 1));
|
||||
$thisfile_png_chunk_type_text['minute'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 5, 1));
|
||||
$thisfile_png_chunk_type_text['second'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 6, 1));
|
||||
$thisfile_png_chunk_type_text['unix'] = gmmktime($thisfile_png_chunk_type_text['hour'], $thisfile_png_chunk_type_text['minute'], $thisfile_png_chunk_type_text['second'], $thisfile_png_chunk_type_text['month'], $thisfile_png_chunk_type_text['day'], $thisfile_png_chunk_type_text['year']);
|
||||
break;
|
||||
|
||||
|
||||
case 'oFFs': // Image Offset
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text['position_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4), false, true);
|
||||
$thisfile_png_chunk_type_text['position_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4), false, true);
|
||||
$thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1));
|
||||
$thisfile_png_chunk_type_text['unit'] = $this->PNGoFFsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
|
||||
break;
|
||||
|
||||
|
||||
case 'pCAL': // Calibration Of Pixel Values
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($calibrationname, $otherdata) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['calibration_name'] = $calibrationname;
|
||||
$pCALoffset = 0;
|
||||
$thisfile_png_chunk_type_text['original_zero'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 4), false, true);
|
||||
$pCALoffset += 4;
|
||||
$thisfile_png_chunk_type_text['original_max'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 4), false, true);
|
||||
$pCALoffset += 4;
|
||||
$thisfile_png_chunk_type_text['equation_type'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 1));
|
||||
$pCALoffset += 1;
|
||||
$thisfile_png_chunk_type_text['equation_type_text'] = $this->PNGpCALequationTypeLookup($thisfile_png_chunk_type_text['equation_type']);
|
||||
$thisfile_png_chunk_type_text['parameter_count'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 1));
|
||||
$pCALoffset += 1;
|
||||
$thisfile_png_chunk_type_text['parameters'] = explode("\x00", substr($chunk['data'], $pCALoffset));
|
||||
break;
|
||||
|
||||
|
||||
case 'sCAL': // Physical Scale Of Image Subject
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
|
||||
$thisfile_png_chunk_type_text['unit'] = $this->PNGsCALUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
|
||||
list($pixelwidth, $pixelheight) = explode("\x00", substr($chunk['data'], 1));
|
||||
$thisfile_png_chunk_type_text['pixel_width'] = $pixelwidth;
|
||||
$thisfile_png_chunk_type_text['pixel_height'] = $pixelheight;
|
||||
break;
|
||||
|
||||
|
||||
case 'gIFg': // GIF Graphic Control Extension
|
||||
$gIFgCounter = 0;
|
||||
if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) {
|
||||
$gIFgCounter = count($thisfile_png_chunk_type_text);
|
||||
}
|
||||
$thisfile_png_chunk_type_text[$gIFgCounter]['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text[$gIFgCounter]['disposal_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
|
||||
$thisfile_png_chunk_type_text[$gIFgCounter]['user_input_flag'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
|
||||
$thisfile_png_chunk_type_text[$gIFgCounter]['delay_time'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 2));
|
||||
break;
|
||||
|
||||
|
||||
case 'gIFx': // GIF Application Extension
|
||||
$gIFxCounter = 0;
|
||||
if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) {
|
||||
$gIFxCounter = count($thisfile_png_chunk_type_text);
|
||||
}
|
||||
$thisfile_png_chunk_type_text[$gIFxCounter]['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text[$gIFxCounter]['application_identifier'] = substr($chunk['data'], 0, 8);
|
||||
$thisfile_png_chunk_type_text[$gIFxCounter]['authentication_code'] = substr($chunk['data'], 8, 3);
|
||||
$thisfile_png_chunk_type_text[$gIFxCounter]['application_data'] = substr($chunk['data'], 11);
|
||||
break;
|
||||
|
||||
|
||||
case 'IDAT': // Image Data
|
||||
$idatinformationfieldindex = 0;
|
||||
if (isset($thisfile_png['IDAT']) && is_array($thisfile_png['IDAT'])) {
|
||||
$idatinformationfieldindex = count($thisfile_png['IDAT']);
|
||||
}
|
||||
unset($chunk['data']);
|
||||
$thisfile_png_chunk_type_text[$idatinformationfieldindex]['header'] = $chunk;
|
||||
break;
|
||||
|
||||
|
||||
case 'IEND': // Image Trailer
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
//unset($chunk['data']);
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$info['warning'][] = 'Unhandled chunk type: '.$chunk['type_text'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function PNGsRGBintentLookup($sRGB) {
|
||||
static $PNGsRGBintentLookup = array(
|
||||
0 => 'Perceptual',
|
||||
1 => 'Relative colorimetric',
|
||||
2 => 'Saturation',
|
||||
3 => 'Absolute colorimetric'
|
||||
);
|
||||
return (isset($PNGsRGBintentLookup[$sRGB]) ? $PNGsRGBintentLookup[$sRGB] : 'invalid');
|
||||
}
|
||||
|
||||
function PNGcompressionMethodLookup($compressionmethod) {
|
||||
static $PNGcompressionMethodLookup = array(
|
||||
0 => 'deflate/inflate'
|
||||
);
|
||||
return (isset($PNGcompressionMethodLookup[$compressionmethod]) ? $PNGcompressionMethodLookup[$compressionmethod] : 'invalid');
|
||||
}
|
||||
|
||||
function PNGpHYsUnitLookup($unitid) {
|
||||
static $PNGpHYsUnitLookup = array(
|
||||
0 => 'unknown',
|
||||
1 => 'meter'
|
||||
);
|
||||
return (isset($PNGpHYsUnitLookup[$unitid]) ? $PNGpHYsUnitLookup[$unitid] : 'invalid');
|
||||
}
|
||||
|
||||
function PNGoFFsUnitLookup($unitid) {
|
||||
static $PNGoFFsUnitLookup = array(
|
||||
0 => 'pixel',
|
||||
1 => 'micrometer'
|
||||
);
|
||||
return (isset($PNGoFFsUnitLookup[$unitid]) ? $PNGoFFsUnitLookup[$unitid] : 'invalid');
|
||||
}
|
||||
|
||||
function PNGpCALequationTypeLookup($equationtype) {
|
||||
static $PNGpCALequationTypeLookup = array(
|
||||
0 => 'Linear mapping',
|
||||
1 => 'Base-e exponential mapping',
|
||||
2 => 'Arbitrary-base exponential mapping',
|
||||
3 => 'Hyperbolic mapping'
|
||||
);
|
||||
return (isset($PNGpCALequationTypeLookup[$equationtype]) ? $PNGpCALequationTypeLookup[$equationtype] : 'invalid');
|
||||
}
|
||||
|
||||
function PNGsCALUnitLookup($unitid) {
|
||||
static $PNGsCALUnitLookup = array(
|
||||
0 => 'meter',
|
||||
1 => 'radian'
|
||||
);
|
||||
return (isset($PNGsCALUnitLookup[$unitid]) ? $PNGsCALUnitLookup[$unitid] : 'invalid');
|
||||
}
|
||||
|
||||
function IHDRcalculateBitsPerSample($color_type, $bit_depth) {
|
||||
switch ($color_type) {
|
||||
case 0: // Each pixel is a grayscale sample.
|
||||
return $bit_depth;
|
||||
break;
|
||||
|
||||
case 2: // Each pixel is an R,G,B triple
|
||||
return 3 * $bit_depth;
|
||||
break;
|
||||
|
||||
case 3: // Each pixel is a palette index; a PLTE chunk must appear.
|
||||
return $bit_depth;
|
||||
break;
|
||||
|
||||
case 4: // Each pixel is a grayscale sample, followed by an alpha sample.
|
||||
return 2 * $bit_depth;
|
||||
break;
|
||||
|
||||
case 6: // Each pixel is an R,G,B triple, followed by an alpha sample.
|
||||
return 4 * $bit_depth;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -1,104 +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 extends getid3_handler
|
||||
{
|
||||
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
|
||||
$SVGheader = fread($this->getid3->fp, 4096);
|
||||
if (preg_match('#\<\?xml([^\>]+)\?\>#i', $SVGheader, $matches)) {
|
||||
$info['svg']['xml']['raw'] = $matches;
|
||||
}
|
||||
if (preg_match('#\<\!DOCTYPE([^\>]+)\>#i', $SVGheader, $matches)) {
|
||||
$info['svg']['doctype']['raw'] = $matches;
|
||||
}
|
||||
if (preg_match('#\<svg([^\>]+)\>#i', $SVGheader, $matches)) {
|
||||
$info['svg']['svg']['raw'] = $matches;
|
||||
}
|
||||
if (isset($info['svg']['svg']['raw'])) {
|
||||
|
||||
$sections_to_fix = array('xml', 'doctype', 'svg');
|
||||
foreach ($sections_to_fix as $section_to_fix) {
|
||||
if (!isset($info['svg'][$section_to_fix])) {
|
||||
continue;
|
||||
}
|
||||
$section_data = array();
|
||||
while (preg_match('/ "([^"]+)"/', $info['svg'][$section_to_fix]['raw'][1], $matches)) {
|
||||
$section_data[] = $matches[1];
|
||||
$info['svg'][$section_to_fix]['raw'][1] = str_replace($matches[0], '', $info['svg'][$section_to_fix]['raw'][1]);
|
||||
}
|
||||
while (preg_match('/([^\s]+)="([^"]+)"/', $info['svg'][$section_to_fix]['raw'][1], $matches)) {
|
||||
$section_data[] = $matches[0];
|
||||
$info['svg'][$section_to_fix]['raw'][1] = str_replace($matches[0], '', $info['svg'][$section_to_fix]['raw'][1]);
|
||||
}
|
||||
$section_data = array_merge($section_data, preg_split('/[\s,]+/', $info['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] : '');
|
||||
$info['svg'][$section_to_fix]['sections'][$key] = trim($value, '"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$info['fileformat'] = 'svg';
|
||||
$info['video']['dataformat'] = 'svg';
|
||||
$info['video']['lossless'] = true;
|
||||
//$info['video']['bits_per_sample'] = 24;
|
||||
$info['video']['pixel_aspect_ratio'] = (float) 1;
|
||||
|
||||
if (!empty($info['svg']['svg']['sections']['width'])) {
|
||||
$info['svg']['width'] = intval($info['svg']['svg']['sections']['width']);
|
||||
}
|
||||
if (!empty($info['svg']['svg']['sections']['height'])) {
|
||||
$info['svg']['height'] = intval($info['svg']['svg']['sections']['height']);
|
||||
}
|
||||
if (!empty($info['svg']['svg']['sections']['version'])) {
|
||||
$info['svg']['version'] = $info['svg']['svg']['sections']['version'];
|
||||
}
|
||||
if (!isset($info['svg']['version']) && isset($info['svg']['doctype']['sections'])) {
|
||||
foreach ($info['svg']['doctype']['sections'] as $key => $value) {
|
||||
if (preg_match('#//W3C//DTD SVG ([0-9\.]+)//#i', $key, $matches)) {
|
||||
$info['svg']['version'] = $matches[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($info['svg']['width'])) {
|
||||
$info['video']['resolution_x'] = $info['svg']['width'];
|
||||
}
|
||||
if (!empty($info['svg']['height'])) {
|
||||
$info['video']['resolution_y'] = $info['svg']['height'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
$info['error'][] = 'Did not find expected <svg> tag';
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user