Merge branch 'master' of https://github.com/shish/shimmie2
This commit is contained in:
commit
cebebcd975
@ -26,7 +26,7 @@ because the feature doesn't work yet :P
|
||||
Requirements
|
||||
~~~~~~~~~~~~
|
||||
MySQL 5.1+ (with experimental support for PostgreSQL 8+ and SQLite 3)
|
||||
PHP 5.2.6+
|
||||
PHP 5.3+
|
||||
GD or ImageMagick
|
||||
|
||||
|
||||
|
||||
@ -45,9 +45,10 @@ class BaseThemelet {
|
||||
$h_tip = html_escape($image->get_tooltip());
|
||||
$h_tags = strtolower($image->get_tag_list());
|
||||
$base = get_base_href();
|
||||
$ext = strtolower($image->ext);
|
||||
|
||||
// If file is flash or svg then sets thumbnail to max size.
|
||||
if($image->ext === 'swf' || $image->ext === 'svg'){
|
||||
// If the file doesn't support thumbnail generation, show it at max size.
|
||||
if($ext === 'swf' || $ext === 'svg' || $ext === 'mp4' || $ext === 'ogv' || $ext === 'webm' || $ext === 'flv'){
|
||||
$tsize = get_thumbnail_size($config->get_int('thumb_width'), $config->get_int('thumb_height'));
|
||||
}
|
||||
else{
|
||||
|
||||
@ -214,4 +214,12 @@ class DatabaseConfig extends BaseConfig {
|
||||
$this->database->cache->delete("config");
|
||||
}
|
||||
}
|
||||
|
||||
class MockConfig extends HardcodeConfig {
|
||||
public function __construct($config=array()) {
|
||||
$config["db_version"] = "999";
|
||||
$config["anon_id"] = "0";
|
||||
parent::__construct($config);
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@ -483,6 +483,35 @@ class Database {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MockDatabase extends Database {
|
||||
var $query_id = 0;
|
||||
var $responses = array();
|
||||
var $cache = null;
|
||||
|
||||
public function __construct($responses = array()) {
|
||||
$this->cache = new NoCache();
|
||||
$this->responses = $responses;
|
||||
}
|
||||
public function execute($query, $params=array()) {
|
||||
log_debug("mock-database",
|
||||
"QUERY: " . $query .
|
||||
"\nARGS: " . var_export($params, true) .
|
||||
"\nRETURN: " . var_export($this->responses[$this->query_id], true)
|
||||
);
|
||||
return $this->responses[$this->query_id++];
|
||||
}
|
||||
|
||||
public function get_all($query, $args=array()) {return $this->execute($query, $args);}
|
||||
public function get_row($query, $args=array()) {return $this->execute($query, $args);}
|
||||
public function get_col($query, $args=array()) {return $this->execute($query, $args);}
|
||||
public function get_pairs($query, $args=array()) {return $this->execute($query, $args);}
|
||||
public function get_one($query, $args=array()) {return $this->execute($query, $args);}
|
||||
public function get_last_insert_id($seq) {return $this->query_id;}
|
||||
|
||||
public function scoreql_to_sql($sql) {return $sql;}
|
||||
public function create_table($name, $def) {}
|
||||
public function connect_engine() {}
|
||||
}
|
||||
?>
|
||||
|
||||
@ -283,4 +283,7 @@ class Page {
|
||||
$this->add_html_header("<script src='$data_href/$js_cache_file' type='text/javascript'></script>");
|
||||
}
|
||||
}
|
||||
|
||||
class MockPage extends Page {
|
||||
}
|
||||
?>
|
||||
|
||||
@ -200,4 +200,18 @@ class User {
|
||||
return (isset($_POST["auth_token"]) && $_POST["auth_token"] == $this->get_auth_token());
|
||||
}
|
||||
}
|
||||
|
||||
class MockUser extends User {
|
||||
public function __construct($name) {
|
||||
$row = array(
|
||||
"name" => $name,
|
||||
"id" => 1,
|
||||
"email" => "",
|
||||
"joindate" => "",
|
||||
"pass" => "",
|
||||
"class" => "admin",
|
||||
);
|
||||
parent::__construct($row);
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
require_once "lib/recaptchalib.php";
|
||||
require_once "lib/securimage/securimage.php";
|
||||
require_once "lib/context.php";
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
|
||||
* Input / Output Sanitising *
|
||||
@ -444,9 +445,9 @@ function captcha_get_html() {
|
||||
|
||||
$captcha = "";
|
||||
if($user->is_anonymous() && $config->get_bool("comment_captcha")) {
|
||||
$rpk = $config->get_string("api_recaptcha_privkey");
|
||||
if(!empty($rpk)) {
|
||||
$captcha = recaptcha_get_html($rpk);
|
||||
$r_publickey = $config->get_string("api_recaptcha_pubkey");
|
||||
if(!empty($r_publickey)) {
|
||||
$captcha = recaptcha_get_html($r_publickey);
|
||||
}
|
||||
else {
|
||||
session_start();
|
||||
@ -465,10 +466,10 @@ function captcha_check() {
|
||||
if(DEBUG && ip_in_range($_SERVER['REMOTE_ADDR'], "127.0.0.0/8")) return true;
|
||||
|
||||
if($user->is_anonymous() && $config->get_bool("comment_captcha")) {
|
||||
$rpk = $config->get_string('api_recaptcha_pubkey');
|
||||
if(!empty($rpk)) {
|
||||
$r_privatekey = $config->get_string('api_recaptcha_privkey');
|
||||
if(!empty($r_privatekey)) {
|
||||
$resp = recaptcha_check_answer(
|
||||
$rpk,
|
||||
$r_privatekey,
|
||||
$_SERVER["REMOTE_ADDR"],
|
||||
$_POST["recaptcha_challenge_field"],
|
||||
$_POST["recaptcha_response_field"]
|
||||
@ -509,6 +510,27 @@ function captcha_check() {
|
||||
* @return string
|
||||
*/
|
||||
function getMimeType($file, $ext="") {
|
||||
|
||||
// Static extension lookup
|
||||
$ext = strtolower($ext);
|
||||
static $exts = array(
|
||||
'jpg' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png',
|
||||
'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'ico' => 'image/x-icon',
|
||||
'swf' => 'application/x-shockwave-flash', 'pdf' => 'application/pdf',
|
||||
'zip' => 'application/zip', 'gz' => 'application/x-gzip',
|
||||
'tar' => 'application/x-tar', 'bz' => 'application/x-bzip',
|
||||
'bz2' => 'application/x-bzip2', 'txt' => 'text/plain',
|
||||
'asc' => 'text/plain', 'htm' => 'text/html', 'html' => 'text/html',
|
||||
'css' => 'text/css', 'js' => 'text/javascript',
|
||||
'xml' => 'text/xml', 'xsl' => 'application/xsl+xml',
|
||||
'ogg' => 'application/ogg', 'mp3' => 'audio/mpeg', 'wav' => 'audio/x-wav',
|
||||
'avi' => 'video/x-msvideo', 'mpg' => 'video/mpeg', 'mpeg' => 'video/mpeg',
|
||||
'mov' => 'video/quicktime', 'flv' => 'video/x-flv', 'php' => 'text/x-php',
|
||||
'mp4' => 'video/mp4', 'ogv' => 'video/ogg', 'webm' => 'video/webm'
|
||||
);
|
||||
|
||||
if (isset($exts[$ext])) { return $exts[$ext]; }
|
||||
|
||||
$type = false;
|
||||
// Fileinfo documentation says fileinfo_open() will use the
|
||||
// MAGIC env var for the magic file
|
||||
@ -530,24 +552,8 @@ function getMimeType($file, $ext="") {
|
||||
$type = trim(mime_content_type($file));
|
||||
|
||||
if ($type !== false && strlen($type) > 0) return $type;
|
||||
|
||||
// Otherwise do it the old fashioned way
|
||||
$ext = strtolower($ext);
|
||||
static $exts = array(
|
||||
'jpg' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png',
|
||||
'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'ico' => 'image/x-icon',
|
||||
'swf' => 'application/x-shockwave-flash', 'pdf' => 'application/pdf',
|
||||
'zip' => 'application/zip', 'gz' => 'application/x-gzip',
|
||||
'tar' => 'application/x-tar', 'bz' => 'application/x-bzip',
|
||||
'bz2' => 'application/x-bzip2', 'txt' => 'text/plain',
|
||||
'asc' => 'text/plain', 'htm' => 'text/html', 'html' => 'text/html',
|
||||
'css' => 'text/css', 'js' => 'text/javascript',
|
||||
'xml' => 'text/xml', 'xsl' => 'application/xsl+xml',
|
||||
'ogg' => 'application/ogg', 'mp3' => 'audio/mpeg', 'wav' => 'audio/x-wav',
|
||||
'avi' => 'video/x-msvideo', 'mpg' => 'video/mpeg', 'mpeg' => 'video/mpeg',
|
||||
'mov' => 'video/quicktime', 'flv' => 'video/x-flv', 'php' => 'text/x-php'
|
||||
);
|
||||
return isset($exts[$ext]) ? $exts[$ext] : 'application/octet-stream';
|
||||
|
||||
return 'application/octet-stream';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -895,7 +901,8 @@ define("SCORE_LOG_NOTSET", 0);
|
||||
*/
|
||||
function log_msg(/*string*/ $section, /*int*/ $priority, /*string*/ $message, $flash=null) {
|
||||
send_event(new LogEvent($section, $priority, $message));
|
||||
if(is_cli() && ($priority >= CLI_LOG_LEVEL)) {
|
||||
$threshold = defined("CLI_LOG_LEVEL") ? CLI_LOG_LEVEL : 0;
|
||||
if(is_cli() && ($priority >= $threshold)) {
|
||||
print date("c")." $section: $message\n";
|
||||
}
|
||||
if($flash === True) {
|
||||
@ -1171,6 +1178,16 @@ function _sanitise_environment() {
|
||||
error_reporting(E_ALL);
|
||||
}
|
||||
|
||||
if(CONTEXT) {
|
||||
ctx_set_log(CONTEXT);
|
||||
ctx_log_start(@$_SERVER["REQUEST_URI"], true, true);
|
||||
}
|
||||
|
||||
if(COVERAGE) {
|
||||
_start_coverage();
|
||||
register_shutdown_function("_end_coverage");
|
||||
}
|
||||
|
||||
assert_options(ASSERT_ACTIVE, 1);
|
||||
assert_options(ASSERT_BAIL, 1);
|
||||
|
||||
@ -1202,6 +1219,55 @@ function _get_themelet_files($_theme) {
|
||||
return array_merge($base_themelets, $ext_themelets, $custom_themelets);
|
||||
}
|
||||
|
||||
function _set_event_listeners($classes) {
|
||||
global $_event_listeners;
|
||||
$_event_listeners = array();
|
||||
|
||||
foreach($classes as $class) {
|
||||
$rclass = new ReflectionClass($class);
|
||||
if($rclass->isAbstract()) {
|
||||
// don't do anything
|
||||
}
|
||||
elseif(is_subclass_of($class, "Extension")) {
|
||||
$c = new $class();
|
||||
$c->i_am($c);
|
||||
$my_events = array();
|
||||
foreach(get_class_methods($c) as $method) {
|
||||
if(substr($method, 0, 2) == "on") {
|
||||
$my_events[] = substr($method, 2) . "Event";
|
||||
}
|
||||
}
|
||||
add_event_listener($c, $c->get_priority(), $my_events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _dump_event_listeners($event_listeners, $path) {
|
||||
$p = "<"."?php\n";
|
||||
|
||||
foreach(get_declared_classes() as $class) {
|
||||
$rclass = new ReflectionClass($class);
|
||||
if($rclass->isAbstract()) {}
|
||||
elseif(is_subclass_of($class, "Extension")) {
|
||||
$p .= "\$$class = new $class(); ";
|
||||
$p .= "\${$class}->i_am(\$$class);\n";
|
||||
}
|
||||
}
|
||||
|
||||
$p .= "\$_event_listeners = array(\n";
|
||||
foreach($event_listeners as $event => $listeners) {
|
||||
$p .= "\t'$event' => array(\n";
|
||||
foreach($listeners as $id => $listener) {
|
||||
$p .= "\t\t$id => \$".get_class($listener).",\n";
|
||||
}
|
||||
$p .= "\t),\n";
|
||||
}
|
||||
$p .= ");\n";
|
||||
|
||||
$p .= "?".">";
|
||||
file_put_contents($path, $p);
|
||||
}
|
||||
|
||||
function _load_extensions() {
|
||||
global $_event_listeners;
|
||||
|
||||
@ -1211,48 +1277,10 @@ function _load_extensions() {
|
||||
require_once("data/cache/event_listeners.php");
|
||||
}
|
||||
else {
|
||||
foreach(get_declared_classes() as $class) {
|
||||
$rclass = new ReflectionClass($class);
|
||||
if($rclass->isAbstract()) {
|
||||
// don't do anything
|
||||
}
|
||||
elseif(is_subclass_of($class, "Extension")) {
|
||||
$c = new $class();
|
||||
$c->i_am($c);
|
||||
$my_events = array();
|
||||
foreach(get_class_methods($c) as $method) {
|
||||
if(substr($method, 0, 2) == "on") {
|
||||
$my_events[] = substr($method, 2) . "Event";
|
||||
}
|
||||
}
|
||||
add_event_listener($c, $c->get_priority(), $my_events);
|
||||
}
|
||||
}
|
||||
_set_event_listeners(get_declared_classes());
|
||||
|
||||
if(COMPILE_ELS) {
|
||||
$p = "<"."?php\n";
|
||||
|
||||
foreach(get_declared_classes() as $class) {
|
||||
$rclass = new ReflectionClass($class);
|
||||
if($rclass->isAbstract()) {}
|
||||
elseif(is_subclass_of($class, "Extension")) {
|
||||
$p .= "\$$class = new $class(); ";
|
||||
$p .= "\${$class}->i_am(\$$class);\n";
|
||||
}
|
||||
}
|
||||
|
||||
$p .= "\$_event_listeners = array(\n";
|
||||
foreach($_event_listeners as $event => $listeners) {
|
||||
$p .= "\t'$event' => array(\n";
|
||||
foreach($listeners as $id => $listener) {
|
||||
$p .= "\t\t$id => \$".get_class($listener).",\n";
|
||||
}
|
||||
$p .= "\t),\n";
|
||||
}
|
||||
$p .= ");\n";
|
||||
|
||||
$p .= "?".">";
|
||||
file_put_contents(data_path("cache/event_listeners.php"), $p);
|
||||
_dump_event_listeners($_event_listeners, data_path("cache/event_listeners.php"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,11 +6,13 @@
|
||||
* Description: Bulk add server-side images with metadata from CSV file
|
||||
* Documentation:
|
||||
* Modification of "Bulk Add" by Shish.<br><br>
|
||||
* Adds images from a CSV with the four following values: <br>
|
||||
* "/path/to/image.jpg","space separated tags","source","rating (s, q, or e)" <br>
|
||||
* <b>e.g.</b> "/tmp/cat.png","shish oekaki","shimmie.shishnet.org/v2/post/view/3051","s" <br><br>
|
||||
* Any value but the first may be omitted, but there must be four values per line.<br>
|
||||
* <b>e.g.</b> "/why/not/try/bulk_add.jpg","","",""<br><br>
|
||||
* Adds images from a CSV with the five following values: <br>
|
||||
* "/path/to/image.jpg","spaced tags","source","rating s/q/e","/path/thumbnail.jpg" <br>
|
||||
* <b>e.g.</b> "/tmp/cat.png","shish oekaki","shimmie.shishnet.org","s","tmp/custom.jpg" <br><br>
|
||||
* Any value but the first may be omitted, but there must be five values per line.<br>
|
||||
* <b>e.g.</b> "/why/not/try/bulk_add.jpg","","","",""<br><br>
|
||||
* Image thumbnails will be displayed at the AR of the full image. Thumbnails that are
|
||||
* normally static (e.g. SWF) will be displayed at the board's max thumbnail size<br><br>
|
||||
* Useful for importing tagged images without having to do database manipulation.<br>
|
||||
* <p><b>Note:</b> requires "Admin Controls" and optionally "Image Ratings" to be enabled<br><br>
|
||||
*
|
||||
@ -53,7 +55,7 @@ class BulkAddCSV extends Extension {
|
||||
/**
|
||||
* Generate the necessary DataUploadEvent for a given image and tags.
|
||||
*/
|
||||
private function add_image($tmpname, $filename, $tags, $source, $rating) {
|
||||
private function add_image($tmpname, $filename, $tags, $source, $rating, $thumbfile) {
|
||||
assert(file_exists($tmpname));
|
||||
|
||||
$pathinfo = pathinfo($filename);
|
||||
@ -68,9 +70,14 @@ class BulkAddCSV extends Extension {
|
||||
send_event($event);
|
||||
if($event->image_id == -1) {
|
||||
throw new UploadException("File type not recognised");
|
||||
} elseif(class_exists("RatingSetEvent") && in_array($rating, array("s", "q", "e"))) {
|
||||
$ratingevent = new RatingSetEvent(Image::by_id($event->image_id), $rating);
|
||||
send_event($ratingevent);
|
||||
} else {
|
||||
if(class_exists("RatingSetEvent") && in_array($rating, array("s", "q", "e"))) {
|
||||
$ratingevent = new RatingSetEvent(Image::by_id($event->image_id), $rating);
|
||||
send_event($ratingevent);
|
||||
}
|
||||
if (file_exists($thumbfile)) {
|
||||
copy($thumbfile, warehouse_path("thumbs", $event->hash));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +98,7 @@ class BulkAddCSV extends Extension {
|
||||
$csvhandle = fopen($csvfile, "r");
|
||||
|
||||
while (($csvdata = fgetcsv($csvhandle, 0, ",")) !== FALSE) {
|
||||
if(count($csvdata) != 4) {
|
||||
if(count($csvdata) != 5) {
|
||||
if(strlen($list) > 0) {
|
||||
$this->theme->add_status("Error", "<b>Encountered malformed data. Line $linenum $csvfile</b><br>".$list);
|
||||
fclose($csvhandle);
|
||||
@ -106,12 +113,13 @@ class BulkAddCSV extends Extension {
|
||||
$tags = trim($csvdata[1]);
|
||||
$source = $csvdata[2];
|
||||
$rating = $csvdata[3];
|
||||
$thumbfile = $csvdata[4];
|
||||
$pathinfo = pathinfo($fullpath);
|
||||
$shortpath = $pathinfo["basename"];
|
||||
$list .= "<br>".html_escape("$shortpath (".str_replace(" ", ", ", $tags).")... ");
|
||||
if (file_exists($csvdata[0]) && is_file($csvdata[0])) {
|
||||
try{
|
||||
$this->add_image($fullpath, $pathinfo["basename"], $tags, $source, $rating);
|
||||
$this->add_image($fullpath, $pathinfo["basename"], $tags, $source, $rating, $thumbfile);
|
||||
$list .= "ok\n";
|
||||
}
|
||||
catch(Exception $ex) {
|
||||
|
||||
@ -178,13 +178,16 @@ class CommentList extends Extension {
|
||||
$this->build_page($page_num);
|
||||
}
|
||||
else if($event->get_arg(0) === "beta-search") {
|
||||
$i_comment_count = Comment::count_comments_by_user($user);
|
||||
$com_per_page = 50;
|
||||
$total_pages = ceil($i_comment_count/$com_per_page);
|
||||
$search = $event->get_arg(1);
|
||||
$page_num = int_escape($event->get_arg(2));
|
||||
|
||||
$page_num = $this->sanity_check_pagenumber($page_num, $total_pages);
|
||||
$duser = User::by_name($search);
|
||||
|
||||
$comments = $this->get_user_comments($duser->id, 50, ($page_num-1) * 50);
|
||||
$this->theme->display_all_user_comments($comments, $page_num, 10);
|
||||
$comments = $this->get_user_comments($duser->id, $com_per_page, ($page_num-1) * $com_per_page);
|
||||
$this->theme->display_all_user_comments($comments, $page_num, $total_pages);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -289,11 +292,11 @@ class CommentList extends Extension {
|
||||
if(class_exists("Ratings")) {
|
||||
$user_ratings = Ratings::get_user_privs($user);
|
||||
}
|
||||
|
||||
$total_pages = $database->cache->get("comment_pages");
|
||||
if(is_null($current_page) || $current_page <= 0) {
|
||||
$current_page = 1;
|
||||
}
|
||||
|
||||
$current_page = $this->sanity_check_pagenumber($current_page, $total_pages);
|
||||
$threads_per_page = 10;
|
||||
$start = $threads_per_page * ($current_page - 1);
|
||||
|
||||
@ -307,7 +310,6 @@ class CommentList extends Extension {
|
||||
";
|
||||
$result = $database->Execute($get_threads, array("limit"=>$threads_per_page, "offset"=>$start));
|
||||
|
||||
$total_pages = $database->cache->get("comment_pages");
|
||||
if(empty($total_pages)) {
|
||||
$total_pages = (int)($database->get_one("SELECT COUNT(c1) FROM (SELECT COUNT(image_id) AS c1 FROM comments $where GROUP BY image_id) AS s1") / 10);
|
||||
$database->cache->set("comment_pages", $total_pages, 600);
|
||||
@ -363,7 +365,7 @@ class CommentList extends Extension {
|
||||
LEFT JOIN users ON comments.owner_id=users.id
|
||||
WHERE users.id = :user_id
|
||||
ORDER BY comments.id DESC
|
||||
OFFSET :offset LIMIT :limit
|
||||
LIMIT :limit OFFSET :offset
|
||||
", array("user_id"=>$user_id, "offset"=>$offset, "limit"=>$count));
|
||||
$comments = array();
|
||||
foreach($rows as $row) {
|
||||
@ -474,7 +476,19 @@ class CommentList extends Extension {
|
||||
global $database;
|
||||
return ($database->get_row("SELECT * FROM comments WHERE image_id=:image_id AND comment=:comment", array("image_id"=>$image_id, "comment"=>$comment)));
|
||||
}
|
||||
|
||||
// do some checks
|
||||
private function sanity_check_pagenumber($pagenum, $maxpage){
|
||||
if (!is_numeric($pagenum)){
|
||||
$pagenum=1;
|
||||
}
|
||||
if ($pagenum>$maxpage){
|
||||
$pagenum=$maxpage;
|
||||
}
|
||||
if ($pagenum<=0){
|
||||
$pagenum=1;
|
||||
}
|
||||
return $pagenum;
|
||||
}
|
||||
private function add_comment_wrapper(/*int*/ $image_id, User $user, /*string*/ $comment) {
|
||||
global $database;
|
||||
global $config;
|
||||
|
||||
@ -36,7 +36,7 @@ class CommentListTheme extends Themelet {
|
||||
|
||||
$h_prev = ($page_number <= 1) ? "Prev" :
|
||||
'<a href="'.make_link('comment/list/'.$prev).'">Prev</a>';
|
||||
$h_index = "<a href='".make_link("comment/list")."'>Index</a>";
|
||||
$h_index = "<a href='".make_link("post/list")."'>Index</a>";
|
||||
$h_next = ($page_number >= $total_pages) ? "Next" :
|
||||
'<a href="'.make_link('comment/list/'.$next).'">Next</a>';
|
||||
|
||||
@ -171,7 +171,11 @@ class CommentListTheme extends Themelet {
|
||||
}
|
||||
|
||||
public function display_all_user_comments($comments, $page_number, $total_pages) {
|
||||
global $page;
|
||||
global $page, $user;
|
||||
|
||||
assert(is_numeric($page_number));
|
||||
assert(is_numeric($total_pages));
|
||||
|
||||
$html = "";
|
||||
foreach($comments as $comment) {
|
||||
$html .= $this->comment_to_html($comment, true);
|
||||
@ -184,19 +188,20 @@ class CommentListTheme extends Themelet {
|
||||
|
||||
$prev = $page_number - 1;
|
||||
$next = $page_number + 1;
|
||||
|
||||
$u_tags = url_escape(implode(" ", $search_terms));
|
||||
$query = empty($u_tags) ? "" : '/'.$u_tags;
|
||||
|
||||
//$search_terms = array('I','have','no','idea','what','this','does!');
|
||||
//$u_tags = url_escape(implode(" ", $search_terms));
|
||||
//$query = empty($u_tags) ? "" : '/'.$u_tags;
|
||||
|
||||
|
||||
$h_prev = ($page_number <= 1) ? "Prev" : "<a href='$prev'>Prev</a>";
|
||||
$h_index = "<a href='".make_link("post/list")."'>Index</a>";
|
||||
$h_next = ($page_number >= $total_pages) ? "Next" : "<a href='$next'>Next</a>";
|
||||
|
||||
$page->add_block(new Block("Navigation", $h_prev.' | '.$h_next, "left", 0));
|
||||
$page->add_block(new Block("Navigation", $h_prev.' | '.$h_index.' | '.$h_next, "left", 0));
|
||||
$this->display_paginator($page, 'comment/beta-search/'.$user->name, null, $page_number, $total_pages);
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected function comment_to_html($comment, $trim=false) {
|
||||
global $config, $user;
|
||||
|
||||
|
||||
@ -26,7 +26,20 @@ class MP3FileHandler extends DataHandlerExtension {
|
||||
|
||||
$image->filesize = $metadata['size'];
|
||||
$image->hash = $metadata['hash'];
|
||||
$image->filename = $metadata['filename'];
|
||||
|
||||
//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 {
|
||||
$image->filename = $metadata['filename'];
|
||||
}
|
||||
|
||||
$image->ext = $metadata['extension'];
|
||||
$image->tag_array = Tag::explode($metadata['tags']);
|
||||
$image->source = $metadata['source'];
|
||||
@ -35,8 +48,15 @@ class MP3FileHandler extends DataHandlerExtension {
|
||||
}
|
||||
|
||||
protected function check_contents($file) {
|
||||
// FIXME: mp3 magic header?
|
||||
return (file_exists($file));
|
||||
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;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
82
ext/handle_video/main.php
Normal file
82
ext/handle_video/main.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/*
|
||||
* Name: Handle Video
|
||||
* Author: velocity37 <velocity37@gmail.com>
|
||||
* License: GPLv2
|
||||
* Description: Handle FLV, MP4, OGV and WEBM video files.
|
||||
* Documentation:
|
||||
* Based heavily on "Handle MP3" by Shish.<br><br>
|
||||
* FLV: Flash player<br>
|
||||
* MP4: HTML5 with Flash fallback<br>
|
||||
* 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>
|
||||
* <a href='http://jarisflvplayer.org/'>Jaris FLV Player</a> - GPLv3 flash multimedia player.
|
||||
*/
|
||||
|
||||
class VideoFileHandler extends DataHandlerExtension {
|
||||
protected function create_thumb($hash) {
|
||||
copy("ext/handle_video/thumb.jpg", warehouse_path("thumbs", $hash));
|
||||
}
|
||||
|
||||
protected function supported_ext($ext) {
|
||||
$exts = array("flv", "mp4", "m4v", "ogv", "webm");
|
||||
return in_array(strtolower($ext), $exts);
|
||||
}
|
||||
|
||||
protected function create_image_from_data($filename, $metadata) {
|
||||
global $config;
|
||||
|
||||
$image = new Image();
|
||||
|
||||
require_once('lib/getid3/getid3/getid3.php');
|
||||
$getID3 = new getID3;
|
||||
$ThisFileInfo = $getID3->analyze($filename);
|
||||
|
||||
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']) {
|
||||
case "video/webm":
|
||||
$image->ext = "webm";
|
||||
break;
|
||||
case "video/quicktime":
|
||||
$image->ext = "mp4";
|
||||
break;
|
||||
case "application/ogg":
|
||||
$image->ext = "ogv";
|
||||
break;
|
||||
case "video/x-flv":
|
||||
$image->ext = "flv";
|
||||
break;
|
||||
}
|
||||
|
||||
$image->filesize = $metadata['size'];
|
||||
$image->hash = $metadata['hash'];
|
||||
$image->filename = $metadata['filename'];
|
||||
$image->tag_array = Tag::explode($metadata['tags']);
|
||||
$image->source = $metadata['source'];
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
protected function check_contents($file) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
?>
|
||||
37
ext/handle_video/theme.php
Normal file
37
ext/handle_video/theme.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
class VideoFileHandlerTheme extends Themelet {
|
||||
public function display_image(Page $page, Image $image) {
|
||||
$data_href = get_base_href();
|
||||
$ilink = $image->get_image_link();
|
||||
$ext = strtolower($image->get_ext());
|
||||
|
||||
if ($ext == "mp4") {
|
||||
$html = "Video not playing? <a href='" . $image->parse_link_template(make_link('image/$id/$id%20-%20$tags.$ext')) . "'>Click here</a> to download the file.<br><script language='JavaScript' type='text/javascript'>
|
||||
if( navigator.userAgent.match(/Firefox/i) ||
|
||||
navigator.userAgent.match(/Opera/i) ||
|
||||
(navigator.userAgent.match(/MSIE/i) && parseFloat(navigator.appVersion.split('MSIE')[1]) < 9)){
|
||||
document.write(\"<object data='$data_href/lib/Jaris/bin/JarisFLVPlayer.swf' id='VideoPlayer' type='application/x-shockwave-flash' height='" . strval($image->height + 1). "px' width='" . strval($image->width) . "px'><param value='#000000' name='bgcolor'><param name='allowFullScreen' value='true'><param value='high' name='quality'><param value='opaque' name='wmode'><param value='source=$ilink&type=video&streamtype=file&controltype=0' name='flashvars'></object>\");
|
||||
}
|
||||
else {
|
||||
document.write(\"<video controls='controls' autoplay='autoplay'>\");
|
||||
document.write(\"<source src='" . make_link("/image/" . $image->id) . "' type='video/mp4' />\");
|
||||
document.write(\"<object data='$data_href/lib/Jaris/bin/JarisFLVPlayer.swf' id='VideoPlayer' type='application/x-shockwave-flash' height='" . strval($image->height + 1). "px' width='" . strval($image->width) . "px'><param value='#000000' name='bgcolor'><param name='allowFullScreen' value='true'><param value='high' name='quality'><param value='opaque' name='wmode'><param value='source=$ilink&type=video&streamtype=file&controltype=0' name='flashvars'></object>\");
|
||||
}
|
||||
</script>
|
||||
<noscript>Javascript appears to be disabled. Please enable it and try again.</noscript>";
|
||||
} elseif ($ext == "flv") {
|
||||
$html = "Video not playing? <a href='" . $image->parse_link_template(make_link('image/$id/$id%20-%20$tags.$ext')) . "'>Click here</a> to download the file.<br><object data='$data_href/lib/Jaris/bin/JarisFLVPlayer.swf' id='VideoPlayer' type='application/x-shockwave-flash' height='" . strval($image->height + 1). "px' width='" . strval($image->width) . "px'><param value='#000000' name='bgcolor'><param name='allowFullScreen' value='true'><param value='high' name='quality'><param value='opaque' name='wmode'><param value='source=$ilink&type=video&streamtype=file&controltype=0' name='flashvars'></object>";
|
||||
} elseif ($ext == "ogv") {
|
||||
$html = "Video not playing? <a href='" . $image->parse_link_template(make_link('image/$id/$id%20-%20$tags.$ext')) . "'>Click here</a> to download the file.<br><video controls='controls' autoplay='autoplay'>
|
||||
<source src='" . make_link("/image/" . $image->id) . "' type='video/ogg' />
|
||||
</video>";
|
||||
} elseif ($ext == "webm") {
|
||||
$html = "Video not playing? <a href='" . $image->parse_link_template(make_link('image/$id/$id%20-%20$tags.$ext')) . "'>Click here</a> to download the file.<br><video controls='controls' autoplay='autoplay'>
|
||||
<source src='" . make_link("/image/" . $image->id) . "' type='video/webm' />
|
||||
</video>";
|
||||
}
|
||||
$page->add_block(new Block("Video", $html, "main", 10));
|
||||
}
|
||||
}
|
||||
?>
|
||||
BIN
ext/handle_video/thumb.jpg
Normal file
BIN
ext/handle_video/thumb.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.4 KiB |
@ -49,17 +49,8 @@ if(!file_exists("data/config/shimmie.conf.php")) {
|
||||
}
|
||||
require_once "core/sys_config.inc.php";
|
||||
require_once "core/util.inc.php";
|
||||
require_once "lib/context.php";
|
||||
|
||||
// set up and purify the environment
|
||||
if(CONTEXT) {
|
||||
ctx_set_log(CONTEXT);
|
||||
}
|
||||
ctx_log_start(@$_SERVER["REQUEST_URI"], true, true);
|
||||
if(COVERAGE) {
|
||||
_start_coverage();
|
||||
register_shutdown_function("_end_coverage");
|
||||
}
|
||||
_version_check();
|
||||
_sanitise_environment();
|
||||
|
||||
|
||||
55
lib/Jaris/Jaris FLV Player.hxproj
Normal file
55
lib/Jaris/Jaris FLV Player.hxproj
Normal file
@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<project version="2">
|
||||
<!-- Output SWF options -->
|
||||
<output>
|
||||
<movie outputType="Application" />
|
||||
<movie input="" />
|
||||
<movie path="bin\JarisFLVPlayer.swf" />
|
||||
<movie fps="30" />
|
||||
<movie width="800" />
|
||||
<movie height="600" />
|
||||
<movie version="10" />
|
||||
<movie minorVersion="0" />
|
||||
<movie platform="Flash Player" />
|
||||
<movie background="#FFFFFF" />
|
||||
</output>
|
||||
<!-- Other classes to be compiled into your SWF -->
|
||||
<classpaths>
|
||||
<class path="src" />
|
||||
</classpaths>
|
||||
<!-- Build options -->
|
||||
<build>
|
||||
<option directives="" />
|
||||
<option flashStrict="False" />
|
||||
<option mainClass="jaris.Main" />
|
||||
<option enabledebug="False" />
|
||||
<option additional="" />
|
||||
</build>
|
||||
<!-- haxelib libraries -->
|
||||
<haxelib>
|
||||
<!-- example: <library name="..." /> -->
|
||||
</haxelib>
|
||||
<!-- Class files to compile (other referenced classes will automatically be included) -->
|
||||
<compileTargets>
|
||||
<compile path="src\jaris\Main.hx" />
|
||||
</compileTargets>
|
||||
<!-- Assets to embed into the output SWF -->
|
||||
<library>
|
||||
<!-- example: <asset path="..." id="..." update="..." glyphs="..." mode="..." place="..." sharepoint="..." /> -->
|
||||
</library>
|
||||
<!-- Paths to exclude from the Project Explorer tree -->
|
||||
<hiddenPaths>
|
||||
<!-- example: <hidden path="..." /> -->
|
||||
</hiddenPaths>
|
||||
<!-- Executed before build -->
|
||||
<preBuildCommand />
|
||||
<!-- Executed after build -->
|
||||
<postBuildCommand alwaysRun="False" />
|
||||
<!-- Other project options -->
|
||||
<options>
|
||||
<option showHiddenPaths="True" />
|
||||
<option testMovie="Default" />
|
||||
</options>
|
||||
<!-- Plugin storage -->
|
||||
<storage />
|
||||
</project>
|
||||
BIN
lib/Jaris/bin/JarisFLVPlayer.swf
Normal file
BIN
lib/Jaris/bin/JarisFLVPlayer.swf
Normal file
Binary file not shown.
BIN
lib/Jaris/bin/expressInstall.swf
Normal file
BIN
lib/Jaris/bin/expressInstall.swf
Normal file
Binary file not shown.
126
lib/Jaris/bin/index.html
Normal file
126
lib/Jaris/bin/index.html
Normal file
@ -0,0 +1,126 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Jaris FLV Player</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="language" content="en" />
|
||||
<meta name="description" content="" />
|
||||
<meta name="keywords" content="" />
|
||||
|
||||
<script src="js/swfobject.js" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
var flashvarsVideo = {
|
||||
source: "http://jaris.sourceforge.net/files/jaris-intro.flv",
|
||||
type: "video",
|
||||
streamtype: "file",
|
||||
server: "",//Used for rtmp streams
|
||||
duration: "52",
|
||||
poster: "http://jaris.sourceforge.net/images/poster.png",
|
||||
autostart: "false",
|
||||
logo: "http://jaris.sourceforge.net/images/logo.png",
|
||||
logoposition: "top left",
|
||||
logoalpha: "30",
|
||||
logowidth: "130",
|
||||
logolink: "http://jaris.sourceforge.net",
|
||||
hardwarescaling: "false",
|
||||
darkcolor: "000000",
|
||||
brightcolor: "4c4c4c",
|
||||
controlcolor: "FFFFFF",
|
||||
hovercolor: "67A8C1"
|
||||
};
|
||||
var flashvarsVideoNewControls = {
|
||||
source: "http://jaris.sourceforge.net/files/jaris-intro.flv",
|
||||
type: "video",
|
||||
streamtype: "file",
|
||||
server: "",//Used for rtmp streams
|
||||
duration: "52",
|
||||
poster: "http://jaris.sourceforge.net/images/poster.png",
|
||||
autostart: "false",
|
||||
logo: "http://jaris.sourceforge.net/images/logo.png",
|
||||
logoposition: "top left",
|
||||
logoalpha: "30",
|
||||
logowidth: "130",
|
||||
logolink: "http://jaris.sourceforge.net",
|
||||
hardwarescaling: "false",
|
||||
darkcolor: "000000",
|
||||
brightcolor: "4c4c4c",
|
||||
controlcolor: "FFFFFF",
|
||||
hovercolor: "67A8C1",
|
||||
controltype: 1
|
||||
};
|
||||
var flashvarsAudio = {
|
||||
source: "http://jaris.sourceforge.net/files/audio.mp3",
|
||||
type: "audio",
|
||||
streamtype: "file",
|
||||
server: "",//Used for rtmp streams
|
||||
duration: "00:04:25",
|
||||
poster: "http://jaris.sourceforge.net/images/poster.png",
|
||||
autostart: "false",
|
||||
logo: "http://jaris.sourceforge.net/images/logo.png",
|
||||
logoposition: "top left",
|
||||
logoalpha: "30",
|
||||
logowidth: "130",
|
||||
logolink: "http://jaris.sourceforge.net",
|
||||
hardwarescaling: "false",
|
||||
darkcolor: "D3D3D3",
|
||||
brightcolor: "FFFFFF",
|
||||
controlcolor: "000000",
|
||||
hovercolor: "FF0000"
|
||||
};
|
||||
var params = {
|
||||
menu: "false",
|
||||
scale: "noScale",
|
||||
allowFullscreen: "true",
|
||||
allowScriptAccess: "always",
|
||||
bgcolor: "#000000",
|
||||
quality: "high",
|
||||
wmode: "opaque"
|
||||
};
|
||||
var attributes = {
|
||||
id:"JarisFLVPlayer"
|
||||
};
|
||||
swfobject.embedSWF("JarisFLVPlayer.swf", "altContentOne", "576px", "360px", "10.0.0", "expressInstall.swf", flashvarsVideo, params, attributes);
|
||||
swfobject.embedSWF("JarisFLVPlayer.swf", "altContentOneNewControls", "576px", "360px", "10.0.0", "expressInstall.swf", flashvarsVideoNewControls, params, attributes);
|
||||
swfobject.embedSWF("JarisFLVPlayer.swf", "altContentTwo", "576px", "360px", "10.0.0", "expressInstall.swf", flashvarsAudio, params, attributes);
|
||||
</script>
|
||||
<style>
|
||||
html, body { height:100%; }
|
||||
body { margin:0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<br />
|
||||
<center>
|
||||
<h1>Video Example</h1>
|
||||
<div id="altContentOne">
|
||||
<h1>Jaris FLV Player</h1>
|
||||
<p>Alternative content</p>
|
||||
<p><a href="http://www.adobe.com/go/getflashplayer"><img
|
||||
src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif"
|
||||
alt="Get Adobe Flash player" /></a></p>
|
||||
</div>
|
||||
|
||||
<br /><br />
|
||||
|
||||
<h1>Video Example with New Controls</h1>
|
||||
<div id="altContentOneNewControls">
|
||||
<h1>Jaris FLV Player</h1>
|
||||
<p>Alternative content</p>
|
||||
<p><a href="http://www.adobe.com/go/getflashplayer"><img
|
||||
src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif"
|
||||
alt="Get Adobe Flash player" /></a></p>
|
||||
</div>
|
||||
|
||||
<br /><br />
|
||||
|
||||
<h1>Audio Example</h1>
|
||||
<div id="altContentTwo">
|
||||
<h1>Jaris FLV Player</h1>
|
||||
<p>Alternative content</p>
|
||||
<p><a href="http://www.adobe.com/go/getflashplayer"><img
|
||||
src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif"
|
||||
alt="Get Adobe Flash player" /></a></p>
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
</html>
|
||||
98
lib/Jaris/bin/jarisflvplayer.js
Normal file
98
lib/Jaris/bin/jarisflvplayer.js
Normal file
@ -0,0 +1,98 @@
|
||||
/**
|
||||
* @author Jefferson Gonzalez
|
||||
* @copyright 2010 Jefferson Gonzalez
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
*Interface for the JarisFLVPlayer JavaScript API implemented
|
||||
*by Sascha from http://projekktor.com/
|
||||
*@param id The id of the flash object
|
||||
*/
|
||||
function JarisFLVPlayer(id){
|
||||
|
||||
this.playerId = id; //Stores the id of the player
|
||||
this.player = document.getElementById(id); //Object that points to the player
|
||||
}
|
||||
|
||||
//Event constants
|
||||
JarisFLVPlayer.event = {
|
||||
MOUSE_HIDE: "onMouseHide",
|
||||
MOUSE_SHOW: "onMouseShow",
|
||||
MEDIA_INITIALIZED: "onDataInitialized",
|
||||
BUFFERING: "onBuffering",
|
||||
NOT_BUFFERING: "onNotBuffering",
|
||||
RESIZE: "onResize",
|
||||
PLAY_PAUSE: "onPlayPause",
|
||||
PLAYBACK_FINISHED: "onPlaybackFinished",
|
||||
CONNECTION_FAILED: "onConnectionFailed",
|
||||
ASPECT_RATIO: "onAspectRatio",
|
||||
VOLUME_UP: "onVolumeUp",
|
||||
VOLUME_DOWN: "onVolumeDown",
|
||||
VOLUME_CHANGE: "onVolumeChange",
|
||||
MUTE: "onMute",
|
||||
TIME: "onTimeUpdate",
|
||||
PROGRESS: "onProgress",
|
||||
SEEK: "onSeek",
|
||||
ON_ALL: "on*"
|
||||
};
|
||||
|
||||
JarisFLVPlayer.prototype.isBuffering = function(){
|
||||
return this.player.api_get("isBuffering");
|
||||
}
|
||||
|
||||
JarisFLVPlayer.prototype.isPlaying = function(){
|
||||
return this.player.api_get("isPlaying");
|
||||
}
|
||||
|
||||
JarisFLVPlayer.prototype.getCurrentTime = function(){
|
||||
return this.player.api_get("time");
|
||||
}
|
||||
|
||||
JarisFLVPlayer.prototype.getBytesLoaded = function(){
|
||||
return this.player.api_get("loaded");
|
||||
}
|
||||
|
||||
JarisFLVPlayer.prototype.getVolume = function(){
|
||||
return this.player.api_get("volume");
|
||||
}
|
||||
|
||||
JarisFLVPlayer.prototype.addListener = function(event, listener){
|
||||
this.player.api_addlistener(event, listener);
|
||||
}
|
||||
|
||||
JarisFLVPlayer.prototype.removeListener = function(event){
|
||||
this.player.api_removelistener(event);
|
||||
}
|
||||
|
||||
JarisFLVPlayer.prototype.play = function(){
|
||||
this.player.api_play();
|
||||
}
|
||||
|
||||
JarisFLVPlayer.prototype.pause = function(){
|
||||
this.player.api_pause();
|
||||
}
|
||||
|
||||
JarisFLVPlayer.prototype.seek = function(seconds){
|
||||
this.player.api_seek(seconds);
|
||||
}
|
||||
|
||||
JarisFLVPlayer.prototype.volume = function(value){
|
||||
this.player.api_volume(value);
|
||||
}
|
||||
4
lib/Jaris/bin/js/swfobject.js
Normal file
4
lib/Jaris/bin/js/swfobject.js
Normal file
File diff suppressed because one or more lines are too long
BIN
lib/Jaris/bin/logo-color.png
Normal file
BIN
lib/Jaris/bin/logo-color.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
lib/Jaris/bin/logo.png
Normal file
BIN
lib/Jaris/bin/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
BIN
lib/Jaris/bin/poster.png
Normal file
BIN
lib/Jaris/bin/poster.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
118
lib/Jaris/changes.txt
Normal file
118
lib/Jaris/changes.txt
Normal file
@ -0,0 +1,118 @@
|
||||
Jaris FLV Player v2.0.15 beta - 27/08/2011
|
||||
|
||||
* New player controls
|
||||
* New flashvar controltype (0=old, 1=new) to indicate the which controls to use
|
||||
* New flashvar controlsize for new controls only
|
||||
* New flashvar seekcolor for new controls only
|
||||
* New flashvar buffertime to change the default 10 seconds buffer time for local/pseudo streaming
|
||||
* Bugfix on loader bar
|
||||
* All this changes thanks to Istvan Petres from http://jcore.net
|
||||
|
||||
Jaris FLV Player v2.0.14 beta - 20/05/2011
|
||||
|
||||
* Removed some trace calls on youtube playback.
|
||||
|
||||
Jaris FLV Player v2.0.13 beta - 6/03/2011
|
||||
|
||||
* Implemented loop class
|
||||
* Added loop functionality by passing loop=true or loop=1 as parameter
|
||||
* Fixed reported bug "slider will show wrong position" on pseudostreaming seek (Thanks to Adam)
|
||||
|
||||
Jaris FLV Player v2.0.12 beta - 06/11/2010
|
||||
|
||||
* Java Script Api to listen for events and control the player.
|
||||
* More player events added to use on JSApi.
|
||||
* All this changes thanks to Sascha Kluger from http://projekktor.com
|
||||
|
||||
Jaris FLV Player v2.0.11 beta - 03/10/2010
|
||||
|
||||
* Removed togglePlay of onFullscreen event since it seems that new flash versions doesnt emits
|
||||
the space keydown anymore that affected playback on fullcreen switching.
|
||||
* Added class to store user settings as volume and aspect ratio to load them next time player is load.
|
||||
|
||||
Jaris FLV Player v2.0.10 beta - 29/09/2010
|
||||
|
||||
* Added flashvar aspectratio option to initially tell on wich aspect ratio to play the video
|
||||
|
||||
Jaris FLV Player v2.0.9 beta - 26/05/2010
|
||||
|
||||
* Improved poster to keep aspect ratio and display back when playback finishes
|
||||
|
||||
Jaris FLV Player v2.0.8 beta - 14/05/2010
|
||||
|
||||
* Fixed bug on formatTime function calculating hours as minutes
|
||||
|
||||
Jaris FLV Player v2.0.7 beta - 03/19/2010
|
||||
|
||||
* Fixed youtube security bug
|
||||
|
||||
Jaris FLV Player v2.0.6 beta - 03/13/2010
|
||||
|
||||
* Added: display current aspect ratio label on aspect ratio toggle
|
||||
* Improved readability of text
|
||||
* only attach netstream to video object if input type is video
|
||||
* remove poster from player code
|
||||
|
||||
Jaris FLV Player v2.0.5 beta - 03/12/2010
|
||||
|
||||
* Improved aspect ratio toogle when video aspect ratio is already on the aspect ratios list
|
||||
* Fixed context menu aspect ratio rotation
|
||||
|
||||
Jaris FLV Player v2.0.4 beta - 03/11/2010
|
||||
|
||||
* Fixed a drawing issue where seek bar after fullscreen stayed long
|
||||
* Documented other parts of the code
|
||||
|
||||
Jaris FLV Player v2.0.3 beta - 03/10/2010
|
||||
|
||||
* Support for rtmp streaming
|
||||
* support for youtube
|
||||
* better support for http streaming like lighttpd
|
||||
* Fixed calculation of width on original aspect ratio larger than stage
|
||||
* And many hours of improvements
|
||||
|
||||
Jaris FLV Player v2.0.2 beta - 03/09/2010
|
||||
|
||||
* Implement EventDispatcher on Player class instead of using custom event mechanism
|
||||
* Fixed not getting initial stage widht and height on IE when using swfobjects
|
||||
* Some more improvements to controls on short heights
|
||||
* Other improvements and code refactoring
|
||||
* added id3 info to player events
|
||||
|
||||
Jaris FLV Player v2.0.1 beta - 03/08/2010
|
||||
|
||||
* Toggle Quality on Context Menu
|
||||
* Introduction of type parameter
|
||||
* Initial mp3 support
|
||||
* Loader fixes
|
||||
* Controls fixes
|
||||
* Other refinements and fixes
|
||||
* Duration parameter to indicate how much total time takes input media
|
||||
|
||||
Jaris FLV Player v2.0.0 beta - 03/05/2010
|
||||
|
||||
* Moved from swishmax 2 to haxe and flashdevelop
|
||||
* New GUI completely written in haxe (AS3)
|
||||
* Hide controls on fullscreen
|
||||
* Recalculate aspect ratio on fullscreen.
|
||||
* Redraw controls on fullscreen and normal switching.
|
||||
* Initial pseudo streaming support
|
||||
* Compiled to flash 10
|
||||
* Now uses as3 libraries
|
||||
* Optional Hardware scaling
|
||||
* Video smoothing enabled by default
|
||||
* Added custom context menu
|
||||
* Other refinements and fixes
|
||||
|
||||
Jaris FLV Player v1.0 - 05/21/2008
|
||||
|
||||
* Calculates video aspect ratio on player load.
|
||||
* Support Flash 9 Stage.displayState (Fullscreen mode).
|
||||
* Support for preview image of the video.
|
||||
* Display buffering message.
|
||||
* Internal volume control.
|
||||
* Back and forward control.
|
||||
* Display the actual playing time and total time.
|
||||
* Support for logo image on the fly.
|
||||
* Flag to autostart the video on player load.
|
||||
|
||||
157
lib/Jaris/documentation.txt
Normal file
157
lib/Jaris/documentation.txt
Normal file
@ -0,0 +1,157 @@
|
||||
==================
|
||||
How To!
|
||||
==================
|
||||
|
||||
The above example is one of the ways to embed the player to your html files. Just copy and paste.
|
||||
|
||||
---------------------------------------Code------------------------------------------
|
||||
<object
|
||||
classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
|
||||
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,0,45,2"
|
||||
width="640" height="360"
|
||||
>
|
||||
<param name="allowFullscreen" value="true">
|
||||
<param name="allowScriptAccess" value="always">
|
||||
<param name="movie" value="JarisFLVPlayer.swf">
|
||||
<param name="bgcolor" value="#000000">
|
||||
<param name="quality" value="high">
|
||||
<param name="scale" value="noscale">
|
||||
<param name="wmode" value="opaque">
|
||||
<param name="flashvars" value="source=jaris-intro.mp4&type=video&streamtype=file&poster=poster.png&autostart=false&logo=logo.png&logoposition=top left&logoalpha=30&logowidth=130&logolink=http://jaris.sourceforge.net&hardwarescaling=false&darkcolor=000000&brightcolor=4c4c4c&controlcolor=FFFFFF&hovercolor=67A8C1">
|
||||
<param name="seamlesstabbing" value="false">
|
||||
<embed
|
||||
type="application/x-shockwave-flash"
|
||||
pluginspage="http://www.adobe.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"
|
||||
width="640" height="360"
|
||||
src="JarisFLVPlayer.swf"
|
||||
allowfullscreen="true"
|
||||
allowscriptaccess="always"
|
||||
bgcolor="#000000"
|
||||
quality="high"
|
||||
scale="noscale"
|
||||
wmode="opaque"
|
||||
flashvars="source=jaris-intro.mp4&type=video&streamtype=file&poster=poster.png&autostart=false&logo=logo.png&logoposition=top left&logoalpha=30&logowidth=130&logolink=http://jaris.sourceforge.net&hardwarescaling=false&darkcolor=000000&brightcolor=4c4c4c&controlcolor=FFFFFF&hovercolor=67A8C1"
|
||||
seamlesstabbing="false"
|
||||
>
|
||||
<noembed>
|
||||
</noembed>
|
||||
</embed>
|
||||
</object>
|
||||
--------------------------------------End-Code---------------------------------------
|
||||
|
||||
==================
|
||||
Flash Variables
|
||||
==================
|
||||
|
||||
Here is the list of variables that you can pass to the player.
|
||||
|
||||
* source:
|
||||
This is the actual path of the media that is going to be played.
|
||||
|
||||
* type:
|
||||
The type of file to play, allowable values are: audio, video.
|
||||
|
||||
* streamtype:
|
||||
The stream type of the file, allowable values are: file, http, rmtp, youtube.
|
||||
|
||||
* server:
|
||||
Used in coordination with rtmp stream servers
|
||||
|
||||
* duration:
|
||||
Total times in seconds for input media or formatted string in the format hh:mm:ss
|
||||
|
||||
* poster:
|
||||
Screenshot of the video that is displayed before playing in png, jpg or gif format.
|
||||
|
||||
* autostart:
|
||||
A true or false value that indicates to the player if it should auto play the video on load.
|
||||
|
||||
* logo:
|
||||
The path to the image of your logo.
|
||||
|
||||
* logoposition:
|
||||
The position of the logo in the player, permitted values are: top left, top right, bottom left and bottom right
|
||||
|
||||
* logoalpha:
|
||||
The transparency percent. values permitted 0 to 100, while more higher the vale less transparency is applied.
|
||||
|
||||
* logowidth:
|
||||
The width in pixels of the logo.
|
||||
|
||||
* logolink:
|
||||
A link to a webpage when the logo is clicked.
|
||||
|
||||
* hardwarescaling:
|
||||
Enable or disable hardware scaling on fullscreen mode, values: false or true
|
||||
|
||||
* logoalpha:
|
||||
The transparency percent. values permitted 1 to 100
|
||||
|
||||
* controls:
|
||||
To disable the displaying of controls, values: false to hide otherwise defaults to show
|
||||
|
||||
* controltype
|
||||
Choose which controls to displa. 0 = old controls, 1 = new controls
|
||||
|
||||
* controlsize
|
||||
Changes the height of the new controllers, the default value is 40
|
||||
|
||||
* seekcolor
|
||||
Change the seekbar color (new controls only)
|
||||
|
||||
* darkcolor:
|
||||
The darker color of player controls in html hexadecimal format
|
||||
|
||||
* brightcolor:
|
||||
The bright color of player controls in html hexadecimal format
|
||||
|
||||
* controlcolor:
|
||||
The face color of controls in html hexadecimal format
|
||||
|
||||
* hovercolor:
|
||||
On mouse hover color for controls in html hexadecimal format
|
||||
|
||||
* aspectratio:
|
||||
To override original aspect ratio on first time player load. Allowable values: 1:1, 3:2, 4:3, 5:4, 14:9, 14:10, 16:9, 16:10
|
||||
|
||||
* jsapi:
|
||||
Expose events to javascript functions and enable controlling the player from the outside. Set to any value to enable.
|
||||
|
||||
* loop:
|
||||
As the variable says this keeps looping the video. Set to any value to enable.
|
||||
|
||||
* buffertime
|
||||
To change the default 10 seconds buffer time for local/pseudo streaming
|
||||
|
||||
==================
|
||||
Keyboard Shortcuts
|
||||
==================
|
||||
|
||||
Here is the list of keyboard shortcuts to control Jaris Player.
|
||||
|
||||
* SPACE
|
||||
Play or pause video.
|
||||
|
||||
* TAB
|
||||
Switch between different aspect ratios.
|
||||
|
||||
* UP
|
||||
Raise volume
|
||||
|
||||
* DOWN
|
||||
Lower volume
|
||||
|
||||
* LEFT
|
||||
Rewind
|
||||
|
||||
* RIGHT
|
||||
Forward
|
||||
|
||||
* M
|
||||
Mute or unmute volume.
|
||||
|
||||
* F
|
||||
Swtich to fullscreen mode.
|
||||
|
||||
* X
|
||||
Stops and close current stream
|
||||
789
lib/Jaris/license.txt
Normal file
789
lib/Jaris/license.txt
Normal file
@ -0,0 +1,789 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
52
lib/Jaris/readme.txt
Normal file
52
lib/Jaris/readme.txt
Normal file
@ -0,0 +1,52 @@
|
||||
==================
|
||||
Jaris FLV Player
|
||||
==================
|
||||
A flash flv player made using haxe and flash develop that can be embedded into any website
|
||||
for free or commercial use.
|
||||
|
||||
Web Page: http://jaris.sourceforge.net/
|
||||
Project Page: https://sourceforge.net/projects/jaris/
|
||||
|
||||
==================
|
||||
Be Free!
|
||||
==================
|
||||
|
||||
Searching for an flv player that could be used freely in all aspects and open source was
|
||||
a hard job. So I just decided to work on a basic player that had the most important
|
||||
features found in others players.
|
||||
|
||||
Thats the story of how Jaris was born.
|
||||
|
||||
==================
|
||||
Features
|
||||
==================
|
||||
|
||||
|
||||
* Aspect ratio switcher
|
||||
* Fullscreen support
|
||||
* Http pseudostreaming support
|
||||
* Poster image
|
||||
* Volume control
|
||||
* Seek control
|
||||
* Display time
|
||||
* Use your own logo
|
||||
* Add a link to your logo
|
||||
* Change position of logo
|
||||
* Hide controls on fullscreen
|
||||
* Custom control colors
|
||||
* Hardware scaling
|
||||
* Keyboard shortcuts
|
||||
* Mp3 support
|
||||
|
||||
|
||||
==================
|
||||
License
|
||||
==================
|
||||
|
||||
Jaris is licensed under GPL and LGPL, meaning that you could use it commercially.
|
||||
What we ask for is that any improvements made to the player should be taken back to jaris flv website
|
||||
so that any one could enjoy the new improvements or features also. In this way everyone could
|
||||
help to maintain an up to date tool that adapts to todays multimedia demands.
|
||||
Using sourceforge.net you could send a patch http://sourceforge.net/projects/jaris/.
|
||||
|
||||
Enjoy a totally free player ;-)
|
||||
204
lib/Jaris/src/jaris/Main.hx
Normal file
204
lib/Jaris/src/jaris/Main.hx
Normal file
@ -0,0 +1,204 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
package jaris;
|
||||
|
||||
import flash.display.MovieClip;
|
||||
import flash.display.Stage;
|
||||
import flash.display.StageAlign;
|
||||
import flash.display.StageScaleMode;
|
||||
import flash.Lib;
|
||||
import flash.system.Capabilities;
|
||||
import jaris.display.Logo;
|
||||
import jaris.display.Menu;
|
||||
import jaris.display.Poster;
|
||||
import jaris.player.controls.Controls;
|
||||
import jaris.player.newcontrols.NewControls;
|
||||
import jaris.player.JsApi;
|
||||
import jaris.player.InputType;
|
||||
import jaris.player.Player;
|
||||
import jaris.player.StreamType;
|
||||
import jaris.player.AspectRatio;
|
||||
import jaris.player.UserSettings;
|
||||
import jaris.player.Loop;
|
||||
|
||||
/**
|
||||
* Main jaris player starting point
|
||||
*/
|
||||
class Main
|
||||
{
|
||||
static var stage:Stage;
|
||||
static var movieClip:MovieClip;
|
||||
|
||||
static function main():Void
|
||||
{
|
||||
//Initialize stage and main movie clip
|
||||
stage = Lib.current.stage;
|
||||
movieClip = Lib.current;
|
||||
|
||||
stage.scaleMode = StageScaleMode.NO_SCALE;
|
||||
stage.align = StageAlign.TOP_LEFT;
|
||||
|
||||
//Retrieve user settings
|
||||
var userSettings:UserSettings = new UserSettings();
|
||||
|
||||
//Reads flash vars
|
||||
var parameters:Dynamic<String> = flash.Lib.current.loaderInfo.parameters;
|
||||
|
||||
//Initialize and draw player object
|
||||
var player:Player = new Player();
|
||||
if (Capabilities.playerType == "PlugIn" || Capabilities.playerType == "ActiveX")
|
||||
{
|
||||
var autoStart:Bool = parameters.autostart == "true" || parameters.autostart == "" || parameters.autostart == null? true: false;
|
||||
var type:String = parameters.type != "" && parameters.type != null? parameters.type : InputType.VIDEO;
|
||||
var streamType:String = parameters.streamtype != "" && parameters.streamtype != null? parameters.streamtype : StreamType.FILE;
|
||||
var server:String = parameters.server != "" && parameters.server != null? parameters.server : "";
|
||||
var aspectRatio:String = parameters.aspectratio != "" && parameters.aspectratio != null? parameters.aspectratio : "";
|
||||
var bufferTime:Float = parameters.buffertime != "" && parameters.buffertime != null? Std.parseFloat(parameters.buffertime) : 0;
|
||||
|
||||
if (aspectRatio != "" && !userSettings.isSet("aspectratio"))
|
||||
{
|
||||
switch(aspectRatio)
|
||||
{
|
||||
case "1:1":
|
||||
player.setAspectRatio(AspectRatio._1_1);
|
||||
case "3:2":
|
||||
player.setAspectRatio(AspectRatio._3_2);
|
||||
case "4:3":
|
||||
player.setAspectRatio(AspectRatio._4_3);
|
||||
case "5:4":
|
||||
player.setAspectRatio(AspectRatio._5_4);
|
||||
case "14:9":
|
||||
player.setAspectRatio(AspectRatio._14_9);
|
||||
case "14:10":
|
||||
player.setAspectRatio(AspectRatio._14_10);
|
||||
case "16:9":
|
||||
player.setAspectRatio(AspectRatio._16_9);
|
||||
case "16:10":
|
||||
player.setAspectRatio(AspectRatio._16_10);
|
||||
}
|
||||
}
|
||||
else if(userSettings.isSet("aspectratio"))
|
||||
{
|
||||
player.setAspectRatio(userSettings.getAspectRatio());
|
||||
}
|
||||
|
||||
player.setType(type);
|
||||
player.setStreamType(streamType);
|
||||
player.setServer(server);
|
||||
player.setVolume(userSettings.getVolume());
|
||||
player.setBufferTime(bufferTime);
|
||||
|
||||
if (autoStart)
|
||||
{
|
||||
player.load(parameters.source, type, streamType, server);
|
||||
}
|
||||
else
|
||||
{
|
||||
player.setSource(parameters.source);
|
||||
}
|
||||
|
||||
player.setHardwareScaling(parameters.hardwarescaling=="true"?true:false);
|
||||
}
|
||||
else
|
||||
{
|
||||
//For development purposes
|
||||
if(userSettings.isSet("aspectratio"))
|
||||
{
|
||||
player.setAspectRatio(userSettings.getAspectRatio());
|
||||
}
|
||||
|
||||
player.setVolume(userSettings.getVolume());
|
||||
|
||||
player.load("http://jaris.sourceforge.net/files/jaris-intro.flv", InputType.VIDEO, StreamType.FILE);
|
||||
//player.load("http://jaris.sourceforge.net/files/audio.mp3", InputType.AUDIO, StreamType.FILE);
|
||||
}
|
||||
|
||||
//Draw preview image
|
||||
if (parameters.poster != null)
|
||||
{
|
||||
var poster:String = parameters.poster;
|
||||
var posterImage = new Poster(poster);
|
||||
posterImage.setPlayer(player);
|
||||
movieClip.addChild(posterImage);
|
||||
}
|
||||
|
||||
//Modify Context Menu
|
||||
var menu:Menu = new Menu(player);
|
||||
|
||||
//Draw logo
|
||||
if (parameters.logo!=null)
|
||||
{
|
||||
var logoSource:String = parameters.logo != null ? parameters.logo : "logo.png";
|
||||
var logoPosition:String = parameters.logoposition != null ? parameters.logoposition : "top left";
|
||||
var logoAlpha:Float = parameters.logoalpha != null ? Std.parseFloat(parameters.logoalpha) / 100 : 0.3;
|
||||
var logoWidth:Float = parameters.logowidth != null ? Std.parseFloat(parameters.logowidth) : 130;
|
||||
var logoLink:String = parameters.logolink != null ? parameters.logolink : "http://jaris.sourceforge.net";
|
||||
|
||||
var logo:Logo = new Logo(logoSource, logoPosition, logoAlpha, logoWidth);
|
||||
logo.setLink(logoLink);
|
||||
movieClip.addChild(logo);
|
||||
}
|
||||
|
||||
//Draw Controls
|
||||
if (parameters.controls != "false")
|
||||
{
|
||||
var duration:String = parameters.duration != "" && parameters.duration != null? parameters.duration : "0";
|
||||
var controlType:Int = parameters.controltype != "" && parameters.controltype != null? Std.parseInt(parameters.controltype) : 0;
|
||||
var controlSize:Int = parameters.controlsize != "" && parameters.controlsize != null? Std.parseInt(parameters.controlsize) : 0;
|
||||
|
||||
var controlColors:Array <String> = ["", "", "", "", ""];
|
||||
controlColors[0] = parameters.darkcolor != null ? parameters.darkcolor : "";
|
||||
controlColors[1] = parameters.brightcolor != null ? parameters.brightcolor : "";
|
||||
controlColors[2] = parameters.controlcolor != null ? parameters.controlcolor : "";
|
||||
controlColors[3] = parameters.hovercolor != null ? parameters.hovercolor : "";
|
||||
controlColors[4] = parameters.seekcolor != null ? parameters.seekcolor : "";
|
||||
|
||||
if (controlType == 1) {
|
||||
var controls:NewControls = new NewControls(player);
|
||||
controls.setDurationLabel(duration);
|
||||
controls.setControlColors(controlColors);
|
||||
controls.setControlSize(controlSize);
|
||||
movieClip.addChild(controls);
|
||||
} else {
|
||||
var controls:Controls = new Controls(player);
|
||||
controls.setDurationLabel(duration);
|
||||
controls.setControlColors(controlColors);
|
||||
movieClip.addChild(controls);
|
||||
}
|
||||
}
|
||||
|
||||
//Loop the video
|
||||
if (parameters.loop != null)
|
||||
{
|
||||
var loop:Loop = new Loop(player);
|
||||
}
|
||||
|
||||
//Expose events to javascript functions and enable controlling the player from the outside
|
||||
if (parameters.jsapi != null)
|
||||
{
|
||||
var jsAPI:JsApi = new JsApi(player);
|
||||
movieClip.addChild(jsAPI);
|
||||
}
|
||||
}
|
||||
}
|
||||
35
lib/Jaris/src/jaris/Version.hx
Normal file
35
lib/Jaris/src/jaris/Version.hx
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris;
|
||||
|
||||
/**
|
||||
* Actual jaris flv player version and date
|
||||
*/
|
||||
class Version
|
||||
{
|
||||
public static var NUMBER:String = "2.0.15";
|
||||
public static var STATUS:String = "beta";
|
||||
public static var DATE:String = "27";
|
||||
public static var MONTH:String = "08";
|
||||
public static var YEAR:String = "2011";
|
||||
}
|
||||
77
lib/Jaris/src/jaris/animation/Animation.hx
Normal file
77
lib/Jaris/src/jaris/animation/Animation.hx
Normal file
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.animation;
|
||||
|
||||
/**
|
||||
* Gives quick access usage to jaris animations
|
||||
*/
|
||||
class Animation
|
||||
{
|
||||
|
||||
/**
|
||||
* Quick access to fade in effect
|
||||
* @param object the object to animate
|
||||
* @param seconds the duration of the animation
|
||||
*/
|
||||
public static function fadeIn(object:Dynamic, seconds:Float):Void
|
||||
{
|
||||
var animation:AnimationsBase = new AnimationsBase();
|
||||
animation.fadeIn(object, seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick access to fade out effect
|
||||
* @param object the object to animate
|
||||
* @param seconds the duration of the animation
|
||||
*/
|
||||
public static function fadeOut(object:Dynamic, seconds:Float):Void
|
||||
{
|
||||
var animation:AnimationsBase = new AnimationsBase();
|
||||
animation.fadeOut(object, seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick access to slide in effect
|
||||
* @param object the object to animate
|
||||
* @param position could be top, left, bottom or right
|
||||
* @param seconds the duration of the animation
|
||||
*/
|
||||
public static function slideIn(object:Dynamic, position:String, seconds:Float):Void
|
||||
{
|
||||
var animation:AnimationsBase = new AnimationsBase();
|
||||
animation.slideIn(object, position, seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick access to slide out effect
|
||||
* @param object the object to animate
|
||||
* @param position could be top, left, bottom or right
|
||||
* @param seconds the duration of the animation
|
||||
*/
|
||||
public static function slideOut(object:Dynamic, position:String, seconds:Float):Void
|
||||
{
|
||||
var animation:AnimationsBase = new AnimationsBase();
|
||||
animation.slideOut(object, position, seconds);
|
||||
}
|
||||
|
||||
}
|
||||
306
lib/Jaris/src/jaris/animation/AnimationsBase.hx
Normal file
306
lib/Jaris/src/jaris/animation/AnimationsBase.hx
Normal file
@ -0,0 +1,306 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.animation;
|
||||
|
||||
import flash.display.MovieClip;
|
||||
import flash.display.Stage;
|
||||
import flash.events.TimerEvent;
|
||||
import flash.Lib;
|
||||
import flash.utils.Timer;
|
||||
|
||||
/**
|
||||
* Jaris main animations
|
||||
*/
|
||||
class AnimationsBase
|
||||
{
|
||||
private var _fadeInTimer:Timer;
|
||||
private var _fadeOutTimer:Timer;
|
||||
|
||||
private var _slideInTimer:Timer;
|
||||
private var _slideInOrigX:Float;
|
||||
private var _slideInOrigY:Float;
|
||||
private var _slideInPosition:String;
|
||||
private var _slideInIncrements:Float;
|
||||
|
||||
private var _slideOutTimer:Timer;
|
||||
private var _slideOutOrigX:Float;
|
||||
private var _slideOutOrigY:Float;
|
||||
private var _slideOutPosition:String;
|
||||
private var _slideOutIncrements:Float;
|
||||
|
||||
private var _stage:Stage;
|
||||
private var _movieClip:MovieClip;
|
||||
|
||||
|
||||
private var _currentObject:Dynamic;
|
||||
|
||||
public function new()
|
||||
{
|
||||
_stage = Lib.current.stage;
|
||||
_movieClip = Lib.current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves an object until is shown
|
||||
* @param event
|
||||
*/
|
||||
private function slideInTimer(event:TimerEvent):Void
|
||||
{
|
||||
var last:Bool = false;
|
||||
switch(_slideInPosition)
|
||||
{
|
||||
case "top":
|
||||
if (_currentObject.y >= _slideInOrigY) { last = true; }
|
||||
_currentObject.y += _slideInIncrements;
|
||||
|
||||
case "left":
|
||||
if (_currentObject.x >= _slideInOrigX) { last = true; }
|
||||
_currentObject.x += _slideInIncrements;
|
||||
|
||||
case "bottom":
|
||||
if (_currentObject.y <= _slideInOrigY) { last = true; }
|
||||
_currentObject.y -= _slideInIncrements;
|
||||
|
||||
case "right":
|
||||
if (_currentObject.x <= _slideInOrigX) { last = true; }
|
||||
_currentObject.x -= _slideInIncrements;
|
||||
}
|
||||
|
||||
if (last)
|
||||
{
|
||||
_currentObject.x = _slideInOrigX;
|
||||
_currentObject.y = _slideInOrigY;
|
||||
_slideInTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves an object until is hidden
|
||||
* @param event
|
||||
*/
|
||||
private function slideOutTimer(event:TimerEvent):Void
|
||||
{
|
||||
if (((_currentObject.x + _currentObject.width) < 0) || (_currentObject.y + _currentObject.height < 0))
|
||||
{
|
||||
_currentObject.visible = false;
|
||||
_currentObject.x = _slideOutOrigX;
|
||||
_currentObject.y = _slideOutOrigY;
|
||||
|
||||
_slideOutTimer.stop();
|
||||
}
|
||||
else if (((_currentObject.x) > _stage.stageWidth) || (_currentObject.y > _stage.stageHeight))
|
||||
{
|
||||
_currentObject.visible = false;
|
||||
_currentObject.x = _slideOutOrigX;
|
||||
_currentObject.y = _slideOutOrigY;
|
||||
|
||||
_slideOutTimer.stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(_slideOutPosition)
|
||||
{
|
||||
case "top":
|
||||
_currentObject.y -= _slideOutIncrements;
|
||||
|
||||
case "left":
|
||||
_currentObject.x -= _slideOutIncrements;
|
||||
|
||||
case "bottom":
|
||||
_currentObject.y += _slideOutIncrements;
|
||||
|
||||
case "right":
|
||||
_currentObject.x += _slideOutIncrements;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lower object transparency until not visible
|
||||
* @param event
|
||||
*/
|
||||
private function fadeOutTimer(event:TimerEvent):Void
|
||||
{
|
||||
if (_currentObject.alpha > 0)
|
||||
{
|
||||
_currentObject.alpha -= 1 / 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentObject.visible = false;
|
||||
_fadeOutTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Highers object transparency until visible
|
||||
* @param event
|
||||
*/
|
||||
private function fadeInTimer(event:TimerEvent):Void
|
||||
{
|
||||
if (_currentObject.alpha < 1)
|
||||
{
|
||||
_currentObject.alpha += 1 / 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
_fadeInTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Effect that moves an object into stage
|
||||
* @param object the element to move
|
||||
* @param slidePosition could be top, left bottom or right
|
||||
* @param speed the time in seconds for duration of the animation
|
||||
*/
|
||||
public function slideIn(object:Dynamic, slidePosition:String, speed:Float=1000):Void
|
||||
{
|
||||
if (object.visible)
|
||||
{
|
||||
object.visible = false;
|
||||
}
|
||||
|
||||
_slideInOrigX = object.x;
|
||||
_slideInOrigY = object.y;
|
||||
_slideInPosition = slidePosition;
|
||||
|
||||
var increments:Float = 0;
|
||||
|
||||
switch(slidePosition)
|
||||
{
|
||||
case "top":
|
||||
object.y = 0 - object.height;
|
||||
increments = object.height + _slideInOrigY;
|
||||
|
||||
case "left":
|
||||
object.x = 0 - object.width;
|
||||
increments = object.width + _slideInOrigX;
|
||||
|
||||
case "bottom":
|
||||
object.y = _stage.stageHeight;
|
||||
increments = _stage.stageHeight - _slideInOrigY;
|
||||
|
||||
case "right":
|
||||
object.x = _stage.stageWidth;
|
||||
increments = _stage.stageWidth - _slideInOrigX;
|
||||
}
|
||||
|
||||
_slideInIncrements = increments / (speed / 100);
|
||||
|
||||
_currentObject = object;
|
||||
_currentObject.visible = true;
|
||||
_currentObject.alpha = 1;
|
||||
|
||||
_slideInTimer = new Timer(speed / 100);
|
||||
_slideInTimer.addEventListener(TimerEvent.TIMER, slideInTimer);
|
||||
_slideInTimer.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Effect that moves an object out of stage
|
||||
* @param object the element to move
|
||||
* @param slidePosition could be top, left bottom or right
|
||||
* @param speed the time in seconds for duration of the animation
|
||||
*/
|
||||
public function slideOut(object:Dynamic, slidePosition:String, speed:Float=1000):Void
|
||||
{
|
||||
if (!object.visible)
|
||||
{
|
||||
object.visible = true;
|
||||
}
|
||||
|
||||
_slideOutOrigX = object.x;
|
||||
_slideOutOrigY = object.y;
|
||||
_slideOutPosition = slidePosition;
|
||||
|
||||
var increments:Float = 0;
|
||||
|
||||
switch(slidePosition)
|
||||
{
|
||||
case "top":
|
||||
increments = object.height + _slideOutOrigY;
|
||||
|
||||
case "left":
|
||||
increments = object.width + _slideOutOrigX;
|
||||
|
||||
case "bottom":
|
||||
increments = _stage.stageHeight - _slideOutOrigY;
|
||||
|
||||
case "right":
|
||||
increments = _stage.stageWidth - _slideOutOrigX;
|
||||
}
|
||||
|
||||
_slideOutIncrements = increments / (speed / 100);
|
||||
|
||||
_currentObject = object;
|
||||
_currentObject.visible = true;
|
||||
_currentObject.alpha = 1;
|
||||
|
||||
_slideOutTimer = new Timer(speed / 100);
|
||||
_slideOutTimer.addEventListener(TimerEvent.TIMER, slideOutTimer);
|
||||
_slideOutTimer.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Effect that dissapears an object from stage
|
||||
* @param object the element to dissapear
|
||||
* @param speed the time in seconds for the duration of the animation
|
||||
*/
|
||||
public function fadeOut(object:Dynamic, speed:Float=500):Void
|
||||
{
|
||||
if (!object.visible)
|
||||
{
|
||||
object.visible = true;
|
||||
}
|
||||
|
||||
object.alpha = 1;
|
||||
_currentObject = object;
|
||||
|
||||
_fadeOutTimer = new Timer(speed / 10);
|
||||
_fadeOutTimer.addEventListener(TimerEvent.TIMER, fadeOutTimer);
|
||||
_fadeOutTimer.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Effect that shows a hidden object an in stage
|
||||
* @param object the element to show
|
||||
* @param speed the time in seconds for the duration of the animation
|
||||
*/
|
||||
public function fadeIn(object:Dynamic, speed:Float=500):Void
|
||||
{
|
||||
if (object.visible)
|
||||
{
|
||||
object.visible = false;
|
||||
}
|
||||
|
||||
object.alpha = 0;
|
||||
_currentObject = object;
|
||||
_currentObject.visible = true;
|
||||
|
||||
_fadeInTimer = new Timer(speed / 10);
|
||||
_fadeInTimer.addEventListener(TimerEvent.TIMER, fadeInTimer);
|
||||
_fadeInTimer.start();
|
||||
}
|
||||
|
||||
}
|
||||
181
lib/Jaris/src/jaris/display/Loader.hx
Normal file
181
lib/Jaris/src/jaris/display/Loader.hx
Normal file
@ -0,0 +1,181 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.display;
|
||||
|
||||
import flash.display.MovieClip;
|
||||
import flash.display.Sprite;
|
||||
import flash.display.Stage;
|
||||
import flash.events.Event;
|
||||
import flash.Lib;
|
||||
|
||||
/**
|
||||
* Draws a loading bar
|
||||
*/
|
||||
class Loader extends Sprite
|
||||
{
|
||||
private var _stage:Stage;
|
||||
private var _movieClip:MovieClip;
|
||||
private var _background:Sprite;
|
||||
private var _loaderTrack:Sprite;
|
||||
private var _loaderThumb:Sprite;
|
||||
private var _visible:Bool;
|
||||
private var _brightColor:UInt;
|
||||
private var _controlColor:UInt;
|
||||
private var _forward:Bool;
|
||||
|
||||
public function new()
|
||||
{
|
||||
super();
|
||||
|
||||
_stage = Lib.current.stage;
|
||||
_movieClip = Lib.current;
|
||||
|
||||
_background = new Sprite();
|
||||
addChild(_background);
|
||||
|
||||
_loaderTrack = new Sprite();
|
||||
addChild(_loaderTrack);
|
||||
|
||||
_loaderThumb = new Sprite();
|
||||
addChild(_loaderThumb);
|
||||
|
||||
_brightColor = 0x4c4c4c;
|
||||
_controlColor = 0xFFFFFF;
|
||||
|
||||
_forward = true;
|
||||
_visible = true;
|
||||
|
||||
addEventListener(Event.ENTER_FRAME, onEnterFrame);
|
||||
_stage.addEventListener(Event.RESIZE, onResize);
|
||||
|
||||
drawLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Animation of a thumb moving on the track
|
||||
* @param event
|
||||
*/
|
||||
private function onEnterFrame(event:Event):Void
|
||||
{
|
||||
if (_visible)
|
||||
{
|
||||
if (_forward)
|
||||
{
|
||||
if ((_loaderThumb.x + _loaderThumb.width) >= (_loaderTrack.x + _loaderTrack.width))
|
||||
{
|
||||
_forward = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_loaderThumb.x += 10;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_loaderThumb.x <= _loaderTrack.x)
|
||||
{
|
||||
_forward = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_loaderThumb.x -= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redraws the loader to match new stage size
|
||||
* @param event
|
||||
*/
|
||||
private function onResize(event:Event):Void
|
||||
{
|
||||
drawLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw loader graphics
|
||||
*/
|
||||
private function drawLoader():Void
|
||||
{
|
||||
//Clear graphics
|
||||
_background.graphics.clear();
|
||||
_loaderTrack.graphics.clear();
|
||||
_loaderThumb.graphics.clear();
|
||||
|
||||
//Draw background
|
||||
var backgroundWidth:Float = (65 / 100) * _stage.stageWidth;
|
||||
var backgroundHeight:Float = 30;
|
||||
_background.x = (_stage.stageWidth / 2) - (backgroundWidth / 2);
|
||||
_background.y = (_stage.stageHeight / 2) - (backgroundHeight / 2);
|
||||
_background.graphics.lineStyle();
|
||||
_background.graphics.beginFill(_brightColor, 0.5);
|
||||
_background.graphics.drawRoundRect(0, 0, backgroundWidth, backgroundHeight, 6, 6);
|
||||
_background.graphics.endFill();
|
||||
|
||||
//Draw track
|
||||
var trackWidth:Float = (50 / 100) * _stage.stageWidth;
|
||||
var trackHeight:Float = 15;
|
||||
_loaderTrack.x = (_stage.stageWidth / 2) - (trackWidth / 2);
|
||||
_loaderTrack.y = (_stage.stageHeight / 2) - (trackHeight / 2);
|
||||
_loaderTrack.graphics.lineStyle(2, _controlColor);
|
||||
_loaderTrack.graphics.drawRect(0, 0, trackWidth, trackHeight);
|
||||
|
||||
//Draw thumb
|
||||
_loaderThumb.x = _loaderTrack.x;
|
||||
_loaderThumb.y = _loaderTrack.y;
|
||||
_loaderThumb.graphics.lineStyle();
|
||||
_loaderThumb.graphics.beginFill(_controlColor, 1);
|
||||
_loaderThumb.graphics.drawRect(0, 0, trackHeight, trackHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops drawing the loader
|
||||
*/
|
||||
public function hide():Void
|
||||
{
|
||||
this.visible = false;
|
||||
_visible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts drawing the loader
|
||||
*/
|
||||
public function show():Void
|
||||
{
|
||||
this.visible = true;
|
||||
_visible = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set loader colors
|
||||
* @param colors
|
||||
*/
|
||||
public function setColors(colors:Array<String>):Void
|
||||
{
|
||||
_brightColor = colors[0].length > 0? Std.parseInt("0x" + colors[0]) : 0x4c4c4c;
|
||||
_controlColor = colors[1].length > 0? Std.parseInt("0x" + colors[1]) : 0xFFFFFF;
|
||||
|
||||
drawLoader();
|
||||
}
|
||||
}
|
||||
185
lib/Jaris/src/jaris/display/Logo.hx
Normal file
185
lib/Jaris/src/jaris/display/Logo.hx
Normal file
@ -0,0 +1,185 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.display;
|
||||
|
||||
import flash.display.Loader;
|
||||
import flash.display.MovieClip;
|
||||
import flash.display.Sprite;
|
||||
import flash.display.Stage;
|
||||
import flash.events.Event;
|
||||
import flash.events.IOErrorEvent;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.Lib;
|
||||
import flash.net.URLRequest;
|
||||
|
||||
/**
|
||||
* To display an image in jpg, png or gif format as logo
|
||||
*/
|
||||
class Logo extends Sprite
|
||||
{
|
||||
private var _stage:Stage;
|
||||
private var _movieClip:MovieClip;
|
||||
private var _loader:Loader;
|
||||
private var _position:String;
|
||||
private var _alpha:Float;
|
||||
private var _source:String;
|
||||
private var _width:Float;
|
||||
private var _link:String;
|
||||
private var _loading:Bool;
|
||||
|
||||
public function new(source:String, position:String, alpha:Float, width:Float=0.0)
|
||||
{
|
||||
super();
|
||||
|
||||
_stage = Lib.current.stage;
|
||||
_movieClip = Lib.current;
|
||||
_loader = new Loader();
|
||||
_position = position;
|
||||
_alpha = alpha;
|
||||
_source = source;
|
||||
_width = width;
|
||||
_loading = true;
|
||||
|
||||
this.tabEnabled = false;
|
||||
|
||||
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete);
|
||||
_loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onNotLoaded);
|
||||
_loader.load(new URLRequest(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers when the logo image could not be loaded
|
||||
* @param event
|
||||
*/
|
||||
private function onNotLoaded(event:IOErrorEvent):Void
|
||||
{
|
||||
//Image not loaded
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers when the logo image finished loading.
|
||||
* @param event
|
||||
*/
|
||||
private function onLoaderComplete(event:Event):Void
|
||||
{
|
||||
addChild(_loader);
|
||||
|
||||
setWidth(_width);
|
||||
setPosition(_position);
|
||||
setAlpha(_alpha);
|
||||
_loading = false;
|
||||
|
||||
_stage.addEventListener(Event.RESIZE, onStageResize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculate logo position on stage resize
|
||||
* @param event
|
||||
*/
|
||||
private function onStageResize(event:Event):Void
|
||||
{
|
||||
setPosition(_position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the an url when the logo is clicked
|
||||
* @param event
|
||||
*/
|
||||
private function onLogoClick(event:MouseEvent):Void
|
||||
{
|
||||
Lib.getURL(new URLRequest(_link), "_blank");
|
||||
}
|
||||
|
||||
/**
|
||||
* Position where logo will be showing
|
||||
* @param position values could be top left, top right, bottom left, bottom right
|
||||
*/
|
||||
public function setPosition(position:String):Void
|
||||
{
|
||||
switch(position)
|
||||
{
|
||||
case "top left":
|
||||
this.x = 25;
|
||||
this.y = 25;
|
||||
|
||||
case "top right":
|
||||
this.x = _stage.stageWidth - this._width - 25;
|
||||
this.y = 25;
|
||||
|
||||
case "bottom left":
|
||||
this.x = 25;
|
||||
this.y = _stage.stageHeight - this.height - 25;
|
||||
|
||||
case "bottom right":
|
||||
this.x = _stage.stageWidth - this.width - 25;
|
||||
this.y = _stage.stageHeight - this.height - 25;
|
||||
|
||||
default:
|
||||
this.x = 25;
|
||||
this.y = 25;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To set logo transparency
|
||||
* @param alpha
|
||||
*/
|
||||
public function setAlpha(alpha:Float):Void
|
||||
{
|
||||
this.alpha = alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets logo width and recalculates height keeping aspect ratio
|
||||
* @param width
|
||||
*/
|
||||
public function setWidth(width:Float):Void
|
||||
{
|
||||
if (width > 0)
|
||||
{
|
||||
this.height = (this.height / this.width) * width;
|
||||
this.width = width;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Link that opens when clicked the logo image is clicked
|
||||
* @param link
|
||||
*/
|
||||
public function setLink(link:String):Void
|
||||
{
|
||||
_link = link;
|
||||
this.buttonMode = true;
|
||||
this.useHandCursor = true;
|
||||
this.addEventListener(MouseEvent.CLICK, onLogoClick);
|
||||
}
|
||||
|
||||
/**
|
||||
* To check if the logo stills loading
|
||||
* @return true if loading false otherwise
|
||||
*/
|
||||
public function isLoading():Bool
|
||||
{
|
||||
return _loading;
|
||||
}
|
||||
}
|
||||
246
lib/Jaris/src/jaris/display/Menu.hx
Normal file
246
lib/Jaris/src/jaris/display/Menu.hx
Normal file
@ -0,0 +1,246 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.display;
|
||||
import flash.display.MovieClip;
|
||||
import flash.events.ContextMenuEvent;
|
||||
import flash.Lib;
|
||||
import flash.net.URLRequest;
|
||||
import flash.ui.ContextMenu;
|
||||
import flash.ui.ContextMenuItem;
|
||||
import jaris.player.Player;
|
||||
import jaris.player.AspectRatio;
|
||||
import jaris.Version;
|
||||
|
||||
/**
|
||||
* Modify original context menu
|
||||
*/
|
||||
class Menu
|
||||
{
|
||||
private var _movieClip:MovieClip;
|
||||
public static var _player:Player;
|
||||
|
||||
private var _contextMenu:ContextMenu;
|
||||
private var _jarisVersionMenuItem:ContextMenuItem;
|
||||
private var _playMenuItem:ContextMenuItem;
|
||||
private var _fullscreenMenuItem:ContextMenuItem;
|
||||
private var _aspectRatioMenuItem:ContextMenuItem;
|
||||
private var _muteMenuItem:ContextMenuItem;
|
||||
private var _volumeUpMenuItem:ContextMenuItem;
|
||||
private var _volumeDownMenuItem:ContextMenuItem;
|
||||
private var _qualityContextMenu:ContextMenuItem;
|
||||
|
||||
public function new(player:Player)
|
||||
{
|
||||
_movieClip = Lib.current;
|
||||
_player = player;
|
||||
|
||||
//Initialize context menu replacement
|
||||
_contextMenu = new ContextMenu();
|
||||
_contextMenu.hideBuiltInItems();
|
||||
|
||||
_contextMenu.addEventListener(ContextMenuEvent.MENU_SELECT, onMenuOpen);
|
||||
|
||||
//Initialize each menu item
|
||||
_jarisVersionMenuItem = new ContextMenuItem("Jaris Player v" + Version.NUMBER + " " + Version.STATUS, true, true, true);
|
||||
_jarisVersionMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onJarisVersion);
|
||||
|
||||
_playMenuItem = new ContextMenuItem("Play (SPACE)", true, true, true);
|
||||
_playMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onPlay);
|
||||
|
||||
_fullscreenMenuItem = new ContextMenuItem("Fullscreen View (F)");
|
||||
_fullscreenMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onFullscreen);
|
||||
|
||||
_aspectRatioMenuItem = new ContextMenuItem("Aspect Ratio (original) (TAB)");
|
||||
_aspectRatioMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onAspectRatio);
|
||||
|
||||
_muteMenuItem = new ContextMenuItem("Mute (M)");
|
||||
_muteMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onMute);
|
||||
|
||||
_volumeUpMenuItem = new ContextMenuItem("Volume + (arrow UP)");
|
||||
_volumeUpMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onVolumeUp);
|
||||
|
||||
_volumeDownMenuItem = new ContextMenuItem("Volume - (arrow DOWN)");
|
||||
_volumeDownMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onVolumeDown);
|
||||
|
||||
_qualityContextMenu = new ContextMenuItem("Lower Quality", true, true, true);
|
||||
_qualityContextMenu.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onQuality);
|
||||
|
||||
//add all context menu items to context menu object
|
||||
_contextMenu.customItems.push(_jarisVersionMenuItem);
|
||||
_contextMenu.customItems.push(_playMenuItem);
|
||||
_contextMenu.customItems.push(_fullscreenMenuItem);
|
||||
_contextMenu.customItems.push(_aspectRatioMenuItem);
|
||||
_contextMenu.customItems.push(_muteMenuItem);
|
||||
_contextMenu.customItems.push(_volumeUpMenuItem);
|
||||
_contextMenu.customItems.push(_volumeDownMenuItem);
|
||||
_contextMenu.customItems.push(_qualityContextMenu);
|
||||
|
||||
//override default context menu
|
||||
_movieClip.contextMenu = _contextMenu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update context menu item captions depending on player status before showing them
|
||||
* @param event
|
||||
*/
|
||||
private function onMenuOpen(event:ContextMenuEvent):Void
|
||||
{
|
||||
if (_player.isPlaying())
|
||||
{
|
||||
_playMenuItem.caption = "Pause (SPACE)";
|
||||
}
|
||||
else
|
||||
{
|
||||
_playMenuItem.caption = "Play (SPACE)";
|
||||
}
|
||||
|
||||
if (_player.isFullscreen())
|
||||
{
|
||||
_fullscreenMenuItem.caption = "Normal View";
|
||||
}
|
||||
else
|
||||
{
|
||||
_fullscreenMenuItem.caption = "Fullscreen View (F)";
|
||||
}
|
||||
|
||||
if (_player.getMute())
|
||||
{
|
||||
_muteMenuItem.caption = _player.isFullscreen()?"Unmute":"Unmute (M)";
|
||||
}
|
||||
else
|
||||
{
|
||||
_muteMenuItem.caption = _player.isFullscreen()?"Mute":"Mute (M)";
|
||||
}
|
||||
|
||||
switch(_player.getAspectRatioString())
|
||||
{
|
||||
case "original":
|
||||
_aspectRatioMenuItem.caption = "Aspect Ratio (1:1) (TAB)";
|
||||
|
||||
case "1:1":
|
||||
_aspectRatioMenuItem.caption = "Aspect Ratio (3:2) (TAB)";
|
||||
|
||||
case "3:2":
|
||||
_aspectRatioMenuItem.caption = "Aspect Ratio (4:3) (TAB)";
|
||||
|
||||
case "4:3":
|
||||
_aspectRatioMenuItem.caption = "Aspect Ratio (5:4) (TAB)";
|
||||
|
||||
case "5:4":
|
||||
_aspectRatioMenuItem.caption = "Aspect Ratio (14:9) (TAB)";
|
||||
|
||||
case "14:9":
|
||||
_aspectRatioMenuItem.caption = "Aspect Ratio (14:10) (TAB)";
|
||||
|
||||
case "14:10":
|
||||
_aspectRatioMenuItem.caption = "Aspect Ratio (16:9) (TAB)";
|
||||
|
||||
case "16:9":
|
||||
_aspectRatioMenuItem.caption = "Aspect Ratio (16:10) (TAB)";
|
||||
|
||||
case "16:10":
|
||||
_aspectRatioMenuItem.caption = "Aspect Ratio (original) (TAB)";
|
||||
}
|
||||
|
||||
if (_player.getQuality())
|
||||
{
|
||||
_qualityContextMenu.caption = "Lower Quality";
|
||||
}
|
||||
else
|
||||
{
|
||||
_qualityContextMenu.caption = "Higher Quality";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open jaris player website
|
||||
* @param event
|
||||
*/
|
||||
private function onJarisVersion(event:ContextMenuEvent)
|
||||
{
|
||||
Lib.getURL(new URLRequest("http://jaris.sourceforge.net"), "_blank");
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles playback
|
||||
* @param event
|
||||
*/
|
||||
private function onPlay(event:ContextMenuEvent)
|
||||
{
|
||||
_player.togglePlay();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles fullscreen
|
||||
* @param event
|
||||
*/
|
||||
private function onFullscreen(event:ContextMenuEvent)
|
||||
{
|
||||
_player.toggleFullscreen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles aspect ratio
|
||||
* @param event
|
||||
*/
|
||||
private function onAspectRatio(event:ContextMenuEvent)
|
||||
{
|
||||
_player.toggleAspectRatio();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles mute
|
||||
* @param event
|
||||
*/
|
||||
private function onMute(event:ContextMenuEvent)
|
||||
{
|
||||
_player.toggleMute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Raise volume
|
||||
* @param event
|
||||
*/
|
||||
private function onVolumeUp(event:ContextMenuEvent)
|
||||
{
|
||||
_player.volumeUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lower volume
|
||||
* @param event
|
||||
*/
|
||||
private function onVolumeDown(event:ContextMenuEvent)
|
||||
{
|
||||
_player.volumeDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle video quality
|
||||
* @param event
|
||||
*/
|
||||
private function onQuality(event:ContextMenuEvent)
|
||||
{
|
||||
_player.toggleQuality();
|
||||
}
|
||||
}
|
||||
170
lib/Jaris/src/jaris/display/Poster.hx
Normal file
170
lib/Jaris/src/jaris/display/Poster.hx
Normal file
@ -0,0 +1,170 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.display;
|
||||
|
||||
import flash.display.DisplayObject;
|
||||
import flash.display.Loader;
|
||||
import flash.display.MovieClip;
|
||||
import flash.display.Sprite;
|
||||
import flash.display.Stage;
|
||||
import flash.events.Event;
|
||||
import flash.events.IOErrorEvent;
|
||||
import flash.Lib;
|
||||
import flash.net.URLRequest;
|
||||
import jaris.events.PlayerEvents;
|
||||
import jaris.player.InputType;
|
||||
import jaris.player.Player;
|
||||
|
||||
/**
|
||||
* To display an png, jpg or gif as preview of video content
|
||||
*/
|
||||
class Poster extends Sprite
|
||||
{
|
||||
|
||||
private var _stage:Stage;
|
||||
private var _movieClip:MovieClip;
|
||||
private var _loader:Loader;
|
||||
private var _source:String;
|
||||
private var _width:Float;
|
||||
private var _height:Float;
|
||||
private var _loading:Bool;
|
||||
private var _loaderStatus:jaris.display.Loader;
|
||||
private var _player:Player;
|
||||
|
||||
public function new(source:String)
|
||||
{
|
||||
super();
|
||||
|
||||
_stage = Lib.current.stage;
|
||||
_movieClip = Lib.current;
|
||||
_loader = new Loader();
|
||||
_source = source;
|
||||
_loading = true;
|
||||
|
||||
//Reads flash vars
|
||||
var parameters:Dynamic<String> = flash.Lib.current.loaderInfo.parameters;
|
||||
|
||||
//Draw Loader status
|
||||
var loaderColors:Array <String> = ["", "", "", ""];
|
||||
loaderColors[0] = parameters.brightcolor != null ? parameters.brightcolor : "";
|
||||
loaderColors[1] = parameters.controlcolor != null ? parameters.controlcolor : "";
|
||||
|
||||
_loaderStatus = new jaris.display.Loader();
|
||||
_loaderStatus.show();
|
||||
_loaderStatus.setColors(loaderColors);
|
||||
addChild(_loaderStatus);
|
||||
|
||||
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete);
|
||||
_loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onNotLoaded);
|
||||
_loader.load(new URLRequest(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers when the poster image could not be loaded
|
||||
* @param event
|
||||
*/
|
||||
private function onNotLoaded(event:IOErrorEvent):Void
|
||||
{
|
||||
_loaderStatus.hide();
|
||||
removeChild(_loaderStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers when the poster image finalized loading
|
||||
* @param event
|
||||
*/
|
||||
private function onLoaderComplete(event:Event):Void
|
||||
{
|
||||
_loaderStatus.hide();
|
||||
removeChild(_loaderStatus);
|
||||
|
||||
addChild(_loader);
|
||||
|
||||
_width = this.width;
|
||||
_height = this.height;
|
||||
_loading = false;
|
||||
|
||||
_stage.addEventListener(Event.RESIZE, onStageResize);
|
||||
|
||||
resizeImage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers when the stage is resized to resize the poster image
|
||||
* @param event
|
||||
*/
|
||||
private function onStageResize(event:Event):Void
|
||||
{
|
||||
resizeImage();
|
||||
}
|
||||
|
||||
private function onPlayerMediaInitialized(event:PlayerEvents)
|
||||
{
|
||||
if (_player.getType() == InputType.VIDEO)
|
||||
{
|
||||
this.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private function onPlayerPlay(event:PlayerEvents)
|
||||
{
|
||||
if (_player.getType() == InputType.VIDEO)
|
||||
{
|
||||
this.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private function onPlayBackFinished(event:PlayerEvents)
|
||||
{
|
||||
this.visible = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes the poster image to take all the stage
|
||||
*/
|
||||
private function resizeImage():Void
|
||||
{
|
||||
this.height = _stage.stageHeight;
|
||||
this.width = ((_width / _height) * this.height);
|
||||
|
||||
this.x = (_stage.stageWidth / 2) - (this.width / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* To check if the poster image stills loading
|
||||
* @return true if stills loading false if loaded
|
||||
*/
|
||||
public function isLoading():Bool
|
||||
{
|
||||
return _loading;
|
||||
}
|
||||
|
||||
public function setPlayer(player:Player):Void
|
||||
{
|
||||
_player = player;
|
||||
_player.addEventListener(PlayerEvents.MEDIA_INITIALIZED, onPlayerMediaInitialized);
|
||||
_player.addEventListener(PlayerEvents.PLAYBACK_FINISHED, onPlayBackFinished);
|
||||
_player.addEventListener(PlayerEvents.PLAY_PAUSE, onPlayerPlay);
|
||||
}
|
||||
|
||||
}
|
||||
84
lib/Jaris/src/jaris/events/PlayerEvents.hx
Normal file
84
lib/Jaris/src/jaris/events/PlayerEvents.hx
Normal file
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.events;
|
||||
|
||||
import flash.events.Event;
|
||||
import flash.media.ID3Info;
|
||||
import flash.media.Sound;
|
||||
import flash.net.NetStream;
|
||||
|
||||
/**
|
||||
* Implements the player events
|
||||
*/
|
||||
class PlayerEvents extends Event
|
||||
{
|
||||
public static var ASPECT_RATIO = "onAspectRatio";
|
||||
public static var MOUSE_SHOW = "onMouseShow";
|
||||
public static var MOUSE_HIDE = "onMouseHide";
|
||||
public static var FULLSCREEN = "onFullscreen";
|
||||
public static var VOLUME_UP = "onVolumeUp";
|
||||
public static var VOLUME_DOWN = "onVolumeDown";
|
||||
public static var VOLUME_CHANGE= "onVolumeChange"; //Nuevo
|
||||
public static var MUTE = "onMute";
|
||||
public static var FORWARD = "onForward";
|
||||
public static var REWIND = "onRewind";
|
||||
public static var PLAY_PAUSE = "onPlayPause";
|
||||
public static var SEEK = "onSeek";
|
||||
public static var TIME = "onTimeUpdate";
|
||||
public static var PROGRESS = "onProgress";
|
||||
public static var BUFFERING = "onBuffering";
|
||||
public static var NOT_BUFFERING = "onNotBuffering";
|
||||
public static var CONNECTION_FAILED = "onConnectionFailed";
|
||||
public static var CONNECTION_SUCCESS = "onConnectionSuccess";
|
||||
public static var MEDIA_INITIALIZED = "onDataInitialized";
|
||||
public static var PLAYBACK_FINISHED = "onPlaybackFinished";
|
||||
public static var STOP_CLOSE = "onStopAndClose";
|
||||
public static var RESIZE = "onResize";
|
||||
|
||||
public var name:String;
|
||||
public var aspectRatio:Float;
|
||||
public var duration:Float;
|
||||
public var fullscreen:Bool;
|
||||
public var mute:Bool;
|
||||
public var volume:Float;
|
||||
public var width:Float;
|
||||
public var height:Float;
|
||||
public var stream:NetStream;
|
||||
public var sound:Sound;
|
||||
public var time:Float;
|
||||
public var id3Info:ID3Info;
|
||||
|
||||
public function new(type:String, bubbles:Bool=false, cancelable:Bool=false)
|
||||
{
|
||||
super(type, bubbles, cancelable);
|
||||
|
||||
fullscreen = false;
|
||||
mute = false;
|
||||
volume = 1.0;
|
||||
duration = 0;
|
||||
width = 0;
|
||||
height = 0;
|
||||
time = 0;
|
||||
name = type;
|
||||
}
|
||||
}
|
||||
49
lib/Jaris/src/jaris/player/AspectRatio.hx
Normal file
49
lib/Jaris/src/jaris/player/AspectRatio.hx
Normal file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player;
|
||||
|
||||
/**
|
||||
* Stores the player used aspect ratio constants
|
||||
*/
|
||||
class AspectRatio
|
||||
{
|
||||
public static var _1_1:Float = 1 / 1;
|
||||
public static var _3_2:Float = 3 / 2;
|
||||
public static var _4_3:Float = 4 / 3;
|
||||
public static var _5_4:Float = 5 / 4;
|
||||
public static var _14_9:Float = 14 / 9;
|
||||
public static var _14_10:Float = 14 / 10;
|
||||
public static var _16_9:Float = 16 / 9;
|
||||
public static var _16_10:Float = 16 / 10;
|
||||
|
||||
/**
|
||||
* Calculates the ratio for a given width and height
|
||||
* @param width
|
||||
* @param height
|
||||
* @return aspect ratio
|
||||
*/
|
||||
public static function getAspectRatio(width:Float, height:Float):Float
|
||||
{
|
||||
return width / height;
|
||||
}
|
||||
}
|
||||
32
lib/Jaris/src/jaris/player/InputType.hx
Normal file
32
lib/Jaris/src/jaris/player/InputType.hx
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player;
|
||||
|
||||
/**
|
||||
* Stores the identifiers for loaded media type
|
||||
*/
|
||||
class InputType
|
||||
{
|
||||
public static var AUDIO = "audio";
|
||||
public static var VIDEO = "video";
|
||||
}
|
||||
232
lib/Jaris/src/jaris/player/JsApi.hx
Normal file
232
lib/Jaris/src/jaris/player/JsApi.hx
Normal file
@ -0,0 +1,232 @@
|
||||
/**
|
||||
* @author Sascha Kluger
|
||||
* @copyright 2010 Jefferson González, Sascha Kluger
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player;
|
||||
|
||||
//{Libraries
|
||||
import flash.system.Capabilities;
|
||||
import flash.system.Security;
|
||||
import flash.external.ExternalInterface;
|
||||
import flash.display.GradientType;
|
||||
import flash.events.Event;
|
||||
import flash.events.TimerEvent;
|
||||
import flash.geom.Matrix;
|
||||
import flash.Lib;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.display.MovieClip;
|
||||
import flash.net.NetStream;
|
||||
import flash.geom.Rectangle;
|
||||
import flash.net.ObjectEncoding;
|
||||
import flash.text.AntiAliasType;
|
||||
import flash.text.TextField;
|
||||
import flash.text.TextFieldAutoSize;
|
||||
import flash.text.TextFormat;
|
||||
import flash.utils.Timer;
|
||||
import jaris.animation.Animation;
|
||||
import jaris.display.Loader;
|
||||
import jaris.events.PlayerEvents;
|
||||
import jaris.player.controls.AspectRatioIcon;
|
||||
import jaris.player.controls.FullscreenIcon;
|
||||
import jaris.player.controls.PauseIcon;
|
||||
import jaris.player.controls.PlayIcon;
|
||||
import jaris.player.controls.VolumeIcon;
|
||||
import jaris.player.Player;
|
||||
import flash.display.Sprite;
|
||||
import flash.display.Stage;
|
||||
import jaris.utils.Utils;
|
||||
//}
|
||||
|
||||
/**
|
||||
* Default controls for jaris player
|
||||
*/
|
||||
class JsApi extends MovieClip {
|
||||
|
||||
//{Member Variables
|
||||
private var _stage:Stage;
|
||||
private var _movieClip:MovieClip;
|
||||
private var _player:Player;
|
||||
private var _isBuffering:Bool;
|
||||
private var _percentLoaded:Float;
|
||||
private var _externalListeners:Hash<String>;
|
||||
|
||||
//}
|
||||
|
||||
|
||||
//{Constructor
|
||||
public function new(player:Player)
|
||||
{
|
||||
super();
|
||||
_externalListeners = new Hash<String>();
|
||||
|
||||
Security.allowDomain("*");
|
||||
|
||||
//{Main variables
|
||||
// _stage = Lib.current.stage;
|
||||
// _movieClip = Lib.current;
|
||||
_player = player;
|
||||
|
||||
_player.addEventListener(PlayerEvents.MOUSE_HIDE, onPlayerEvent);
|
||||
_player.addEventListener(PlayerEvents.MOUSE_SHOW, onPlayerEvent);
|
||||
_player.addEventListener(PlayerEvents.MEDIA_INITIALIZED, onPlayerEvent);
|
||||
_player.addEventListener(PlayerEvents.BUFFERING, onPlayerEvent);
|
||||
_player.addEventListener(PlayerEvents.NOT_BUFFERING, onPlayerEvent);
|
||||
_player.addEventListener(PlayerEvents.RESIZE, onPlayerEvent);
|
||||
_player.addEventListener(PlayerEvents.PLAY_PAUSE, onPlayerEvent);
|
||||
_player.addEventListener(PlayerEvents.PLAYBACK_FINISHED, onPlayerEvent);
|
||||
_player.addEventListener(PlayerEvents.CONNECTION_FAILED, onPlayerEvent);
|
||||
_player.addEventListener(PlayerEvents.ASPECT_RATIO, onPlayerEvent);
|
||||
_player.addEventListener(PlayerEvents.VOLUME_UP, onPlayerEvent);
|
||||
_player.addEventListener(PlayerEvents.VOLUME_DOWN, onPlayerEvent);
|
||||
_player.addEventListener(PlayerEvents.VOLUME_CHANGE, onPlayerEvent);
|
||||
_player.addEventListener(PlayerEvents.MUTE, onPlayerEvent);
|
||||
_player.addEventListener(PlayerEvents.TIME, onPlayerEvent);
|
||||
_player.addEventListener(PlayerEvents.PROGRESS, onPlayerEvent);
|
||||
_player.addEventListener(PlayerEvents.SEEK, onPlayerEvent);
|
||||
|
||||
ExternalInterface.addCallback("api_get", getAttribute);
|
||||
ExternalInterface.addCallback("api_addlistener", addJsListener);
|
||||
ExternalInterface.addCallback("api_removelistener", removeJsListener);
|
||||
ExternalInterface.addCallback("api_play", setPlay);
|
||||
ExternalInterface.addCallback("api_pause", setPause);
|
||||
ExternalInterface.addCallback("api_seek", setSeek);
|
||||
ExternalInterface.addCallback("api_volume", setVolume);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function getAttribute(attribute:String):Float {
|
||||
|
||||
switch (attribute) {
|
||||
case 'isBuffering':
|
||||
return (_isBuffering) ? 1 : 0;
|
||||
|
||||
case 'isPlaying':
|
||||
return (_player.isPlaying()) ? 1 : 0;
|
||||
|
||||
case 'time':
|
||||
return Math.round(_player.getCurrentTime() * 10) / 10;
|
||||
|
||||
case 'loaded':
|
||||
return _player.getBytesLoaded();
|
||||
|
||||
case 'volume':
|
||||
return (_player.getMute()==true) ? 0 : _player.getVolume();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function addJsListener(attribute:String, parameter:String):Void {
|
||||
_externalListeners.set(attribute.toLowerCase(), parameter);
|
||||
}
|
||||
|
||||
public function removeJsListener(attribute:String):Void {
|
||||
if (attribute == '*')
|
||||
{
|
||||
_externalListeners = new Hash<String>();
|
||||
return;
|
||||
}
|
||||
_externalListeners.remove(attribute.toLowerCase());
|
||||
}
|
||||
|
||||
public function onPlayerEvent(event:PlayerEvents):Void
|
||||
{
|
||||
var jsFunction = '';
|
||||
var data = {
|
||||
duration: event.duration,
|
||||
fullscreen: event.fullscreen,
|
||||
mute: event.mute,
|
||||
volume: event.volume,
|
||||
position: event.time,
|
||||
type: event.name,
|
||||
loaded: _player.getBytesLoaded(),
|
||||
total: _player.getBytesTotal()
|
||||
};
|
||||
|
||||
if (_externalListeners.exists(event.name.toLowerCase()))
|
||||
{
|
||||
ExternalInterface.call(_externalListeners.get(event.name.toLowerCase()), data);
|
||||
}
|
||||
|
||||
if (_externalListeners.exists('on*'))
|
||||
{
|
||||
ExternalInterface.call(_externalListeners.get('on*'), data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Toggles pause or play
|
||||
*/
|
||||
private function setPlay():Void
|
||||
{
|
||||
if (_player.isPlaying()!=true) {
|
||||
_player.togglePlay();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles play or pause
|
||||
*/
|
||||
private function setPause():Void
|
||||
{
|
||||
if (_player.isPlaying()==true) {
|
||||
_player.togglePlay();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Seek
|
||||
*/
|
||||
private function setSeek(pos:Float):Void
|
||||
{
|
||||
_player.seek(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Volume
|
||||
*/
|
||||
private function setVolume(vol:Float):Void
|
||||
{
|
||||
if (vol <= 0 && _player.getMute()!=true) {
|
||||
_player.toggleMute();
|
||||
_player.setVolume(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player.getMute() == true) {
|
||||
_player.toggleMute();
|
||||
}
|
||||
|
||||
if (vol >= 1) {
|
||||
_player.setVolume(1);
|
||||
return;
|
||||
}
|
||||
|
||||
_player.setVolume(vol);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
50
lib/Jaris/src/jaris/player/Loop.hx
Normal file
50
lib/Jaris/src/jaris/player/Loop.hx
Normal file
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player;
|
||||
|
||||
//{Libraries
|
||||
import jaris.events.PlayerEvents;
|
||||
//}
|
||||
|
||||
/**
|
||||
* Implements a loop mechanism on the player
|
||||
*/
|
||||
class Loop
|
||||
{
|
||||
private var _player:Player;
|
||||
|
||||
public function new(player:Player)
|
||||
{
|
||||
_player = player;
|
||||
_player.addEventListener(PlayerEvents.PLAYBACK_FINISHED, onPlayerStop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Everytime the player stops, the playback is restarted
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerStop(event:PlayerEvents):Void
|
||||
{
|
||||
_player.togglePlay();
|
||||
}
|
||||
}
|
||||
1788
lib/Jaris/src/jaris/player/Player.hx
Normal file
1788
lib/Jaris/src/jaris/player/Player.hx
Normal file
File diff suppressed because it is too large
Load Diff
34
lib/Jaris/src/jaris/player/StreamType.hx
Normal file
34
lib/Jaris/src/jaris/player/StreamType.hx
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player;
|
||||
|
||||
/**
|
||||
* Some constants for the stream types
|
||||
*/
|
||||
class StreamType
|
||||
{
|
||||
public static var FILE:String = "file";
|
||||
public static var PSEUDOSTREAM:String = "http";
|
||||
public static var RTMP:String = "rtmp";
|
||||
public static var YOUTUBE = "youtube";
|
||||
}
|
||||
112
lib/Jaris/src/jaris/player/UserSettings.hx
Normal file
112
lib/Jaris/src/jaris/player/UserSettings.hx
Normal file
@ -0,0 +1,112 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player;
|
||||
|
||||
import flash.net.SharedObject;
|
||||
|
||||
|
||||
/**
|
||||
* To store and retrieve user settings so the player can load them next time it loads.
|
||||
* In this way player can remember user selected aspect ratio and volume.
|
||||
*/
|
||||
class UserSettings
|
||||
{
|
||||
private var _settings:SharedObject;
|
||||
|
||||
public function new()
|
||||
{
|
||||
_settings = SharedObject.getLocal("JarisPlayerUserSettings");
|
||||
}
|
||||
|
||||
//{Methods
|
||||
/**
|
||||
* Deletes all user settings
|
||||
*/
|
||||
public function deleteSettings():Void
|
||||
{
|
||||
_settings.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a user setting is available
|
||||
* @param field The name of the setting
|
||||
* @return true if is set false otherwise
|
||||
*/
|
||||
public function isSet(field:String):Bool
|
||||
{
|
||||
return Reflect.hasField(_settings.data, field);
|
||||
}
|
||||
//}
|
||||
|
||||
//{Properties Setters
|
||||
/**
|
||||
* Stores the volume value
|
||||
* @param level
|
||||
*/
|
||||
public function setVolume(level:Float):Void
|
||||
{
|
||||
_settings.data.volume = level;
|
||||
_settings.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the aspect ratio value
|
||||
* @param aspect
|
||||
*/
|
||||
public function setAspectRatio(aspectratio:Float):Void
|
||||
{
|
||||
_settings.data.aspectratio = aspectratio;
|
||||
_settings.flush();
|
||||
}
|
||||
//}
|
||||
|
||||
//{Properties Getters
|
||||
/**
|
||||
* The last user selected volume value
|
||||
* @return Last user selected volume value or default if not set.
|
||||
*/
|
||||
public function getVolume():Float
|
||||
{
|
||||
if (!isSet("volume"))
|
||||
{
|
||||
return 1.0; //The maximum volume value
|
||||
}
|
||||
|
||||
return _settings.data.volume;
|
||||
}
|
||||
|
||||
/**
|
||||
* The last user selected aspect ratio value
|
||||
* @return Last user selected aspect ratio value or default if not set.
|
||||
*/
|
||||
public function getAspectRatio():Float
|
||||
{
|
||||
if (!isSet("aspectratio"))
|
||||
{
|
||||
return 0.0; //Equivalent to original
|
||||
}
|
||||
|
||||
return _settings.data.aspectratio;
|
||||
}
|
||||
//}
|
||||
}
|
||||
119
lib/Jaris/src/jaris/player/controls/AspectRatioIcon.hx
Normal file
119
lib/Jaris/src/jaris/player/controls/AspectRatioIcon.hx
Normal file
@ -0,0 +1,119 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player.controls;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.MouseEvent;
|
||||
|
||||
class AspectRatioIcon extends Sprite
|
||||
{
|
||||
private var _width:Float;
|
||||
private var _height:Float;
|
||||
private var _normalColor:UInt;
|
||||
private var _hoverColor:UInt;
|
||||
|
||||
public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt)
|
||||
{
|
||||
super();
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.buttonMode = true;
|
||||
this.useHandCursor = true;
|
||||
this.tabEnabled = false;
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
_normalColor = normalColor;
|
||||
_hoverColor = hoverColor;
|
||||
|
||||
addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
|
||||
addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
private function onMouseOver(event:MouseEvent):Void
|
||||
{
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
private function onMouseOut(event:MouseEvent):Void
|
||||
{
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
//{Private Methods
|
||||
private function draw(color:UInt):Void
|
||||
{
|
||||
graphics.clear();
|
||||
|
||||
graphics.lineStyle(2, color);
|
||||
graphics.drawRect(0, 0, _width, _height);
|
||||
|
||||
var innerWidth:Float = (60 / 100) * width;
|
||||
var innerHeight:Float = (60 / 100) * height;
|
||||
var innerX:Float = (width / 2) - (innerWidth / 2) - 1;
|
||||
var innerY:Float = (height / 2) - (innerHeight / 2) - 1;
|
||||
|
||||
graphics.lineStyle();
|
||||
graphics.beginFill(color, 1);
|
||||
graphics.drawRect(innerX, innerY, innerWidth, innerHeight);
|
||||
graphics.endFill();
|
||||
|
||||
graphics.lineStyle();
|
||||
graphics.beginFill(0, 0);
|
||||
graphics.drawRect(0, 0, width, height);
|
||||
graphics.endFill();
|
||||
}
|
||||
//}
|
||||
|
||||
//{Setters
|
||||
public function setNormalColor(color:UInt):Void
|
||||
{
|
||||
_normalColor = color;
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setHoverColor(color:UInt):Void
|
||||
{
|
||||
_hoverColor = color;
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
public function setPosition(x:Float, y:Float):Void
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setSize(width:Float, height:Float):Void
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
//}
|
||||
}
|
||||
912
lib/Jaris/src/jaris/player/controls/Controls.hx
Normal file
912
lib/Jaris/src/jaris/player/controls/Controls.hx
Normal file
@ -0,0 +1,912 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player.controls;
|
||||
|
||||
//{Libraries
|
||||
import flash.display.GradientType;
|
||||
import flash.events.Event;
|
||||
import flash.events.TimerEvent;
|
||||
import flash.geom.Matrix;
|
||||
import flash.Lib;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.display.MovieClip;
|
||||
import flash.net.NetStream;
|
||||
import flash.geom.Rectangle;
|
||||
import flash.text.AntiAliasType;
|
||||
import flash.text.TextField;
|
||||
import flash.text.TextFieldAutoSize;
|
||||
import flash.text.TextFormat;
|
||||
import flash.utils.Timer;
|
||||
import jaris.animation.Animation;
|
||||
import jaris.display.Loader;
|
||||
import jaris.events.PlayerEvents;
|
||||
import jaris.player.controls.AspectRatioIcon;
|
||||
import jaris.player.controls.FullscreenIcon;
|
||||
import jaris.player.controls.PauseIcon;
|
||||
import jaris.player.controls.PlayIcon;
|
||||
import jaris.player.controls.VolumeIcon;
|
||||
import jaris.player.Player;
|
||||
import flash.display.Sprite;
|
||||
import flash.display.Stage;
|
||||
import jaris.utils.Utils;
|
||||
//}
|
||||
|
||||
/**
|
||||
* Default controls for jaris player
|
||||
*/
|
||||
class Controls extends MovieClip {
|
||||
|
||||
//{Member Variables
|
||||
private var _thumb:Sprite;
|
||||
private var _track:Sprite;
|
||||
private var _trackDownloaded:Sprite;
|
||||
private var _scrubbing:Bool;
|
||||
private var _stage:Stage;
|
||||
private var _movieClip:MovieClip;
|
||||
private var _player:Player;
|
||||
private var _darkColor:UInt;
|
||||
private var _brightColor:UInt;
|
||||
private var _controlColor:UInt;
|
||||
private var _hoverColor:UInt;
|
||||
private var _hideControlsTimer:Timer;
|
||||
private var _hideAspectRatioLabelTimer:Timer;
|
||||
private var _currentPlayTimeLabel:TextField;
|
||||
private var _totalPlayTimeLabel:TextField;
|
||||
private var _seekPlayTimeLabel:TextField;
|
||||
private var _percentLoaded:Float;
|
||||
private var _controlsVisible:Bool;
|
||||
private var _seekBar:Sprite;
|
||||
private var _controlsBar:Sprite;
|
||||
private var _playControl:PlayIcon;
|
||||
private var _pauseControl:PauseIcon;
|
||||
private var _aspectRatioControl:AspectRatioIcon;
|
||||
private var _fullscreenControl:FullscreenIcon;
|
||||
private var _volumeIcon:VolumeIcon;
|
||||
private var _volumeTrack:Sprite;
|
||||
private var _volumeSlider:Sprite;
|
||||
private var _loader:Loader;
|
||||
private var _aspectRatioLabelContainer:Sprite;
|
||||
private var _aspectRatioLabel:TextField;
|
||||
private var _textFormat:TextFormat;
|
||||
//}
|
||||
|
||||
|
||||
//{Constructor
|
||||
public function new(player:Player)
|
||||
{
|
||||
super();
|
||||
|
||||
//{Main variables
|
||||
_stage = Lib.current.stage;
|
||||
_movieClip = Lib.current;
|
||||
_player = player;
|
||||
_darkColor = 0x000000;
|
||||
_brightColor = 0x4c4c4c;
|
||||
_controlColor = 0xFFFFFF;
|
||||
_hoverColor = 0x67A8C1;
|
||||
_percentLoaded = 0.0;
|
||||
_hideControlsTimer = new Timer(500);
|
||||
_hideAspectRatioLabelTimer = new Timer(500);
|
||||
_controlsVisible = false;
|
||||
|
||||
_textFormat = new TextFormat();
|
||||
_textFormat.font = "arial";
|
||||
_textFormat.color = _controlColor;
|
||||
_textFormat.size = 14;
|
||||
//}
|
||||
|
||||
//{Seeking Controls initialization
|
||||
_seekBar = new Sprite();
|
||||
addChild(_seekBar);
|
||||
|
||||
_trackDownloaded = new Sprite( );
|
||||
_trackDownloaded.tabEnabled = false;
|
||||
_seekBar.addChild(_trackDownloaded);
|
||||
|
||||
_track = new Sprite( );
|
||||
_track.tabEnabled = false;
|
||||
_track.buttonMode = true;
|
||||
_track.useHandCursor = true;
|
||||
_seekBar.addChild(_track);
|
||||
|
||||
|
||||
_thumb = new Sprite( );
|
||||
_thumb.buttonMode = true;
|
||||
_thumb.useHandCursor = true;
|
||||
_thumb.tabEnabled = false;
|
||||
_seekBar.addChild(_thumb);
|
||||
|
||||
_currentPlayTimeLabel = new TextField();
|
||||
_currentPlayTimeLabel.autoSize = TextFieldAutoSize.LEFT;
|
||||
_currentPlayTimeLabel.text = "00:00:00";
|
||||
_currentPlayTimeLabel.tabEnabled = false;
|
||||
_currentPlayTimeLabel.setTextFormat(_textFormat);
|
||||
_seekBar.addChild(_currentPlayTimeLabel);
|
||||
|
||||
_totalPlayTimeLabel = new TextField();
|
||||
_totalPlayTimeLabel.autoSize = TextFieldAutoSize.LEFT;
|
||||
_totalPlayTimeLabel.text = "00:00:00";
|
||||
_totalPlayTimeLabel.tabEnabled = false;
|
||||
_totalPlayTimeLabel.setTextFormat(_textFormat);
|
||||
_seekBar.addChild(_totalPlayTimeLabel);
|
||||
|
||||
_seekPlayTimeLabel = new TextField();
|
||||
_seekPlayTimeLabel.visible = false;
|
||||
_seekPlayTimeLabel.autoSize = TextFieldAutoSize.LEFT;
|
||||
_seekPlayTimeLabel.text = "00:00:00";
|
||||
_seekPlayTimeLabel.tabEnabled = false;
|
||||
_seekPlayTimeLabel.setTextFormat(_textFormat);
|
||||
addChild(_seekPlayTimeLabel);
|
||||
//}
|
||||
|
||||
//{Playing controls initialization
|
||||
_controlsBar = new Sprite();
|
||||
_controlsBar.visible = true;
|
||||
addChild(_controlsBar);
|
||||
|
||||
_playControl = new PlayIcon(0, 0, 0, 0, _controlColor, _hoverColor);
|
||||
_controlsBar.addChild(_playControl);
|
||||
|
||||
_pauseControl = new PauseIcon(0, 0, 0, 0, _controlColor, _hoverColor);
|
||||
_pauseControl.visible = false;
|
||||
_controlsBar.addChild(_pauseControl);
|
||||
|
||||
_aspectRatioControl = new AspectRatioIcon(0, 0, 0, 0, _controlColor, _hoverColor);
|
||||
_controlsBar.addChild(_aspectRatioControl);
|
||||
|
||||
_fullscreenControl = new FullscreenIcon(0, 0, 0, 0, _controlColor, _hoverColor);
|
||||
_controlsBar.addChild(_fullscreenControl);
|
||||
|
||||
_volumeIcon = new VolumeIcon(0, 0, 0, 0, _controlColor, _hoverColor);
|
||||
_controlsBar.addChild(_volumeIcon);
|
||||
|
||||
_volumeSlider = new Sprite();
|
||||
_controlsBar.addChild(_volumeSlider);
|
||||
|
||||
_volumeTrack = new Sprite();
|
||||
_volumeTrack.buttonMode = true;
|
||||
_volumeTrack.useHandCursor = true;
|
||||
_volumeTrack.tabEnabled = false;
|
||||
_controlsBar.addChild(_volumeTrack);
|
||||
//}
|
||||
|
||||
//{Aspect ratio label
|
||||
_aspectRatioLabelContainer = new Sprite();
|
||||
addChild(_aspectRatioLabelContainer);
|
||||
|
||||
_aspectRatioLabel = new TextField();
|
||||
_aspectRatioLabel.autoSize = TextFieldAutoSize.CENTER;
|
||||
_aspectRatioLabel.text = "original";
|
||||
_aspectRatioLabel.tabEnabled = false;
|
||||
_aspectRatioLabelContainer.addChild(_aspectRatioLabel);
|
||||
//}
|
||||
|
||||
redrawControls();
|
||||
|
||||
//{Loader bar
|
||||
_loader = new Loader();
|
||||
_loader.hide();
|
||||
|
||||
var loaderColors:Array <String> = ["", "", "", ""];
|
||||
loaderColors[0] = Std.string(_brightColor);
|
||||
loaderColors[1] = Std.string(_controlColor);
|
||||
|
||||
_loader.setColors(loaderColors);
|
||||
|
||||
addChild(_loader);
|
||||
//}
|
||||
|
||||
//{event Listeners
|
||||
_movieClip.addEventListener(Event.ENTER_FRAME, onEnterFrame);
|
||||
_thumb.addEventListener(MouseEvent.MOUSE_DOWN, onThumbMouseDown);
|
||||
_thumb.addEventListener(MouseEvent.MOUSE_UP, onThumbMouseUp);
|
||||
_thumb.addEventListener(MouseEvent.MOUSE_OVER, onThumbHover);
|
||||
_thumb.addEventListener(MouseEvent.MOUSE_OUT, onThumbMouseOut);
|
||||
_thumb.addEventListener(MouseEvent.MOUSE_MOVE, onTrackMouseMove);
|
||||
_thumb.addEventListener(MouseEvent.MOUSE_OUT, onTrackMouseOut);
|
||||
_track.addEventListener(MouseEvent.CLICK, onTrackClick);
|
||||
_track.addEventListener(MouseEvent.MOUSE_MOVE, onTrackMouseMove);
|
||||
_track.addEventListener(MouseEvent.MOUSE_OUT, onTrackMouseOut);
|
||||
_playControl.addEventListener(MouseEvent.CLICK, onPlayClick);
|
||||
_pauseControl.addEventListener(MouseEvent.CLICK, onPauseClick);
|
||||
_aspectRatioControl.addEventListener(MouseEvent.CLICK, onAspectRatioClick);
|
||||
_fullscreenControl.addEventListener(MouseEvent.CLICK, onFullscreenClick);
|
||||
_volumeIcon.addEventListener(MouseEvent.CLICK, onVolumeIconClick);
|
||||
_volumeTrack.addEventListener(MouseEvent.CLICK, onVolumeTrackClick);
|
||||
|
||||
_player.addEventListener(PlayerEvents.MOUSE_HIDE, onPlayerMouseHide);
|
||||
_player.addEventListener(PlayerEvents.MOUSE_SHOW, onPlayerMouseShow);
|
||||
_player.addEventListener(PlayerEvents.MEDIA_INITIALIZED, onPlayerMediaInitialized);
|
||||
_player.addEventListener(PlayerEvents.BUFFERING, onPlayerBuffering);
|
||||
_player.addEventListener(PlayerEvents.NOT_BUFFERING, onPlayerNotBuffering);
|
||||
_player.addEventListener(PlayerEvents.RESIZE, onPlayerResize);
|
||||
_player.addEventListener(PlayerEvents.PLAY_PAUSE, onPlayerPlayPause);
|
||||
_player.addEventListener(PlayerEvents.PLAYBACK_FINISHED, onPlayerPlaybackFinished);
|
||||
_player.addEventListener(PlayerEvents.CONNECTION_FAILED, onPlayerStreamNotFound);
|
||||
_player.addEventListener(PlayerEvents.ASPECT_RATIO, onPlayerAspectRatio);
|
||||
|
||||
_stage.addEventListener(MouseEvent.MOUSE_UP, onThumbMouseUp);
|
||||
_stage.addEventListener(MouseEvent.MOUSE_OUT, onThumbMouseUp);
|
||||
_stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
|
||||
_stage.addEventListener(Event.RESIZE, onStageResize);
|
||||
|
||||
_hideControlsTimer.addEventListener(TimerEvent.TIMER, hideControlsTimer);
|
||||
_hideAspectRatioLabelTimer.addEventListener(TimerEvent.TIMER, hideAspectRatioLabelTimer);
|
||||
|
||||
_hideControlsTimer.start();
|
||||
//}
|
||||
}
|
||||
//}
|
||||
|
||||
|
||||
//{Timers
|
||||
/**
|
||||
* Hides the playing controls when not moving mouse.
|
||||
* @param event The timer event associated
|
||||
*/
|
||||
private function hideControlsTimer(event:TimerEvent):Void
|
||||
{
|
||||
if (_player.isPlaying())
|
||||
{
|
||||
if (_controlsVisible)
|
||||
{
|
||||
if (_stage.mouseX < _controlsBar.x ||
|
||||
_stage.mouseX >= _stage.stageWidth - 1 ||
|
||||
_stage.mouseY >= _stage.stageHeight - 1 ||
|
||||
_stage.mouseY <= 1
|
||||
)
|
||||
{
|
||||
_controlsVisible = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hideControls();
|
||||
_hideControlsTimer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides aspect ratio label
|
||||
* @param event
|
||||
*/
|
||||
private function hideAspectRatioLabelTimer(event:TimerEvent):Void
|
||||
{
|
||||
//wait till fade in effect finish
|
||||
if (_aspectRatioLabelContainer.alpha >= 1)
|
||||
{
|
||||
Animation.fadeOut(_aspectRatioLabelContainer, 300);
|
||||
_hideAspectRatioLabelTimer.stop();
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
|
||||
//{Events
|
||||
/**
|
||||
* Keeps syncronized various elements of the controls like the thumb and download track bar
|
||||
* @param event
|
||||
*/
|
||||
private function onEnterFrame(event:Event):Void
|
||||
{
|
||||
if(_player.getDuration() > 0) {
|
||||
if (_scrubbing)
|
||||
{
|
||||
_player.seek(((_thumb.x - _track.x) / _track.width) * _player.getDuration());
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentPlayTimeLabel.text = Utils.formatTime(_player.getCurrentTime());
|
||||
_currentPlayTimeLabel.setTextFormat(_textFormat);
|
||||
_thumb.x = _player.getCurrentTime() / _player.getDuration() * (_track.width-_thumb.width) + _track.x;
|
||||
}
|
||||
}
|
||||
|
||||
_volumeSlider.height = _volumeTrack.height * (_player.getVolume() / 1.0);
|
||||
_volumeSlider.y = (_volumeTrack.y + _volumeTrack.height) - _volumeSlider.height;
|
||||
|
||||
drawDownloadProgress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show playing controls on mouse movement.
|
||||
* @param event
|
||||
*/
|
||||
private function onMouseMove(event:MouseEvent):Void
|
||||
{
|
||||
if (_stage.mouseX >= _controlsBar.x)
|
||||
{
|
||||
if (!_hideControlsTimer.running)
|
||||
{
|
||||
_hideControlsTimer.start();
|
||||
}
|
||||
|
||||
_controlsVisible = true;
|
||||
showControls();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function fired by a stage resize eventthat redraws the player controls
|
||||
* @param event
|
||||
*/
|
||||
private function onStageResize(event:Event):Void
|
||||
{
|
||||
redrawControls();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles pause or play
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayClick(event:MouseEvent):Void
|
||||
{
|
||||
_player.togglePlay();
|
||||
_playControl.visible = !_player.isPlaying();
|
||||
_pauseControl.visible = _player.isPlaying();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles pause or play
|
||||
* @param event
|
||||
*/
|
||||
private function onPauseClick(event:MouseEvent):Void
|
||||
{
|
||||
_player.togglePlay();
|
||||
_playControl.visible = !_player.isPlaying();
|
||||
_pauseControl.visible = _player.isPlaying();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles betewen aspect ratios
|
||||
* @param event
|
||||
*/
|
||||
private function onAspectRatioClick(event:MouseEvent):Void
|
||||
{
|
||||
_player.toggleAspectRatio();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles between window and fullscreen mode
|
||||
* @param event
|
||||
*/
|
||||
private function onFullscreenClick(event:MouseEvent):Void
|
||||
{
|
||||
_player.toggleFullscreen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles between mute and unmute
|
||||
* @param event
|
||||
*/
|
||||
private function onVolumeIconClick(event: MouseEvent):Void
|
||||
{
|
||||
_player.toggleMute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect user click on volume track control and change volume according
|
||||
* @param event
|
||||
*/
|
||||
private function onVolumeTrackClick(event:MouseEvent):Void
|
||||
{
|
||||
var percent:Float = _volumeTrack.height - _volumeTrack.mouseY;
|
||||
var volume:Float = 1.0 * (percent / _volumeTrack.height);
|
||||
|
||||
_player.setVolume(volume);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display not found message
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerStreamNotFound(event:PlayerEvents):Void
|
||||
{
|
||||
//todo: to work on this
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the loader bar when buffering
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerBuffering(event:PlayerEvents):Void
|
||||
{
|
||||
_loader.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides loader bar when not buffering
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerNotBuffering(event:PlayerEvents):Void
|
||||
{
|
||||
_loader.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the selected aspect ratio
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerAspectRatio(event:PlayerEvents):Void
|
||||
{
|
||||
_hideAspectRatioLabelTimer.stop();
|
||||
_aspectRatioLabel.text = _player.getAspectRatioString();
|
||||
drawAspectRatioLabel();
|
||||
|
||||
while (_aspectRatioLabelContainer.visible)
|
||||
{
|
||||
//wait till fade out finishes
|
||||
}
|
||||
|
||||
Animation.fadeIn(_aspectRatioLabelContainer, 300);
|
||||
|
||||
_hideAspectRatioLabelTimer.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitors playbeack when finishes tu update controls
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerPlaybackFinished(event:PlayerEvents):Void
|
||||
{
|
||||
_playControl.visible = !_player.isPlaying();
|
||||
_pauseControl.visible = _player.isPlaying();
|
||||
showControls();
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitors keyboard play pause actions to update icons
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerPlayPause(event:PlayerEvents):Void
|
||||
{
|
||||
_playControl.visible = !_player.isPlaying();
|
||||
_pauseControl.visible = _player.isPlaying();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes the video player on windowed mode substracting the seekbar height
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerResize(event:PlayerEvents):Void
|
||||
{
|
||||
if (!_player.isFullscreen())
|
||||
{
|
||||
if (_player.getVideo().y + _player.getVideo().height >= _stage.stageHeight)
|
||||
{
|
||||
_player.getVideo().height = _stage.stageHeight - _seekBar.height;
|
||||
_player.getVideo().width = _player.getVideo().height * _player.getAspectRatio();
|
||||
|
||||
_player.getVideo().x = (_stage.stageWidth / 2) - (_player.getVideo().width / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates media total time duration.
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerMediaInitialized(event:PlayerEvents):Void
|
||||
{
|
||||
_totalPlayTimeLabel.text = Utils.formatTime(event.duration);
|
||||
_totalPlayTimeLabel.setTextFormat(_textFormat);
|
||||
|
||||
_playControl.visible = !_player.isPlaying();
|
||||
_pauseControl.visible = _player.isPlaying();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides seekbar if on fullscreen.
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerMouseHide(event:PlayerEvents):Void
|
||||
{
|
||||
if (_seekBar.visible && _player.isFullscreen())
|
||||
{
|
||||
Animation.slideOut(_seekBar, "bottom", 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows seekbar
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerMouseShow(event:PlayerEvents):Void
|
||||
{
|
||||
//Only use slidein effect on fullscreen since switching to windowed mode on
|
||||
//hardware scaling causes a bug by a slow response on stage height changes
|
||||
if (_player.isFullscreen() && !_seekBar.visible)
|
||||
{
|
||||
Animation.slideIn(_seekBar, "bottom",1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
_seekBar.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a user click in to time and seeks to it
|
||||
* @param event
|
||||
*/
|
||||
private function onTrackClick(event:MouseEvent):Void
|
||||
{
|
||||
var clickPosition:Float = _track.mouseX;
|
||||
_player.seek(_player.getDuration() * (clickPosition / _track.width));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a small tooltip showing the time calculated by mouse position
|
||||
* @param event
|
||||
*/
|
||||
private function onTrackMouseMove(event:MouseEvent):Void
|
||||
{
|
||||
var clickPosition:Float = _track.mouseX;
|
||||
_seekPlayTimeLabel.text = Utils.formatTime(_player.getDuration() * (clickPosition / _track.width));
|
||||
_seekPlayTimeLabel.setTextFormat(_textFormat);
|
||||
|
||||
_seekPlayTimeLabel.y = _stage.stageHeight - _seekBar.height - _seekPlayTimeLabel.height - 1;
|
||||
_seekPlayTimeLabel.x = clickPosition + (_seekPlayTimeLabel.width / 2);
|
||||
|
||||
_seekPlayTimeLabel.backgroundColor = _brightColor;
|
||||
_seekPlayTimeLabel.background = true;
|
||||
_seekPlayTimeLabel.textColor = _controlColor;
|
||||
_seekPlayTimeLabel.borderColor = _darkColor;
|
||||
_seekPlayTimeLabel.border = true;
|
||||
|
||||
if (!_seekPlayTimeLabel.visible)
|
||||
{
|
||||
Animation.fadeIn(_seekPlayTimeLabel, 300);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the tooltip that shows the time calculated by mouse position
|
||||
* @param event
|
||||
*/
|
||||
private function onTrackMouseOut(event:MouseEvent):Void
|
||||
{
|
||||
Animation.fadeOut(_seekPlayTimeLabel, 300);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables dragging of thumb for seeking media
|
||||
* @param event
|
||||
*/
|
||||
private function onThumbMouseDown(event:MouseEvent):Void
|
||||
{
|
||||
_scrubbing = true;
|
||||
var rectangle:Rectangle = new Rectangle(_track.x, _track.y, _track.width-_thumb.width, 0);
|
||||
_thumb.startDrag(false, rectangle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes thumb seek control to hover color
|
||||
* @param event
|
||||
*/
|
||||
private function onThumbHover(event:MouseEvent):Void
|
||||
{
|
||||
_thumb.graphics.lineStyle();
|
||||
_thumb.graphics.beginFill(_hoverColor);
|
||||
_thumb.graphics.drawRect(0, (_seekBar.height/2)-(10/2), 10, 10);
|
||||
_thumb.graphics.endFill();
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes thumb seek control to control color
|
||||
* @param event
|
||||
*/
|
||||
private function onThumbMouseOut(event:MouseEvent):Void
|
||||
{
|
||||
_thumb.graphics.lineStyle();
|
||||
_thumb.graphics.beginFill(_controlColor);
|
||||
_thumb.graphics.drawRect(0, (_seekBar.height/2)-(10/2), 10, 10);
|
||||
_thumb.graphics.endFill();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables dragging of thumb
|
||||
* @param event
|
||||
*/
|
||||
private function onThumbMouseUp(event:MouseEvent):Void
|
||||
{
|
||||
_scrubbing = false;
|
||||
_thumb.stopDrag( );
|
||||
}
|
||||
//}
|
||||
|
||||
|
||||
//{Drawing functions
|
||||
/**
|
||||
* Clears all current graphics a draw new ones
|
||||
*/
|
||||
private function redrawControls():Void
|
||||
{
|
||||
drawSeekControls();
|
||||
drawPlayingControls();
|
||||
drawAspectRatioLabel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the download progress track bar
|
||||
*/
|
||||
private function drawDownloadProgress():Void
|
||||
{
|
||||
if (_player.getBytesTotal() > 0)
|
||||
{
|
||||
var bytesLoaded:Float = _player.getBytesLoaded();
|
||||
var bytesTotal:Float = _player.getBytesTotal();
|
||||
|
||||
_percentLoaded = bytesLoaded / bytesTotal;
|
||||
}
|
||||
|
||||
var position:Float = _player.getStartTime() / _player.getDuration();
|
||||
//var startPosition:Float = (position * _track.width) + _track.x; //Old way
|
||||
var startPosition:Float = (position > 0?(position * _track.width):0) + _track.x;
|
||||
|
||||
_trackDownloaded.graphics.clear();
|
||||
_trackDownloaded.graphics.lineStyle();
|
||||
_trackDownloaded.x = startPosition;
|
||||
_trackDownloaded.graphics.beginFill(_brightColor, 0xFFFFFF);
|
||||
_trackDownloaded.graphics.drawRect(0, (_seekBar.height / 2) - (10 / 2), ((_track.width + _track.x) - _trackDownloaded.x) * _percentLoaded, 10);
|
||||
_trackDownloaded.graphics.endFill();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws all seekbar controls
|
||||
*/
|
||||
private function drawSeekControls()
|
||||
{
|
||||
//Reset sprites for redraw
|
||||
_seekBar.graphics.clear();
|
||||
_track.graphics.clear();
|
||||
_thumb.graphics.clear();
|
||||
|
||||
//Draw seek bar
|
||||
var _seekBarWidth:UInt = _stage.stageWidth;
|
||||
var _seekBarHeight:UInt = 25;
|
||||
_seekBar.x = 0;
|
||||
_seekBar.y = _stage.stageHeight - _seekBarHeight;
|
||||
var matrix:Matrix = new Matrix( );
|
||||
matrix.createGradientBox(_seekBarWidth, _seekBarHeight, Utils.degreesToRadians(90), 0, 0);
|
||||
var colors:Array<UInt> = [_brightColor, _darkColor];
|
||||
var alphas:Array<UInt> = [1, 1];
|
||||
var ratios:Array<UInt> = [0, 255];
|
||||
_seekBar.graphics.lineStyle();
|
||||
_seekBar.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix);
|
||||
_seekBar.graphics.drawRect(0, 0, _seekBarWidth, _seekBarHeight);
|
||||
_seekBar.graphics.endFill();
|
||||
|
||||
_textFormat.color = _controlColor;
|
||||
|
||||
//Draw current play time label
|
||||
_currentPlayTimeLabel.y = _seekBarHeight - (_seekBarHeight / 2) - (_currentPlayTimeLabel.height / 2);
|
||||
_currentPlayTimeLabel.antiAliasType = AntiAliasType.ADVANCED;
|
||||
_currentPlayTimeLabel.setTextFormat(_textFormat);
|
||||
|
||||
//Draw total play time label
|
||||
_totalPlayTimeLabel.x = _seekBarWidth - _totalPlayTimeLabel.width;
|
||||
_totalPlayTimeLabel.y = _seekBarHeight - (_seekBarHeight / 2) - (_totalPlayTimeLabel.height / 2);
|
||||
_totalPlayTimeLabel.antiAliasType = AntiAliasType.ADVANCED;
|
||||
_totalPlayTimeLabel.setTextFormat(_textFormat);
|
||||
|
||||
//Draw download progress
|
||||
drawDownloadProgress();
|
||||
|
||||
//Draw track place holder for drag
|
||||
_track.x = _currentPlayTimeLabel.width;
|
||||
_track.graphics.lineStyle(1, _controlColor);
|
||||
_track.graphics.beginFill(_darkColor, 0);
|
||||
_track.graphics.drawRect(0, (_seekBarHeight / 2) - (10 / 2), _seekBarWidth - _currentPlayTimeLabel.width - _totalPlayTimeLabel.width, 10);
|
||||
_track.graphics.endFill();
|
||||
|
||||
//Draw thumb
|
||||
_thumb.x = _currentPlayTimeLabel.width;
|
||||
_thumb.graphics.lineStyle();
|
||||
_thumb.graphics.beginFill(_controlColor);
|
||||
_thumb.graphics.drawRect(0, (_seekBarHeight/2)-(10/2), 10, 10);
|
||||
_thumb.graphics.endFill();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws control bar player controls
|
||||
*/
|
||||
private function drawPlayingControls():Void
|
||||
{
|
||||
//Reset sprites for redraw
|
||||
_controlsBar.graphics.clear();
|
||||
_volumeTrack.graphics.clear();
|
||||
_volumeSlider.graphics.clear();
|
||||
|
||||
//Draw controls bar
|
||||
var barMargin = _stage.stageHeight < 330 ? 5 : 25;
|
||||
var barHeight = _stage.stageHeight - _seekBar.height - (barMargin * 2);
|
||||
var barWidth = _stage.stageHeight < 330 ? 45 : 60;
|
||||
_controlsBar.x = (_stage.stageWidth - barWidth) + 20;
|
||||
_controlsBar.y = barMargin;
|
||||
|
||||
var matrix:Matrix = new Matrix( );
|
||||
matrix.createGradientBox(barWidth, barHeight, Utils.degreesToRadians(0), 0, barHeight);
|
||||
var colors:Array<UInt> = [_brightColor, _darkColor];
|
||||
var alphas:Array<Float> = [0.75, 0.75];
|
||||
var ratios:Array<UInt> = [0, 255];
|
||||
_controlsBar.graphics.lineStyle();
|
||||
_controlsBar.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix);
|
||||
_controlsBar.graphics.drawRoundRect(0, 0, barWidth, barHeight, 20, 20);
|
||||
_controlsBar.graphics.endFill();
|
||||
|
||||
var topMargin:Float = _stage.stageHeight < 330 ? 5 : 10;
|
||||
var barCenter:Float = (barWidth - 20) / 2;
|
||||
var buttonSize:Float = ((80 / 100) * (barWidth - 20));
|
||||
var buttonX:Float = buttonSize / 2;
|
||||
|
||||
//Draw playbutton
|
||||
_playControl.setNormalColor(_controlColor);
|
||||
_playControl.setHoverColor(_hoverColor);
|
||||
_playControl.setPosition(barCenter - buttonX, topMargin);
|
||||
_playControl.setSize(buttonSize, buttonSize);
|
||||
|
||||
//Draw pausebutton
|
||||
_pauseControl.setNormalColor(_controlColor);
|
||||
_pauseControl.setHoverColor(_hoverColor);
|
||||
_pauseControl.setPosition(_playControl.x, topMargin);
|
||||
_pauseControl.setSize(buttonSize, buttonSize);
|
||||
|
||||
//Draw aspec ratio button
|
||||
_aspectRatioControl.setNormalColor(_controlColor);
|
||||
_aspectRatioControl.setHoverColor(_hoverColor);
|
||||
_aspectRatioControl.setPosition(_playControl.x, (_playControl.y + buttonSize) + topMargin);
|
||||
_aspectRatioControl.setSize(buttonSize, buttonSize);
|
||||
|
||||
//Draw fullscreen button
|
||||
_fullscreenControl.setNormalColor(_controlColor);
|
||||
_fullscreenControl.setHoverColor(_hoverColor);
|
||||
_fullscreenControl.setPosition(_playControl.x, (_aspectRatioControl.y + _aspectRatioControl.height) + topMargin);
|
||||
_fullscreenControl.setSize(buttonSize, buttonSize);
|
||||
|
||||
//Draw volume icon
|
||||
_volumeIcon.setNormalColor(_controlColor);
|
||||
_volumeIcon.setHoverColor(_hoverColor);
|
||||
_volumeIcon.setPosition(_playControl.x, barHeight - _playControl.height - topMargin);
|
||||
_volumeIcon.setSize(buttonSize, buttonSize);
|
||||
|
||||
//Draw volume track
|
||||
_volumeTrack.x = _playControl.x;
|
||||
_volumeTrack.y = (_fullscreenControl.y + _fullscreenControl.height) + topMargin;
|
||||
_volumeTrack.graphics.lineStyle(1, _controlColor);
|
||||
_volumeTrack.graphics.beginFill(0x000000, 0);
|
||||
_volumeTrack.graphics.drawRect(0, 0, _playControl.width / 2, _volumeIcon.y - (_fullscreenControl.y + _fullscreenControl.height) - (topMargin*2));
|
||||
_volumeTrack.graphics.endFill();
|
||||
_volumeTrack.x = barCenter - (_volumeTrack.width / 2);
|
||||
|
||||
//Draw volume slider
|
||||
_volumeSlider.x = _volumeTrack.x;
|
||||
_volumeSlider.y = _volumeTrack.y;
|
||||
_volumeSlider.graphics.lineStyle();
|
||||
_volumeSlider.graphics.beginFill(_controlColor, 1);
|
||||
_volumeSlider.graphics.drawRect(0, 0, _volumeTrack.width, _volumeTrack.height);
|
||||
_volumeSlider.graphics.endFill();
|
||||
|
||||
}
|
||||
|
||||
private function drawAspectRatioLabel():Void
|
||||
{
|
||||
_aspectRatioLabelContainer.graphics.clear();
|
||||
_aspectRatioLabelContainer.visible = false;
|
||||
|
||||
//Update aspect ratio label
|
||||
var textFormat:TextFormat = new TextFormat();
|
||||
textFormat.font = "arial";
|
||||
textFormat.bold = true;
|
||||
textFormat.size = 40;
|
||||
textFormat.color = _controlColor;
|
||||
|
||||
_aspectRatioLabel.setTextFormat(textFormat);
|
||||
_aspectRatioLabel.x = (_stage.stageWidth / 2) - (_aspectRatioLabel.width / 2);
|
||||
_aspectRatioLabel.y = (_stage.stageHeight / 2) - (_aspectRatioLabel.height / 2);
|
||||
|
||||
//Draw aspect ratio label container
|
||||
_aspectRatioLabelContainer.x = _aspectRatioLabel.x - 10;
|
||||
_aspectRatioLabelContainer.y = _aspectRatioLabel.y - 10;
|
||||
_aspectRatioLabelContainer.graphics.lineStyle(3, _controlColor);
|
||||
_aspectRatioLabelContainer.graphics.beginFill(_brightColor, 1);
|
||||
_aspectRatioLabelContainer.graphics.drawRoundRect(0, 0, _aspectRatioLabel.width + 20, _aspectRatioLabel.height + 20, 15, 15);
|
||||
_aspectRatioLabelContainer.graphics.endFill();
|
||||
|
||||
_aspectRatioLabel.x = 10;
|
||||
_aspectRatioLabel.y = 10;
|
||||
}
|
||||
//}
|
||||
|
||||
|
||||
//{Private Methods
|
||||
/**
|
||||
* Hide the play controls bar
|
||||
*/
|
||||
private function hideControls():Void
|
||||
{
|
||||
if(_controlsBar.visible)
|
||||
{
|
||||
drawPlayingControls();
|
||||
Animation.slideOut(_controlsBar, "right", 800);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows play controls bar
|
||||
*/
|
||||
private function showControls():Void
|
||||
{
|
||||
if(!_controlsBar.visible)
|
||||
{
|
||||
drawPlayingControls();
|
||||
Animation.slideIn(_controlsBar, "right", 800);
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
|
||||
//{Setters
|
||||
/**
|
||||
* Sets the player colors and redraw them
|
||||
* @param colors Array of colors in the following order: darkColor, brightColor, controlColor, hoverColor
|
||||
*/
|
||||
public function setControlColors(colors:Array<String>):Void
|
||||
{
|
||||
_darkColor = colors[0].length > 0? Std.parseInt("0x" + colors[0]) : 0x000000;
|
||||
_brightColor = colors[1].length > 0? Std.parseInt("0x" + colors[1]) : 0x4c4c4c;
|
||||
_controlColor = colors[2].length > 0? Std.parseInt("0x" + colors[2]) : 0xFFFFFF;
|
||||
_hoverColor = colors[3].length > 0? Std.parseInt("0x" + colors[3]) : 0x67A8C1;
|
||||
|
||||
var loaderColors:Array <String> = ["", ""];
|
||||
loaderColors[0] = colors[1];
|
||||
loaderColors[1] = colors[2];
|
||||
_loader.setColors(loaderColors);
|
||||
|
||||
redrawControls();
|
||||
}
|
||||
|
||||
/**
|
||||
* To set the duration label when autostart parameter is false
|
||||
* @param duration in seconds or formatted string in format hh:mm:ss
|
||||
*/
|
||||
public function setDurationLabel(duration:String):Void
|
||||
{
|
||||
//Person passed time already formatted
|
||||
if (duration.indexOf(":") != -1)
|
||||
{
|
||||
_totalPlayTimeLabel.text = duration;
|
||||
}
|
||||
|
||||
//Time passed in seconds
|
||||
else
|
||||
{
|
||||
_totalPlayTimeLabel.text = Std.string(Utils.formatTime(Std.parseFloat(duration)));
|
||||
}
|
||||
|
||||
_totalPlayTimeLabel.setTextFormat(_textFormat);
|
||||
}
|
||||
//}
|
||||
|
||||
}
|
||||
114
lib/Jaris/src/jaris/player/controls/FullscreenIcon.hx
Normal file
114
lib/Jaris/src/jaris/player/controls/FullscreenIcon.hx
Normal file
@ -0,0 +1,114 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player.controls;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.MouseEvent;
|
||||
|
||||
class FullscreenIcon extends Sprite
|
||||
{
|
||||
private var _width:Float;
|
||||
private var _height:Float;
|
||||
private var _normalColor:UInt;
|
||||
private var _hoverColor:UInt;
|
||||
|
||||
public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt)
|
||||
{
|
||||
super();
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.buttonMode = true;
|
||||
this.useHandCursor = true;
|
||||
this.tabEnabled = false;
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
_normalColor = normalColor;
|
||||
_hoverColor = hoverColor;
|
||||
|
||||
addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
|
||||
addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
private function onMouseOver(event:MouseEvent):Void
|
||||
{
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
private function onMouseOut(event:MouseEvent):Void
|
||||
{
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
//{Private Methods
|
||||
private function draw(color:UInt):Void
|
||||
{
|
||||
graphics.clear();
|
||||
|
||||
graphics.lineStyle(2, color);
|
||||
graphics.beginFill(0x000000, 0);
|
||||
graphics.drawRoundRect(0, 0, _width, _height, 6, 6);
|
||||
graphics.endFill();
|
||||
|
||||
graphics.lineStyle();
|
||||
graphics.beginFill(color, 1);
|
||||
graphics.drawRoundRect(3, 3, 4, 4, 2, 2);
|
||||
graphics.drawRoundRect(width - 9, 3, 4, 4, 2, 2);
|
||||
graphics.drawRoundRect(3, height - 9, 4, 4, 2, 2);
|
||||
graphics.drawRoundRect(width - 9, height - 9, 4, 4, 2, 2);
|
||||
graphics.endFill();
|
||||
}
|
||||
//}
|
||||
|
||||
//{Setters
|
||||
public function setNormalColor(color:UInt):Void
|
||||
{
|
||||
_normalColor = color;
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setHoverColor(color:UInt):Void
|
||||
{
|
||||
_hoverColor = color;
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
public function setPosition(x:Float, y:Float):Void
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setSize(width:Float, height:Float):Void
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
//}
|
||||
}
|
||||
112
lib/Jaris/src/jaris/player/controls/PauseIcon.hx
Normal file
112
lib/Jaris/src/jaris/player/controls/PauseIcon.hx
Normal file
@ -0,0 +1,112 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player.controls;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.MouseEvent;
|
||||
|
||||
class PauseIcon extends Sprite
|
||||
{
|
||||
private var _width:Float;
|
||||
private var _height:Float;
|
||||
private var _normalColor:UInt;
|
||||
private var _hoverColor:UInt;
|
||||
|
||||
public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt)
|
||||
{
|
||||
super();
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.buttonMode = true;
|
||||
this.useHandCursor = true;
|
||||
this.tabEnabled = false;
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
_normalColor = normalColor;
|
||||
_hoverColor = hoverColor;
|
||||
|
||||
addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
|
||||
addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
private function onMouseOver(event:MouseEvent):Void
|
||||
{
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
private function onMouseOut(event:MouseEvent):Void
|
||||
{
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
//{Private Methods
|
||||
private function draw(color:UInt):Void
|
||||
{
|
||||
graphics.clear();
|
||||
|
||||
graphics.lineStyle();
|
||||
graphics.beginFill(color);
|
||||
graphics.drawRoundRect(0, 0, (33 / 100) * _width, _height, 6, 6);
|
||||
graphics.drawRoundRect(_width - ((33 / 100) * _width), 0, (33 / 100) * _width, _height, 6, 6);
|
||||
graphics.endFill();
|
||||
|
||||
graphics.lineStyle();
|
||||
graphics.beginFill(color, 0);
|
||||
graphics.drawRect(0, 0, _width, _height);
|
||||
graphics.endFill();
|
||||
}
|
||||
//}
|
||||
|
||||
//{Setters
|
||||
public function setNormalColor(color:UInt):Void
|
||||
{
|
||||
_normalColor = color;
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setHoverColor(color:UInt):Void
|
||||
{
|
||||
_hoverColor = color;
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
public function setPosition(x:Float, y:Float):Void
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setSize(width:Float, height:Float):Void
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
//}
|
||||
}
|
||||
107
lib/Jaris/src/jaris/player/controls/PlayIcon.hx
Normal file
107
lib/Jaris/src/jaris/player/controls/PlayIcon.hx
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player.controls;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.MouseEvent;
|
||||
|
||||
class PlayIcon extends Sprite
|
||||
{
|
||||
private var _width:Float;
|
||||
private var _height:Float;
|
||||
private var _normalColor:UInt;
|
||||
private var _hoverColor:UInt;
|
||||
|
||||
public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt)
|
||||
{
|
||||
super();
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.buttonMode = true;
|
||||
this.useHandCursor = true;
|
||||
this.tabEnabled = false;
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
_normalColor = normalColor;
|
||||
_hoverColor = hoverColor;
|
||||
|
||||
addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
|
||||
addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
private function onMouseOver(event:MouseEvent):Void
|
||||
{
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
private function onMouseOut(event:MouseEvent):Void
|
||||
{
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
//{Private Methods
|
||||
private function draw(color:UInt):Void
|
||||
{
|
||||
graphics.clear();
|
||||
graphics.lineStyle();
|
||||
graphics.beginFill(color);
|
||||
graphics.lineTo(0, _height);
|
||||
graphics.lineTo(_width, _height / 2);
|
||||
graphics.lineTo(0, 0);
|
||||
graphics.endFill();
|
||||
}
|
||||
//}
|
||||
|
||||
//{Setters
|
||||
public function setNormalColor(color:UInt):Void
|
||||
{
|
||||
_normalColor = color;
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setHoverColor(color:UInt):Void
|
||||
{
|
||||
_hoverColor = color;
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
public function setPosition(x:Float, y:Float):Void
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setSize(width:Float, height:Float):Void
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
//}
|
||||
}
|
||||
110
lib/Jaris/src/jaris/player/controls/VolumeIcon.hx
Normal file
110
lib/Jaris/src/jaris/player/controls/VolumeIcon.hx
Normal file
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player.controls;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.MouseEvent;
|
||||
|
||||
class VolumeIcon extends Sprite
|
||||
{
|
||||
private var _width:Float;
|
||||
private var _height:Float;
|
||||
private var _normalColor:UInt;
|
||||
private var _hoverColor:UInt;
|
||||
|
||||
public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt)
|
||||
{
|
||||
super();
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.buttonMode = true;
|
||||
this.useHandCursor = true;
|
||||
this.tabEnabled = false;
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
_normalColor = normalColor;
|
||||
_hoverColor = hoverColor;
|
||||
|
||||
addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
|
||||
addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
private function onMouseOver(event:MouseEvent):Void
|
||||
{
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
private function onMouseOut(event:MouseEvent):Void
|
||||
{
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
//{Private Methods
|
||||
private function draw(color:UInt):Void
|
||||
{
|
||||
graphics.clear();
|
||||
|
||||
graphics.lineStyle();
|
||||
graphics.beginFill(color, 1);
|
||||
graphics.drawRect(0, ((50 / 100) * _height) / 2, _width / 2, ((50 / 100) * _height));
|
||||
graphics.moveTo(_width / 2, ((50 / 100) * _height)/2);
|
||||
graphics.lineTo(_width, 0);
|
||||
graphics.lineTo(_width, _height);
|
||||
graphics.lineTo(_width / 2, ((50 / 100) * _height) + (((50 / 100) * _height) / 2));
|
||||
graphics.endFill();
|
||||
}
|
||||
//}
|
||||
|
||||
//{Setters
|
||||
public function setNormalColor(color:UInt):Void
|
||||
{
|
||||
_normalColor = color;
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setHoverColor(color:UInt):Void
|
||||
{
|
||||
_hoverColor = color;
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
public function setPosition(x:Float, y:Float):Void
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setSize(width:Float, height:Float):Void
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
//}
|
||||
}
|
||||
130
lib/Jaris/src/jaris/player/newcontrols/AspectRatioIcon.hx
Normal file
130
lib/Jaris/src/jaris/player/newcontrols/AspectRatioIcon.hx
Normal file
@ -0,0 +1,130 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player.newcontrols;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.geom.Matrix;
|
||||
import jaris.utils.Utils;
|
||||
import flash.display.GradientType;
|
||||
|
||||
class AspectRatioIcon extends Sprite
|
||||
{
|
||||
private var _width:Float;
|
||||
private var _height:Float;
|
||||
private var _normalColor:UInt;
|
||||
private var _hoverColor:UInt;
|
||||
|
||||
public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt)
|
||||
{
|
||||
super();
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.buttonMode = true;
|
||||
this.useHandCursor = true;
|
||||
this.tabEnabled = false;
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
_normalColor = normalColor;
|
||||
_hoverColor = hoverColor;
|
||||
|
||||
addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
|
||||
addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
private function onMouseOver(event:MouseEvent):Void
|
||||
{
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
private function onMouseOut(event:MouseEvent):Void
|
||||
{
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
//{Private Methods
|
||||
private function draw(color:UInt):Void
|
||||
{
|
||||
graphics.clear();
|
||||
|
||||
graphics.lineStyle(0, color, 0.0);
|
||||
graphics.beginFill(color, 0);
|
||||
graphics.drawRect(0, 0, _width, _height);
|
||||
graphics.endFill();
|
||||
|
||||
var matrix:Matrix = new Matrix( );
|
||||
matrix.createGradientBox(_width, _height, Utils.degreesToRadians(-90), _width, 0);
|
||||
var colors:Array<UInt> = [color, color];
|
||||
var alphas:Array<Float> = [0.75, 1];
|
||||
var ratios:Array<UInt> = [0, 255];
|
||||
|
||||
var innerWidth:Float = (70 / 100) * width;
|
||||
var innerHeight:Float = (40 / 100) * height;
|
||||
var innerX:Float = (width / 2) - (innerWidth / 2) + 1 ;
|
||||
var innerY:Float = (height / 2) - (innerHeight / 2) + 1;
|
||||
|
||||
graphics.lineStyle();
|
||||
graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix);
|
||||
//graphics.beginFill(color, 1);
|
||||
graphics.drawRect(0, 0, 1, _height+1);
|
||||
graphics.drawRect(0, 0, _width+1, 1);
|
||||
graphics.drawRect(_width+1, 0, 1, _height+1);
|
||||
graphics.drawRect(0, _height+1, _width+1, 1);
|
||||
graphics.drawRect(innerX, innerY, innerWidth, innerHeight);
|
||||
graphics.endFill();
|
||||
}
|
||||
//}
|
||||
|
||||
//{Setters
|
||||
public function setNormalColor(color:UInt):Void
|
||||
{
|
||||
_normalColor = color;
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setHoverColor(color:UInt):Void
|
||||
{
|
||||
_hoverColor = color;
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
public function setPosition(x:Float, y:Float):Void
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setSize(width:Float, height:Float):Void
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
//}
|
||||
}
|
||||
130
lib/Jaris/src/jaris/player/newcontrols/FullscreenIcon.hx
Normal file
130
lib/Jaris/src/jaris/player/newcontrols/FullscreenIcon.hx
Normal file
@ -0,0 +1,130 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player.newcontrols;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.geom.Matrix;
|
||||
import jaris.utils.Utils;
|
||||
import flash.display.GradientType;
|
||||
|
||||
class FullscreenIcon extends Sprite
|
||||
{
|
||||
private var _width:Float;
|
||||
private var _height:Float;
|
||||
private var _normalColor:UInt;
|
||||
private var _hoverColor:UInt;
|
||||
|
||||
public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt)
|
||||
{
|
||||
super();
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.buttonMode = true;
|
||||
this.useHandCursor = true;
|
||||
this.tabEnabled = false;
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
_normalColor = normalColor;
|
||||
_hoverColor = hoverColor;
|
||||
|
||||
addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
|
||||
addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
private function onMouseOver(event:MouseEvent):Void
|
||||
{
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
private function onMouseOut(event:MouseEvent):Void
|
||||
{
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
//{Private Methods
|
||||
private function draw(color:UInt):Void
|
||||
{
|
||||
graphics.clear();
|
||||
|
||||
graphics.lineStyle(0, color, 0.0);
|
||||
graphics.beginFill(color, 0);
|
||||
graphics.drawRect(0, 0, _width, _height);
|
||||
graphics.endFill();
|
||||
|
||||
var arrowWidth = Std.int(_width / 2 * 0.8);
|
||||
|
||||
var matrix:Matrix = new Matrix( );
|
||||
matrix.createGradientBox(_width, _height, Utils.degreesToRadians(-90), _width, 0);
|
||||
var colors:Array<UInt> = [color, color];
|
||||
var alphas:Array<Float> = [0.75, 1];
|
||||
var ratios:Array<UInt> = [0, 255];
|
||||
|
||||
graphics.lineStyle(0, color, 0, true);
|
||||
graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix);
|
||||
//graphics.beginFill(color, 0);
|
||||
graphics.drawRect(0, 0, arrowWidth, 2);
|
||||
graphics.drawRect(0, 2, 2, arrowWidth-2);
|
||||
graphics.drawRect(_width-arrowWidth+1, 0, arrowWidth, 2);
|
||||
graphics.drawRect(_width-1, 2, 2, arrowWidth-2);
|
||||
graphics.drawRect(0, _height-arrowWidth+2, 2, arrowWidth);
|
||||
graphics.drawRect(2, _height, arrowWidth-2, 2);
|
||||
graphics.drawRect(_width-1, _height-arrowWidth+2, 2, arrowWidth-2);
|
||||
graphics.drawRect(_width-arrowWidth+1, _height, arrowWidth, 2);
|
||||
graphics.endFill();
|
||||
}
|
||||
//}
|
||||
|
||||
//{Setters
|
||||
public function setNormalColor(color:UInt):Void
|
||||
{
|
||||
_normalColor = color;
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setHoverColor(color:UInt):Void
|
||||
{
|
||||
_hoverColor = color;
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
public function setPosition(x:Float, y:Float):Void
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setSize(width:Float, height:Float):Void
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
//}
|
||||
}
|
||||
195
lib/Jaris/src/jaris/player/newcontrols/Loader.hx
Normal file
195
lib/Jaris/src/jaris/player/newcontrols/Loader.hx
Normal file
@ -0,0 +1,195 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player.newcontrols;
|
||||
|
||||
import flash.display.MovieClip;
|
||||
import flash.display.Sprite;
|
||||
import flash.display.Stage;
|
||||
import flash.events.Event;
|
||||
import flash.Lib;
|
||||
import flash.geom.Matrix;
|
||||
import jaris.utils.Utils;
|
||||
import flash.display.GradientType;
|
||||
|
||||
/**
|
||||
* Draws a loading bar
|
||||
*/
|
||||
class Loader extends Sprite
|
||||
{
|
||||
private var _stage:Stage;
|
||||
private var _movieClip:MovieClip;
|
||||
private var _background:Sprite;
|
||||
private var _loaderTrack:Sprite;
|
||||
private var _loaderThumb:Sprite;
|
||||
private var _visible:Bool;
|
||||
private var _darkColor:UInt;
|
||||
private var _controlColor:UInt;
|
||||
private var _seekColor:UInt;
|
||||
private var _forward:Bool;
|
||||
|
||||
public function new()
|
||||
{
|
||||
super();
|
||||
|
||||
_stage = Lib.current.stage;
|
||||
_movieClip = Lib.current;
|
||||
|
||||
_background = new Sprite();
|
||||
addChild(_background);
|
||||
|
||||
_loaderTrack = new Sprite();
|
||||
addChild(_loaderTrack);
|
||||
|
||||
_loaderThumb = new Sprite();
|
||||
addChild(_loaderThumb);
|
||||
|
||||
_darkColor = 0x000000;
|
||||
_controlColor = 0xFFFFFF;
|
||||
_seekColor = 0x747474;
|
||||
|
||||
_forward = true;
|
||||
_visible = true;
|
||||
|
||||
addEventListener(Event.ENTER_FRAME, onEnterFrame);
|
||||
_stage.addEventListener(Event.RESIZE, onResize);
|
||||
|
||||
drawLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Animation of a thumb moving on the track
|
||||
* @param event
|
||||
*/
|
||||
private function onEnterFrame(event:Event):Void
|
||||
{
|
||||
if (_visible)
|
||||
{
|
||||
if (_forward)
|
||||
{
|
||||
if ((_loaderThumb.x + _loaderThumb.width) >= (_loaderTrack.x + _loaderTrack.width))
|
||||
{
|
||||
_forward = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_loaderThumb.x += 10;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_loaderThumb.x <= _loaderTrack.x)
|
||||
{
|
||||
_forward = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_loaderThumb.x -= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redraws the loader to match new stage size
|
||||
* @param event
|
||||
*/
|
||||
private function onResize(event:Event):Void
|
||||
{
|
||||
drawLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw loader graphics
|
||||
*/
|
||||
private function drawLoader():Void
|
||||
{
|
||||
//Clear graphics
|
||||
_background.graphics.clear();
|
||||
_loaderTrack.graphics.clear();
|
||||
_loaderThumb.graphics.clear();
|
||||
|
||||
//Draw background
|
||||
var backgroundWidth:Float = (65 / 100) * _stage.stageWidth;
|
||||
var backgroundHeight:Float = 30;
|
||||
_background.x = (_stage.stageWidth / 2) - (backgroundWidth / 2);
|
||||
_background.y = (_stage.stageHeight / 2) - (backgroundHeight / 2);
|
||||
_background.graphics.lineStyle();
|
||||
_background.graphics.beginFill(_darkColor, 0.75);
|
||||
_background.graphics.drawRoundRect(0, 0, backgroundWidth, backgroundHeight, 6, 6);
|
||||
_background.graphics.endFill();
|
||||
|
||||
//Draw track
|
||||
var trackWidth:Float = (50 / 100) * _stage.stageWidth;
|
||||
var trackHeight:Float = 11;
|
||||
_loaderTrack.x = (_stage.stageWidth / 2) - (trackWidth / 2);
|
||||
_loaderTrack.y = (_stage.stageHeight / 2) - (trackHeight / 2);
|
||||
_loaderTrack.graphics.lineStyle();
|
||||
_loaderTrack.graphics.beginFill(_seekColor, 0.3);
|
||||
_loaderTrack.graphics.drawRoundRect(0, trackHeight/2/2, trackWidth, trackHeight/2, 5, 5);
|
||||
|
||||
//Draw thumb
|
||||
var matrix:Matrix = new Matrix( );
|
||||
matrix.createGradientBox(trackHeight*3, trackHeight, Utils.degreesToRadians(-90), trackHeight*3, 0);
|
||||
var colors:Array<UInt> = [_controlColor, _controlColor];
|
||||
var alphas:Array<Float> = [0.75, 1];
|
||||
var ratios:Array<UInt> = [0, 255];
|
||||
|
||||
_loaderThumb.x = _loaderTrack.x;
|
||||
_loaderThumb.y = _loaderTrack.y;
|
||||
_loaderThumb.graphics.lineStyle();
|
||||
_loaderThumb.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix);
|
||||
//_loaderThumb.graphics.beginFill(_controlColor, 1);
|
||||
_loaderThumb.graphics.drawRoundRect(0, 0, trackHeight*3, trackHeight, 10, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops drawing the loader
|
||||
*/
|
||||
public function hide():Void
|
||||
{
|
||||
this.visible = false;
|
||||
_visible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts drawing the loader
|
||||
*/
|
||||
public function show():Void
|
||||
{
|
||||
this.visible = true;
|
||||
_visible = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set loader colors
|
||||
* @param colors
|
||||
*/
|
||||
public function setColors(colors:Array<String>):Void
|
||||
{
|
||||
_darkColor = colors[0].length > 0? Std.parseInt("0x" + colors[0]) : 0x000000;
|
||||
_controlColor = colors[1].length > 0? Std.parseInt("0x" + colors[1]) : 0xFFFFFF;
|
||||
_seekColor = colors[2].length > 0? Std.parseInt("0x" + colors[2]) : 0x747474;
|
||||
|
||||
drawLoader();
|
||||
}
|
||||
}
|
||||
945
lib/Jaris/src/jaris/player/newcontrols/NewControls.hx
Normal file
945
lib/Jaris/src/jaris/player/newcontrols/NewControls.hx
Normal file
@ -0,0 +1,945 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player.newcontrols;
|
||||
|
||||
//{Libraries
|
||||
import flash.display.GradientType;
|
||||
import flash.events.Event;
|
||||
import flash.events.TimerEvent;
|
||||
import flash.geom.Matrix;
|
||||
import flash.Lib;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.display.MovieClip;
|
||||
import flash.net.NetStream;
|
||||
import flash.geom.Rectangle;
|
||||
import flash.text.AntiAliasType;
|
||||
import flash.text.TextField;
|
||||
import flash.text.TextFieldAutoSize;
|
||||
import flash.text.TextFormat;
|
||||
import flash.utils.Timer;
|
||||
import jaris.animation.Animation;
|
||||
import jaris.events.PlayerEvents;
|
||||
import jaris.player.newcontrols.Loader;
|
||||
import jaris.player.newcontrols.AspectRatioIcon;
|
||||
import jaris.player.newcontrols.FullscreenIcon;
|
||||
import jaris.player.newcontrols.PauseIcon;
|
||||
import jaris.player.newcontrols.PlayIcon;
|
||||
import jaris.player.newcontrols.VolumeIcon;
|
||||
import jaris.player.Player;
|
||||
import flash.display.Sprite;
|
||||
import flash.display.Stage;
|
||||
import jaris.utils.Utils;
|
||||
//}
|
||||
|
||||
/**
|
||||
* Default controls for jaris player
|
||||
*/
|
||||
class NewControls extends MovieClip {
|
||||
|
||||
//{Member Variables
|
||||
private var _thumb:Sprite;
|
||||
private var _track:Sprite;
|
||||
private var _trackDownloaded:Sprite;
|
||||
private var _scrubbing:Bool;
|
||||
private var _stage:Stage;
|
||||
private var _movieClip:MovieClip;
|
||||
private var _player:Player;
|
||||
private var _darkColor:UInt;
|
||||
private var _brightColor:UInt;
|
||||
private var _seekColor:UInt;
|
||||
private var _controlColor:UInt;
|
||||
private var _controlSize:Int;
|
||||
private var _hoverColor:UInt;
|
||||
private var _hideControlsTimer:Timer;
|
||||
private var _hideAspectRatioLabelTimer:Timer;
|
||||
private var _currentPlayTimeLabel:TextField;
|
||||
private var _totalPlayTimeLabel:TextField;
|
||||
private var _seekPlayTimeLabel:TextField;
|
||||
private var _percentLoaded:Float;
|
||||
private var _controlsVisible:Bool;
|
||||
private var _seekBar:Sprite;
|
||||
private var _controlsBar:Sprite;
|
||||
private var _playControl:PlayIcon;
|
||||
private var _pauseControl:PauseIcon;
|
||||
private var _aspectRatioControl:AspectRatioIcon;
|
||||
private var _fullscreenControl:FullscreenIcon;
|
||||
private var _volumeIcon:VolumeIcon;
|
||||
private var _volumeTrack:Sprite;
|
||||
private var _volumeSlider:Sprite;
|
||||
private var _loader:Loader;
|
||||
private var _aspectRatioLabelContainer:Sprite;
|
||||
private var _aspectRatioLabel:TextField;
|
||||
private var _textFormat:TextFormat;
|
||||
//}
|
||||
|
||||
|
||||
//{Constructor
|
||||
public function new(player:Player)
|
||||
{
|
||||
super();
|
||||
|
||||
//{Main variables
|
||||
_stage = Lib.current.stage;
|
||||
_movieClip = Lib.current;
|
||||
_player = player;
|
||||
_darkColor = 0x000000;
|
||||
_brightColor = 0x4c4c4c;
|
||||
_controlColor = 0xFFFFFF;
|
||||
_hoverColor = 0x67A8C1;
|
||||
_seekColor = 0x7c7c7c;
|
||||
_controlSize = 40;
|
||||
_percentLoaded = 0.0;
|
||||
_hideControlsTimer = new Timer(500);
|
||||
_hideAspectRatioLabelTimer = new Timer(500);
|
||||
_controlsVisible = false;
|
||||
|
||||
_textFormat = new TextFormat();
|
||||
_textFormat.font = "arial";
|
||||
_textFormat.color = _controlColor;
|
||||
_textFormat.size = 14;
|
||||
//}
|
||||
|
||||
//{Playing controls initialization
|
||||
_controlsBar = new Sprite();
|
||||
_controlsBar.visible = true;
|
||||
addChild(_controlsBar);
|
||||
|
||||
_playControl = new PlayIcon(0, 0, 0, 0, _controlColor, _hoverColor);
|
||||
_controlsBar.addChild(_playControl);
|
||||
|
||||
_pauseControl = new PauseIcon(0, 0, 0, 0, _controlColor, _hoverColor);
|
||||
_pauseControl.visible = false;
|
||||
_controlsBar.addChild(_pauseControl);
|
||||
|
||||
_aspectRatioControl = new AspectRatioIcon(0, 0, 0, 0, _controlColor, _hoverColor);
|
||||
_controlsBar.addChild(_aspectRatioControl);
|
||||
|
||||
_fullscreenControl = new FullscreenIcon(0, 0, 0, 0, _controlColor, _hoverColor);
|
||||
_controlsBar.addChild(_fullscreenControl);
|
||||
|
||||
_volumeIcon = new VolumeIcon(0, 0, 0, 0, _controlColor, _hoverColor);
|
||||
_controlsBar.addChild(_volumeIcon);
|
||||
|
||||
_volumeSlider = new Sprite();
|
||||
_volumeSlider.visible = false;
|
||||
_controlsBar.addChild(_volumeSlider);
|
||||
|
||||
_volumeTrack = new Sprite();
|
||||
_volumeTrack.visible = false;
|
||||
_volumeTrack.buttonMode = true;
|
||||
_volumeTrack.useHandCursor = true;
|
||||
_volumeTrack.tabEnabled = false;
|
||||
_controlsBar.addChild(_volumeTrack);
|
||||
//}
|
||||
|
||||
//{Seeking Controls initialization
|
||||
_seekBar = new Sprite();
|
||||
_controlsBar.addChild(_seekBar);
|
||||
|
||||
_trackDownloaded = new Sprite( );
|
||||
_trackDownloaded.tabEnabled = false;
|
||||
_seekBar.addChild(_trackDownloaded);
|
||||
|
||||
_track = new Sprite( );
|
||||
_track.tabEnabled = false;
|
||||
_track.buttonMode = true;
|
||||
_track.useHandCursor = true;
|
||||
_seekBar.addChild(_track);
|
||||
|
||||
_thumb = new Sprite( );
|
||||
_thumb.buttonMode = true;
|
||||
_thumb.useHandCursor = true;
|
||||
_thumb.tabEnabled = false;
|
||||
_seekBar.addChild(_thumb);
|
||||
|
||||
_currentPlayTimeLabel = new TextField();
|
||||
_currentPlayTimeLabel.autoSize = TextFieldAutoSize.LEFT;
|
||||
_currentPlayTimeLabel.text = "00:00:00";
|
||||
_currentPlayTimeLabel.tabEnabled = false;
|
||||
_currentPlayTimeLabel.setTextFormat(_textFormat);
|
||||
_seekBar.addChild(_currentPlayTimeLabel);
|
||||
|
||||
_totalPlayTimeLabel = new TextField();
|
||||
_totalPlayTimeLabel.autoSize = TextFieldAutoSize.LEFT;
|
||||
_totalPlayTimeLabel.text = "00:00:00";
|
||||
_totalPlayTimeLabel.tabEnabled = false;
|
||||
_totalPlayTimeLabel.setTextFormat(_textFormat);
|
||||
_seekBar.addChild(_totalPlayTimeLabel);
|
||||
|
||||
_seekPlayTimeLabel = new TextField();
|
||||
_seekPlayTimeLabel.visible = false;
|
||||
_seekPlayTimeLabel.autoSize = TextFieldAutoSize.LEFT;
|
||||
_seekPlayTimeLabel.text = "00:00:00";
|
||||
_seekPlayTimeLabel.tabEnabled = false;
|
||||
_seekPlayTimeLabel.setTextFormat(_textFormat);
|
||||
addChild(_seekPlayTimeLabel);
|
||||
//}
|
||||
|
||||
//{Aspect ratio label
|
||||
_aspectRatioLabelContainer = new Sprite();
|
||||
addChild(_aspectRatioLabelContainer);
|
||||
|
||||
_aspectRatioLabel = new TextField();
|
||||
_aspectRatioLabel.autoSize = TextFieldAutoSize.CENTER;
|
||||
_aspectRatioLabel.text = "original";
|
||||
_aspectRatioLabel.tabEnabled = false;
|
||||
_aspectRatioLabelContainer.addChild(_aspectRatioLabel);
|
||||
//}
|
||||
|
||||
redrawControls();
|
||||
|
||||
//{Loader bar
|
||||
_loader = new Loader();
|
||||
_loader.hide();
|
||||
|
||||
var loaderColors:Array <String> = ["", "", "", ""];
|
||||
loaderColors[0] = Std.string(_darkColor);
|
||||
loaderColors[1] = Std.string(_controlColor);
|
||||
loaderColors[2] = Std.string(_seekColor);
|
||||
|
||||
_loader.setColors(loaderColors);
|
||||
|
||||
addChild(_loader);
|
||||
//}
|
||||
|
||||
//{event Listeners
|
||||
_movieClip.addEventListener(Event.ENTER_FRAME, onEnterFrame);
|
||||
_thumb.addEventListener(MouseEvent.MOUSE_DOWN, onThumbMouseDown);
|
||||
_thumb.addEventListener(MouseEvent.MOUSE_UP, onThumbMouseUp);
|
||||
_thumb.addEventListener(MouseEvent.MOUSE_OVER, onThumbHover);
|
||||
_thumb.addEventListener(MouseEvent.MOUSE_OUT, onThumbMouseOut);
|
||||
_thumb.addEventListener(MouseEvent.MOUSE_MOVE, onTrackMouseMove);
|
||||
_thumb.addEventListener(MouseEvent.MOUSE_OUT, onTrackMouseOut);
|
||||
_track.addEventListener(MouseEvent.CLICK, onTrackClick);
|
||||
_track.addEventListener(MouseEvent.MOUSE_MOVE, onTrackMouseMove);
|
||||
_track.addEventListener(MouseEvent.MOUSE_OUT, onTrackMouseOut);
|
||||
_playControl.addEventListener(MouseEvent.CLICK, onPlayClick);
|
||||
_pauseControl.addEventListener(MouseEvent.CLICK, onPauseClick);
|
||||
_aspectRatioControl.addEventListener(MouseEvent.CLICK, onAspectRatioClick);
|
||||
_fullscreenControl.addEventListener(MouseEvent.CLICK, onFullscreenClick);
|
||||
_volumeIcon.addEventListener(MouseEvent.CLICK, onVolumeIconClick);
|
||||
_volumeTrack.addEventListener(MouseEvent.CLICK, onVolumeTrackClick);
|
||||
|
||||
_player.addEventListener(PlayerEvents.MOUSE_HIDE, onPlayerMouseHide);
|
||||
_player.addEventListener(PlayerEvents.MOUSE_SHOW, onPlayerMouseShow);
|
||||
_player.addEventListener(PlayerEvents.MEDIA_INITIALIZED, onPlayerMediaInitialized);
|
||||
_player.addEventListener(PlayerEvents.BUFFERING, onPlayerBuffering);
|
||||
_player.addEventListener(PlayerEvents.NOT_BUFFERING, onPlayerNotBuffering);
|
||||
_player.addEventListener(PlayerEvents.RESIZE, onPlayerResize);
|
||||
_player.addEventListener(PlayerEvents.PLAY_PAUSE, onPlayerPlayPause);
|
||||
_player.addEventListener(PlayerEvents.PLAYBACK_FINISHED, onPlayerPlaybackFinished);
|
||||
_player.addEventListener(PlayerEvents.CONNECTION_FAILED, onPlayerStreamNotFound);
|
||||
_player.addEventListener(PlayerEvents.ASPECT_RATIO, onPlayerAspectRatio);
|
||||
|
||||
_stage.addEventListener(MouseEvent.MOUSE_UP, onThumbMouseUp);
|
||||
_stage.addEventListener(MouseEvent.MOUSE_OUT, onThumbMouseUp);
|
||||
_stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
|
||||
_stage.addEventListener(Event.RESIZE, onStageResize);
|
||||
|
||||
_hideControlsTimer.addEventListener(TimerEvent.TIMER, hideControlsTimer);
|
||||
_hideAspectRatioLabelTimer.addEventListener(TimerEvent.TIMER, hideAspectRatioLabelTimer);
|
||||
|
||||
_hideControlsTimer.start();
|
||||
//}
|
||||
}
|
||||
//}
|
||||
|
||||
|
||||
//{Timers
|
||||
/**
|
||||
* Hides the playing controls when not moving mouse.
|
||||
* @param event The timer event associated
|
||||
*/
|
||||
private function hideControlsTimer(event:TimerEvent):Void
|
||||
{
|
||||
if (_player.isPlaying())
|
||||
{
|
||||
if (_controlsVisible)
|
||||
{
|
||||
if (_stage.mouseX < _controlsBar.x ||
|
||||
_stage.mouseX >= _stage.stageWidth - 1 ||
|
||||
_stage.mouseY >= _stage.stageHeight - 1 ||
|
||||
_stage.mouseY <= 1
|
||||
)
|
||||
{
|
||||
_controlsVisible = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hideControls();
|
||||
_hideControlsTimer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides aspect ratio label
|
||||
* @param event
|
||||
*/
|
||||
private function hideAspectRatioLabelTimer(event:TimerEvent):Void
|
||||
{
|
||||
//wait till fade in effect finish
|
||||
if (_aspectRatioLabelContainer.alpha >= 1)
|
||||
{
|
||||
Animation.fadeOut(_aspectRatioLabelContainer, 300);
|
||||
_hideAspectRatioLabelTimer.stop();
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
|
||||
//{Events
|
||||
/**
|
||||
* Keeps syncronized various elements of the controls like the thumb and download track bar
|
||||
* @param event
|
||||
*/
|
||||
private function onEnterFrame(event:Event):Void
|
||||
{
|
||||
if(_player.getDuration() > 0) {
|
||||
if (_scrubbing)
|
||||
{
|
||||
_player.seek(((_thumb.x - _track.x) / _track.width) * _player.getDuration());
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentPlayTimeLabel.text = Utils.formatTime(_player.getCurrentTime());
|
||||
_currentPlayTimeLabel.setTextFormat(_textFormat);
|
||||
_thumb.x = _player.getCurrentTime() / _player.getDuration() * (_track.width-_thumb.width) + _track.x;
|
||||
}
|
||||
}
|
||||
|
||||
_volumeSlider.height = _volumeTrack.height * (_player.getVolume() / 1.0);
|
||||
_volumeSlider.y = (_volumeTrack.y + _volumeTrack.height) - _volumeSlider.height;
|
||||
|
||||
drawDownloadProgress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show playing controls on mouse movement.
|
||||
* @param event
|
||||
*/
|
||||
private function onMouseMove(event:MouseEvent):Void
|
||||
{
|
||||
if (_stage.mouseX >= _controlsBar.x)
|
||||
{
|
||||
if (!_hideControlsTimer.running)
|
||||
{
|
||||
_hideControlsTimer.start();
|
||||
}
|
||||
|
||||
_controlsVisible = true;
|
||||
showControls();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function fired by a stage resize eventthat redraws the player controls
|
||||
* @param event
|
||||
*/
|
||||
private function onStageResize(event:Event):Void
|
||||
{
|
||||
redrawControls();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles pause or play
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayClick(event:MouseEvent):Void
|
||||
{
|
||||
_player.togglePlay();
|
||||
_playControl.visible = !_player.isPlaying();
|
||||
_pauseControl.visible = _player.isPlaying();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles pause or play
|
||||
* @param event
|
||||
*/
|
||||
private function onPauseClick(event:MouseEvent):Void
|
||||
{
|
||||
_player.togglePlay();
|
||||
_playControl.visible = !_player.isPlaying();
|
||||
_pauseControl.visible = _player.isPlaying();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles betewen aspect ratios
|
||||
* @param event
|
||||
*/
|
||||
private function onAspectRatioClick(event:MouseEvent):Void
|
||||
{
|
||||
_player.toggleAspectRatio();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles between window and fullscreen mode
|
||||
* @param event
|
||||
*/
|
||||
private function onFullscreenClick(event:MouseEvent):Void
|
||||
{
|
||||
_player.toggleFullscreen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles between mute and unmute
|
||||
* @param event
|
||||
*/
|
||||
private function onVolumeIconClick(event: MouseEvent):Void
|
||||
{
|
||||
if (_volumeSlider.visible) {
|
||||
_volumeSlider.visible = false;
|
||||
_volumeTrack.visible = false;
|
||||
} else {
|
||||
_volumeSlider.visible = true;
|
||||
_volumeTrack.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect user click on volume track control and change volume according
|
||||
* @param event
|
||||
*/
|
||||
private function onVolumeTrackClick(event:MouseEvent):Void
|
||||
{
|
||||
var percent:Float = _volumeTrack.height - _volumeTrack.mouseY;
|
||||
var volume:Float = 1.0 * (percent / _volumeTrack.height);
|
||||
|
||||
_player.setVolume(volume);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display not found message
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerStreamNotFound(event:PlayerEvents):Void
|
||||
{
|
||||
//todo: to work on this
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the loader bar when buffering
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerBuffering(event:PlayerEvents):Void
|
||||
{
|
||||
_loader.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides loader bar when not buffering
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerNotBuffering(event:PlayerEvents):Void
|
||||
{
|
||||
_loader.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the selected aspect ratio
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerAspectRatio(event:PlayerEvents):Void
|
||||
{
|
||||
_hideAspectRatioLabelTimer.stop();
|
||||
_aspectRatioLabel.text = _player.getAspectRatioString();
|
||||
drawAspectRatioLabel();
|
||||
|
||||
while (_aspectRatioLabelContainer.visible)
|
||||
{
|
||||
//wait till fade out finishes
|
||||
}
|
||||
|
||||
Animation.fadeIn(_aspectRatioLabelContainer, 1);
|
||||
|
||||
_hideAspectRatioLabelTimer.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitors playbeack when finishes tu update controls
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerPlaybackFinished(event:PlayerEvents):Void
|
||||
{
|
||||
_playControl.visible = !_player.isPlaying();
|
||||
_pauseControl.visible = _player.isPlaying();
|
||||
showControls();
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitors keyboard play pause actions to update icons
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerPlayPause(event:PlayerEvents):Void
|
||||
{
|
||||
_playControl.visible = !_player.isPlaying();
|
||||
_pauseControl.visible = _player.isPlaying();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes the video player on windowed mode substracting the seekbar height
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerResize(event:PlayerEvents):Void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates media total time duration.
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerMediaInitialized(event:PlayerEvents):Void
|
||||
{
|
||||
_totalPlayTimeLabel.text = Utils.formatTime(event.duration);
|
||||
_totalPlayTimeLabel.setTextFormat(_textFormat);
|
||||
|
||||
_playControl.visible = !_player.isPlaying();
|
||||
_pauseControl.visible = _player.isPlaying();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides seekbar if on fullscreen.
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerMouseHide(event:PlayerEvents):Void
|
||||
{
|
||||
if (_controlsBar.visible && _player.isFullscreen())
|
||||
{
|
||||
hideControls();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows seekbar
|
||||
* @param event
|
||||
*/
|
||||
private function onPlayerMouseShow(event:PlayerEvents):Void
|
||||
{
|
||||
//Only use slidein effect on fullscreen since switching to windowed mode on
|
||||
//hardware scaling causes a bug by a slow response on stage height changes
|
||||
if (_player.isFullscreen() && !_controlsBar.visible)
|
||||
{
|
||||
_controlsBar.visible = true;
|
||||
}
|
||||
else if (!_controlsBar.visible)
|
||||
{
|
||||
_controlsBar.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a user click in to time and seeks to it
|
||||
* @param event
|
||||
*/
|
||||
private function onTrackClick(event:MouseEvent):Void
|
||||
{
|
||||
var clickPosition:Float = _track.mouseX;
|
||||
_player.seek(_player.getDuration() * (clickPosition / _track.width));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a small tooltip showing the time calculated by mouse position
|
||||
* @param event
|
||||
*/
|
||||
private function onTrackMouseMove(event:MouseEvent):Void
|
||||
{
|
||||
var clickPosition:Float = _track.mouseX;
|
||||
_seekPlayTimeLabel.text = Utils.formatTime(_player.getDuration() * (clickPosition / _track.width));
|
||||
_seekPlayTimeLabel.setTextFormat(_textFormat);
|
||||
|
||||
_seekPlayTimeLabel.y = _stage.stageHeight - _seekBar.height - _seekPlayTimeLabel.height - 1;
|
||||
_seekPlayTimeLabel.x = clickPosition + (_seekPlayTimeLabel.width / 2) + (_playControl.width + 10) * 2;
|
||||
_seekPlayTimeLabel.backgroundColor = _darkColor;
|
||||
_seekPlayTimeLabel.background = true;
|
||||
_seekPlayTimeLabel.textColor = _controlColor;
|
||||
_seekPlayTimeLabel.borderColor = _darkColor;
|
||||
_seekPlayTimeLabel.border = true;
|
||||
|
||||
if (!_seekPlayTimeLabel.visible)
|
||||
{
|
||||
_seekPlayTimeLabel.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the tooltip that shows the time calculated by mouse position
|
||||
* @param event
|
||||
*/
|
||||
private function onTrackMouseOut(event:MouseEvent):Void
|
||||
{
|
||||
_seekPlayTimeLabel.visible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables dragging of thumb for seeking media
|
||||
* @param event
|
||||
*/
|
||||
private function onThumbMouseDown(event:MouseEvent):Void
|
||||
{
|
||||
_scrubbing = true;
|
||||
var rectangle:Rectangle = new Rectangle(_track.x, _track.y, _track.width-_thumb.width, 0);
|
||||
_thumb.startDrag(false, rectangle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes thumb seek control to hover color
|
||||
* @param event
|
||||
*/
|
||||
private function onThumbHover(event:MouseEvent):Void
|
||||
{
|
||||
_thumb.graphics.lineStyle();
|
||||
_thumb.graphics.beginFill(_hoverColor);
|
||||
_thumb.graphics.drawRoundRect(0, (_seekBar.height/2)-(11/2), 11, 11, 10, 10);
|
||||
_thumb.graphics.endFill();
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes thumb seek control to control color
|
||||
* @param event
|
||||
*/
|
||||
private function onThumbMouseOut(event:MouseEvent):Void
|
||||
{
|
||||
var matrix:Matrix = new Matrix( );
|
||||
matrix.createGradientBox(11, 11, Utils.degreesToRadians(-90), 11, 0);
|
||||
var colors:Array<UInt> = [_controlColor, _controlColor];
|
||||
var alphas:Array<Float> = [0.75, 1];
|
||||
var ratios:Array<UInt> = [0, 255];
|
||||
|
||||
_thumb.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix);
|
||||
_thumb.graphics.drawRoundRect(0, (_seekBar.height / 2) - (11 / 2), 11, 11, 10, 10);
|
||||
_thumb.graphics.endFill();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables dragging of thumb
|
||||
* @param event
|
||||
*/
|
||||
private function onThumbMouseUp(event:MouseEvent):Void
|
||||
{
|
||||
_scrubbing = false;
|
||||
_thumb.stopDrag( );
|
||||
}
|
||||
//}
|
||||
|
||||
|
||||
//{Drawing functions
|
||||
/**
|
||||
* Clears all current graphics a draw new ones
|
||||
*/
|
||||
private function redrawControls():Void
|
||||
{
|
||||
drawControls();
|
||||
drawAspectRatioLabel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the download progress track bar
|
||||
*/
|
||||
private function drawDownloadProgress():Void
|
||||
{
|
||||
if (_player.getBytesTotal() > 0)
|
||||
{
|
||||
var bytesLoaded:Float = _player.getBytesLoaded();
|
||||
var bytesTotal:Float = _player.getBytesTotal();
|
||||
|
||||
_percentLoaded = bytesLoaded / bytesTotal;
|
||||
}
|
||||
|
||||
var position:Float = _player.getStartTime() / _player.getDuration();
|
||||
var startPosition:Float = (position > 0?(position * _track.width):0) + _track.x;
|
||||
|
||||
_trackDownloaded.graphics.clear();
|
||||
_trackDownloaded.graphics.lineStyle();
|
||||
_trackDownloaded.x = startPosition;
|
||||
_trackDownloaded.graphics.beginFill(_seekColor, 0.5);
|
||||
_trackDownloaded.graphics.drawRoundRect(0, (_seekBar.height / 2) - (5 / 2), ((_track.width + _track.x) - _trackDownloaded.x) * _percentLoaded, 5, 3, 3);
|
||||
_trackDownloaded.graphics.endFill();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws NEW control bar player/seek controls
|
||||
*/
|
||||
private function drawControls():Void
|
||||
{
|
||||
//Reset sprites for redraw
|
||||
_controlsBar.graphics.clear();
|
||||
_volumeTrack.graphics.clear();
|
||||
_volumeSlider.graphics.clear();
|
||||
_volumeSlider.visible = false;
|
||||
_volumeTrack.visible = false;
|
||||
|
||||
//Reset sprites for redraw
|
||||
_seekBar.graphics.clear();
|
||||
_track.graphics.clear();
|
||||
_thumb.graphics.clear();
|
||||
|
||||
//Draw controls bar
|
||||
var barMargin = 10;
|
||||
var barWidth = _stage.stageWidth;
|
||||
var barHeight = _controlSize;
|
||||
var barCenter = barWidth / 2;
|
||||
var buttonSize = Std.int(((80 / 100) * (barHeight - (barMargin*2))));
|
||||
|
||||
_controlsBar.x = 0;
|
||||
_controlsBar.y = (_stage.stageHeight - barHeight);
|
||||
|
||||
var matrix:Matrix = new Matrix( );
|
||||
matrix.createGradientBox(barWidth, barHeight, Utils.degreesToRadians(-90), barWidth, 0);
|
||||
var colors:Array<UInt> = [_brightColor, _darkColor];
|
||||
var alphas:Array<Float> = [1.0, 1];
|
||||
var ratios:Array<UInt> = [0, 255];
|
||||
_controlsBar.graphics.lineStyle();
|
||||
_controlsBar.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix);
|
||||
_controlsBar.graphics.drawRect(0, 2, barWidth, barHeight-2);
|
||||
_controlsBar.graphics.endFill();
|
||||
_controlsBar.graphics.beginFill(_darkColor, 1);
|
||||
_controlsBar.graphics.drawRect(0, 0, barWidth, 1);
|
||||
_controlsBar.graphics.endFill();
|
||||
_controlsBar.graphics.beginFill(_brightColor, 1);
|
||||
_controlsBar.graphics.drawRect(0, 1, barWidth, 1);
|
||||
_controlsBar.graphics.endFill();
|
||||
|
||||
//Draw seek bar
|
||||
var _seekBarWidth = barWidth - (buttonSize+barMargin)*3 - (_playControl.x + _playControl.width + barMargin) - barMargin;
|
||||
var _seekBarHeight = barHeight;
|
||||
_seekBar.x = _playControl.x + _playControl.width + barMargin;
|
||||
_seekBar.y = 0;
|
||||
_seekBar.graphics.lineStyle();
|
||||
_seekBar.graphics.beginFill(_darkColor, 0);
|
||||
_seekBar.graphics.drawRect(0, 0, _seekBarWidth, _seekBarHeight);
|
||||
_seekBar.graphics.endFill();
|
||||
|
||||
//Draw playbutton
|
||||
_playControl.setNormalColor(_controlColor);
|
||||
_playControl.setHoverColor(_hoverColor);
|
||||
_playControl.setPosition(barMargin, barMargin);
|
||||
_playControl.setSize(buttonSize+5, buttonSize+5);
|
||||
|
||||
//Draw pausebutton
|
||||
_pauseControl.setNormalColor(_controlColor);
|
||||
_pauseControl.setHoverColor(_hoverColor);
|
||||
_pauseControl.setPosition(_playControl.x, _playControl.y);
|
||||
_pauseControl.setSize(buttonSize+5, buttonSize+5);
|
||||
|
||||
//Draw current play time label
|
||||
_textFormat.color = _seekColor;
|
||||
_currentPlayTimeLabel.x = 0;
|
||||
_currentPlayTimeLabel.y = _seekBarHeight - (_seekBarHeight / 2) - (_currentPlayTimeLabel.height / 2);
|
||||
_currentPlayTimeLabel.antiAliasType = AntiAliasType.ADVANCED;
|
||||
_currentPlayTimeLabel.setTextFormat(_textFormat);
|
||||
|
||||
//Draw total play time label
|
||||
_totalPlayTimeLabel.x = _seekBarWidth - _totalPlayTimeLabel.width;
|
||||
_totalPlayTimeLabel.y = _seekBarHeight - (_seekBarHeight / 2) - (_totalPlayTimeLabel.height / 2);
|
||||
_totalPlayTimeLabel.antiAliasType = AntiAliasType.ADVANCED;
|
||||
_totalPlayTimeLabel.setTextFormat(_textFormat);
|
||||
|
||||
//Draw download progress
|
||||
drawDownloadProgress();
|
||||
|
||||
//Draw track place holder for drag
|
||||
_track.x = _currentPlayTimeLabel.x + _currentPlayTimeLabel.width + barMargin;
|
||||
_track.graphics.lineStyle();
|
||||
_track.graphics.beginFill(_seekColor, 0);
|
||||
_track.graphics.drawRect(0, (_seekBarHeight / 2) - ((buttonSize+barMargin) / 2), _totalPlayTimeLabel.x - _totalPlayTimeLabel.width - barMargin - barMargin, buttonSize + barMargin);
|
||||
_track.graphics.endFill();
|
||||
|
||||
_track.graphics.lineStyle();
|
||||
_track.graphics.beginFill(_seekColor, 0.3);
|
||||
_track.graphics.drawRoundRect(0, (_seekBarHeight / 2) - (5 / 2), _totalPlayTimeLabel.x - _totalPlayTimeLabel.width - barMargin - barMargin, 5, 3, 3);
|
||||
_track.graphics.endFill();
|
||||
|
||||
//Draw thumb
|
||||
var matrix:Matrix = new Matrix( );
|
||||
matrix.createGradientBox(11, 11, Utils.degreesToRadians(-90), 11, 0);
|
||||
var colors:Array<UInt> = [_controlColor, _controlColor];
|
||||
var alphas:Array<Float> = [0.75, 1];
|
||||
var ratios:Array<UInt> = [0, 255];
|
||||
|
||||
_thumb.x = _currentPlayTimeLabel.width + _currentPlayTimeLabel.x + barMargin;
|
||||
_thumb.graphics.lineStyle();
|
||||
_thumb.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix);
|
||||
//_thumb.graphics.beginFill(_controlColor);
|
||||
_thumb.graphics.drawRoundRect(0, (_seekBarHeight/2)-(11/2), 11, 11, 10, 10);
|
||||
_thumb.graphics.endFill();
|
||||
|
||||
//Draw volume icon
|
||||
_volumeIcon.setNormalColor(_controlColor);
|
||||
_volumeIcon.setHoverColor(_hoverColor);
|
||||
_volumeIcon.setPosition(_seekBar.x + _seekBar.width + barMargin, _playControl.y+1);
|
||||
_volumeIcon.setSize(buttonSize, buttonSize);
|
||||
|
||||
//Draw aspec ratio button
|
||||
_aspectRatioControl.setNormalColor(_controlColor);
|
||||
_aspectRatioControl.setHoverColor(_hoverColor);
|
||||
_aspectRatioControl.setPosition(_volumeIcon.x + _volumeIcon.width + barMargin, _playControl.y+1);
|
||||
_aspectRatioControl.setSize(buttonSize, buttonSize);
|
||||
|
||||
//Draw fullscreen button
|
||||
_fullscreenControl.setNormalColor(_controlColor);
|
||||
_fullscreenControl.setHoverColor(_hoverColor);
|
||||
_fullscreenControl.setPosition(_aspectRatioControl.x + _aspectRatioControl.width + barMargin, _playControl.y+1);
|
||||
_fullscreenControl.setSize(buttonSize, buttonSize);
|
||||
|
||||
//Draw volume track
|
||||
_volumeTrack.x = _controlsBar.width-(buttonSize+barMargin)*3;
|
||||
_volumeTrack.y = -_controlsBar.height-2;
|
||||
_volumeTrack.graphics.lineStyle(1, _controlColor);
|
||||
_volumeTrack.graphics.beginFill(0x000000, 0);
|
||||
_volumeTrack.graphics.drawRect(0, 0, buttonSize, _controlsBar.height);
|
||||
_volumeTrack.graphics.endFill();
|
||||
|
||||
//Draw volume slider
|
||||
var matrix:Matrix = new Matrix( );
|
||||
matrix.createGradientBox(_volumeTrack.width, _volumeTrack.height, Utils.degreesToRadians(-90), _volumeTrack.width, 0);
|
||||
var colors:Array<UInt> = [_hoverColor, _hoverColor];
|
||||
var alphas:Array<Float> = [0.75, 1];
|
||||
var ratios:Array<UInt> = [0, 255];
|
||||
|
||||
_volumeSlider.x = _volumeTrack.x;
|
||||
_volumeSlider.y = _volumeTrack.y;
|
||||
_volumeSlider.graphics.lineStyle();
|
||||
_volumeSlider.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix);
|
||||
//_volumeSlider.graphics.beginFill(_hoverColor, 1);
|
||||
_volumeSlider.graphics.drawRect(0, 0, _volumeTrack.width, _volumeTrack.height);
|
||||
_volumeSlider.graphics.endFill();
|
||||
|
||||
}
|
||||
|
||||
private function drawAspectRatioLabel():Void
|
||||
{
|
||||
_aspectRatioLabelContainer.graphics.clear();
|
||||
_aspectRatioLabelContainer.visible = false;
|
||||
|
||||
//Update aspect ratio label
|
||||
var textFormat:TextFormat = new TextFormat();
|
||||
textFormat.font = "arial";
|
||||
textFormat.bold = true;
|
||||
textFormat.size = 40;
|
||||
textFormat.color = _controlColor;
|
||||
|
||||
_aspectRatioLabel.setTextFormat(textFormat);
|
||||
_aspectRatioLabel.x = (_stage.stageWidth / 2) - (_aspectRatioLabel.width / 2);
|
||||
_aspectRatioLabel.y = (_stage.stageHeight / 2) - (_aspectRatioLabel.height / 2);
|
||||
|
||||
//Draw aspect ratio label container
|
||||
_aspectRatioLabelContainer.x = _aspectRatioLabel.x - 10;
|
||||
_aspectRatioLabelContainer.y = _aspectRatioLabel.y - 10;
|
||||
_aspectRatioLabelContainer.graphics.lineStyle(0, _darkColor);
|
||||
_aspectRatioLabelContainer.graphics.beginFill(_darkColor, 1);
|
||||
_aspectRatioLabelContainer.graphics.drawRoundRect(0, 0, _aspectRatioLabel.width + 20, _aspectRatioLabel.height + 20, 15, 15);
|
||||
_aspectRatioLabelContainer.graphics.endFill();
|
||||
|
||||
_aspectRatioLabel.x = 10;
|
||||
_aspectRatioLabel.y = 10;
|
||||
}
|
||||
//}
|
||||
|
||||
|
||||
//{Private Methods
|
||||
/**
|
||||
* Hide the play controls bar
|
||||
*/
|
||||
private function hideControls():Void
|
||||
{
|
||||
if(_controlsBar.visible)
|
||||
{
|
||||
drawControls();
|
||||
Animation.slideOut(_controlsBar, "bottom", 800);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows play controls bar
|
||||
*/
|
||||
private function showControls():Void
|
||||
{
|
||||
if(!_controlsBar.visible)
|
||||
{
|
||||
drawControls();
|
||||
_controlsBar.visible = true;
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
|
||||
//{Setters
|
||||
/**
|
||||
* Sets the player colors and redraw them
|
||||
* @param colors Array of colors in the following order: darkColor, brightColor, controlColor, hoverColor
|
||||
*/
|
||||
public function setControlColors(colors:Array<String>):Void
|
||||
{
|
||||
_darkColor = colors[0].length > 0? Std.parseInt("0x" + colors[0]) : 0x000000;
|
||||
_brightColor = colors[1].length > 0? Std.parseInt("0x" + colors[1]) : 0x4c4c4c;
|
||||
_controlColor = colors[2].length > 0? Std.parseInt("0x" + colors[2]) : 0xFFFFFF;
|
||||
_hoverColor = colors[3].length > 0? Std.parseInt("0x" + colors[3]) : 0x67A8C1;
|
||||
_seekColor = colors[4].length > 0? Std.parseInt("0x" + colors[4]) : 0x7c7c7c;
|
||||
|
||||
|
||||
var loaderColors:Array <String> = ["", ""];
|
||||
loaderColors[0] = colors[0];
|
||||
loaderColors[1] = colors[2];
|
||||
loaderColors[2] = colors[4];
|
||||
_loader.setColors(loaderColors);
|
||||
|
||||
redrawControls();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the player controls size (height)
|
||||
* @param size int: for e.g. 50
|
||||
*/
|
||||
public function setControlSize(size:Int):Void
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
_controlSize = size;
|
||||
redrawControls();
|
||||
}
|
||||
|
||||
/**
|
||||
* To set the duration label when autostart parameter is false
|
||||
* @param duration in seconds or formatted string in format hh:mm:ss
|
||||
*/
|
||||
public function setDurationLabel(duration:String):Void
|
||||
{
|
||||
//Person passed time already formatted
|
||||
if (duration.indexOf(":") != -1)
|
||||
{
|
||||
_totalPlayTimeLabel.text = duration;
|
||||
}
|
||||
|
||||
//Time passed in seconds
|
||||
else
|
||||
{
|
||||
_totalPlayTimeLabel.text = Std.string(Utils.formatTime(Std.parseFloat(duration)));
|
||||
}
|
||||
|
||||
_totalPlayTimeLabel.setTextFormat(_textFormat);
|
||||
}
|
||||
//}
|
||||
|
||||
}
|
||||
127
lib/Jaris/src/jaris/player/newcontrols/PauseIcon.hx
Normal file
127
lib/Jaris/src/jaris/player/newcontrols/PauseIcon.hx
Normal file
@ -0,0 +1,127 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player.newcontrols;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.geom.Matrix;
|
||||
import jaris.utils.Utils;
|
||||
import flash.display.GradientType;
|
||||
|
||||
class PauseIcon extends Sprite
|
||||
{
|
||||
private var _width:Float;
|
||||
private var _height:Float;
|
||||
private var _normalColor:UInt;
|
||||
private var _hoverColor:UInt;
|
||||
|
||||
public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt)
|
||||
{
|
||||
super();
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.buttonMode = true;
|
||||
this.useHandCursor = true;
|
||||
this.tabEnabled = false;
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
_normalColor = normalColor;
|
||||
_hoverColor = hoverColor;
|
||||
|
||||
addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
|
||||
addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
private function onMouseOver(event:MouseEvent):Void
|
||||
{
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
private function onMouseOut(event:MouseEvent):Void
|
||||
{
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
//{Private Methods
|
||||
private function draw(color:UInt):Void
|
||||
{
|
||||
graphics.clear();
|
||||
|
||||
graphics.lineStyle(0, color, 0.0);
|
||||
graphics.beginFill(color, 0);
|
||||
graphics.drawRect(0, 0, _width, _height);
|
||||
graphics.endFill();
|
||||
|
||||
var matrix:Matrix = new Matrix( );
|
||||
matrix.createGradientBox(_width, _height, Utils.degreesToRadians(-90), _width, 0);
|
||||
var colors:Array<UInt> = [color, color];
|
||||
var alphas:Array<Float> = [0.75, 1];
|
||||
var ratios:Array<UInt> = [0, 255];
|
||||
|
||||
graphics.lineStyle();
|
||||
graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix);
|
||||
//graphics.beginFill(color);
|
||||
graphics.drawRoundRect(0, 0, (33 / 100) * _width, _height, 6, 6);
|
||||
graphics.drawRoundRect(_width - ((33 / 100) * _width), 0, (33 / 100) * _width, _height, 6, 6);
|
||||
graphics.endFill();
|
||||
|
||||
graphics.lineStyle();
|
||||
graphics.beginFill(color, 0);
|
||||
graphics.drawRect(0, 0, _width, _height);
|
||||
graphics.endFill();
|
||||
}
|
||||
//}
|
||||
|
||||
//{Setters
|
||||
public function setNormalColor(color:UInt):Void
|
||||
{
|
||||
_normalColor = color;
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setHoverColor(color:UInt):Void
|
||||
{
|
||||
_hoverColor = color;
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
public function setPosition(x:Float, y:Float):Void
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setSize(width:Float, height:Float):Void
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
//}
|
||||
}
|
||||
122
lib/Jaris/src/jaris/player/newcontrols/PlayIcon.hx
Normal file
122
lib/Jaris/src/jaris/player/newcontrols/PlayIcon.hx
Normal file
@ -0,0 +1,122 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player.newcontrols;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.geom.Matrix;
|
||||
import jaris.utils.Utils;
|
||||
import flash.display.GradientType;
|
||||
|
||||
class PlayIcon extends Sprite
|
||||
{
|
||||
private var _width:Float;
|
||||
private var _height:Float;
|
||||
private var _normalColor:UInt;
|
||||
private var _hoverColor:UInt;
|
||||
|
||||
public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt)
|
||||
{
|
||||
super();
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.buttonMode = true;
|
||||
this.useHandCursor = true;
|
||||
this.tabEnabled = false;
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
_normalColor = normalColor;
|
||||
_hoverColor = hoverColor;
|
||||
|
||||
addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
|
||||
addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
private function onMouseOver(event:MouseEvent):Void
|
||||
{
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
private function onMouseOut(event:MouseEvent):Void
|
||||
{
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
//{Private Methods
|
||||
private function draw(color:UInt):Void
|
||||
{
|
||||
graphics.clear();
|
||||
graphics.lineStyle(0, color, 0.0);
|
||||
graphics.beginFill(color, 0);
|
||||
graphics.drawRect(0, 0, _width, _height);
|
||||
graphics.endFill();
|
||||
|
||||
var matrix:Matrix = new Matrix( );
|
||||
matrix.createGradientBox(_width, _height, Utils.degreesToRadians(-90), _width, 0);
|
||||
var colors:Array<UInt> = [color, color];
|
||||
var alphas:Array<Float> = [0.75, 1];
|
||||
var ratios:Array<UInt> = [0, 255];
|
||||
|
||||
graphics.lineStyle();
|
||||
graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix);
|
||||
//graphics.beginFill(color);
|
||||
graphics.lineTo(0, _height);
|
||||
graphics.lineTo(_width, _height / 2);
|
||||
graphics.lineTo(0, 0);
|
||||
graphics.endFill();
|
||||
}
|
||||
//}
|
||||
|
||||
//{Setters
|
||||
public function setNormalColor(color:UInt):Void
|
||||
{
|
||||
_normalColor = color;
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setHoverColor(color:UInt):Void
|
||||
{
|
||||
_hoverColor = color;
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
public function setPosition(x:Float, y:Float):Void
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setSize(width:Float, height:Float):Void
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
//}
|
||||
}
|
||||
125
lib/Jaris/src/jaris/player/newcontrols/VolumeIcon.hx
Normal file
125
lib/Jaris/src/jaris/player/newcontrols/VolumeIcon.hx
Normal file
@ -0,0 +1,125 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.player.newcontrols;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.geom.Matrix;
|
||||
import jaris.utils.Utils;
|
||||
import flash.display.GradientType;
|
||||
|
||||
class VolumeIcon extends Sprite
|
||||
{
|
||||
private var _width:Float;
|
||||
private var _height:Float;
|
||||
private var _normalColor:UInt;
|
||||
private var _hoverColor:UInt;
|
||||
|
||||
public function new(x:Float, y:Float, width:Float, height:Float, normalColor:UInt, hoverColor:UInt)
|
||||
{
|
||||
super();
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.buttonMode = true;
|
||||
this.useHandCursor = true;
|
||||
this.tabEnabled = false;
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
_normalColor = normalColor;
|
||||
_hoverColor = hoverColor;
|
||||
|
||||
addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
|
||||
addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
private function onMouseOver(event:MouseEvent):Void
|
||||
{
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
private function onMouseOut(event:MouseEvent):Void
|
||||
{
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
//{Private Methods
|
||||
private function draw(color:UInt):Void
|
||||
{
|
||||
graphics.clear();
|
||||
|
||||
graphics.lineStyle(0, color, 0.0);
|
||||
graphics.beginFill(color, 0);
|
||||
graphics.drawRect(0, 0, _width, _height);
|
||||
graphics.endFill();
|
||||
|
||||
var matrix:Matrix = new Matrix( );
|
||||
matrix.createGradientBox(_width, _height, Utils.degreesToRadians(-90), _width, 0);
|
||||
var colors:Array<UInt> = [color, color];
|
||||
var alphas:Array<Float> = [0.75, 1];
|
||||
var ratios:Array<UInt> = [0, 255];
|
||||
|
||||
graphics.lineStyle();
|
||||
graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix);
|
||||
//graphics.beginFill(color, 1);
|
||||
graphics.drawRect(0, ((50 / 100) * _height) / 2+1, _width / 2-1, ((50 / 100) * _height));
|
||||
graphics.moveTo(_width / 2 -1, ((50 / 100) * _height)/2+1);
|
||||
graphics.lineTo(_width, 0);
|
||||
graphics.lineTo(_width, _height+2);
|
||||
graphics.lineTo(_width / 2 -1, ((50 / 100) * _height) + (((50 / 100) * _height) / 2)+1);
|
||||
graphics.endFill();
|
||||
}
|
||||
//}
|
||||
|
||||
//{Setters
|
||||
public function setNormalColor(color:UInt):Void
|
||||
{
|
||||
_normalColor = color;
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setHoverColor(color:UInt):Void
|
||||
{
|
||||
_hoverColor = color;
|
||||
draw(_hoverColor);
|
||||
}
|
||||
|
||||
public function setPosition(x:Float, y:Float):Void
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
|
||||
public function setSize(width:Float, height:Float):Void
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
draw(_normalColor);
|
||||
}
|
||||
//}
|
||||
}
|
||||
161
lib/Jaris/src/jaris/utils/Utils.hx
Normal file
161
lib/Jaris/src/jaris/utils/Utils.hx
Normal file
@ -0,0 +1,161 @@
|
||||
/**
|
||||
* @author Jefferson González
|
||||
* @copyright 2010 Jefferson González
|
||||
*
|
||||
* @license
|
||||
* This file is part of Jaris FLV Player.
|
||||
*
|
||||
* Jaris FLV Player is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License or GNU LESSER GENERAL
|
||||
* PUBLIC LICENSE as published by the Free Software Foundation, either version
|
||||
* 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Jaris FLV Player is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License and
|
||||
* GNU LESSER GENERAL PUBLIC LICENSE along with Jaris FLV Player. If not,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package jaris.utils;
|
||||
|
||||
/**
|
||||
* Some utility functions
|
||||
*/
|
||||
class Utils
|
||||
{
|
||||
|
||||
/**
|
||||
* Converts degrees to radians for easy rotation where applicable
|
||||
* @param value A radian value to convert
|
||||
* @return conversion of degree to radian
|
||||
*/
|
||||
public static function degreesToRadians(value:Float):Float
|
||||
{
|
||||
return (Math.PI / 180) * value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float value representing seconds to a readale string
|
||||
* @param time A given time in seconds
|
||||
* @return A string in the format 00:00:00
|
||||
*/
|
||||
public static function formatTime(time:Float):String
|
||||
{
|
||||
var seconds:String = "";
|
||||
var minutes:String = "";
|
||||
var hours:String = "";
|
||||
var timeString:String = "";
|
||||
|
||||
if (((time / 60) / 60) >= 1)
|
||||
{
|
||||
if (Math.floor((time / 60)) / 60 < 10)
|
||||
{
|
||||
hours = "0" + Math.floor((time / 60) / 60) + ":";
|
||||
}
|
||||
else
|
||||
{
|
||||
hours = Math.floor((time / 60) / 60) + ":";
|
||||
}
|
||||
|
||||
if (Math.floor((time / 60) % 60) < 10)
|
||||
{
|
||||
minutes = "0" + Math.floor((time / 60) % 60) + ":";
|
||||
}
|
||||
else
|
||||
{
|
||||
minutes = Math.floor((time / 60) % 60) + ":";
|
||||
}
|
||||
|
||||
if (Math.floor(time % 60) < 10)
|
||||
{
|
||||
seconds = "0" + Math.floor(time % 60);
|
||||
}
|
||||
else
|
||||
{
|
||||
seconds = Std.string(Math.floor(time % 60));
|
||||
}
|
||||
}
|
||||
else if((time / 60) >= 1)
|
||||
{
|
||||
hours = "00:";
|
||||
|
||||
if (Math.floor(time / 60) < 10)
|
||||
{
|
||||
minutes = "0" + Math.floor(time / 60) + ":";
|
||||
}
|
||||
else
|
||||
{
|
||||
minutes = Math.floor(time / 60) + ":";
|
||||
}
|
||||
|
||||
if (Math.floor(time % 60) < 10)
|
||||
{
|
||||
seconds = "0" + Math.floor(time % 60);
|
||||
}
|
||||
else
|
||||
{
|
||||
seconds = Std.string(Math.floor(time % 60));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hours = "00:";
|
||||
|
||||
minutes = "00:";
|
||||
|
||||
if (Math.floor(time) < 10)
|
||||
{
|
||||
seconds = "0" + Math.floor(time);
|
||||
}
|
||||
else
|
||||
{
|
||||
seconds = Std.string(Math.floor(time));
|
||||
}
|
||||
}
|
||||
|
||||
timeString += hours + minutes + seconds;
|
||||
|
||||
return timeString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a given rtmp source to a valid format for NetStream
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
public static function rtmpSourceParser(source:String):String
|
||||
{
|
||||
if (source.indexOf(".flv") != -1)
|
||||
{
|
||||
return source.split(".flv").join("");
|
||||
}
|
||||
else if (source.indexOf(".mp3") != -1)
|
||||
{
|
||||
return "mp3:" + source.split(".mp3").join("");
|
||||
}
|
||||
else if (source.indexOf(".mp4") != -1)
|
||||
{
|
||||
return "mp4:" + source;
|
||||
}
|
||||
else if (source.indexOf(".f4v") != -1)
|
||||
{
|
||||
return "mp4:" + source;
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes a youtube url to the format youtube.com/v/video_id
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
public static function youtubeSourceParse(source:String):String
|
||||
{
|
||||
return source.split("watch?v=").join("v/");
|
||||
}
|
||||
}
|
||||
5
lib/getid3/THIS_HAS_BEEN_MODIFIED.txt
Normal file
5
lib/getid3/THIS_HAS_BEEN_MODIFIED.txt
Normal file
@ -0,0 +1,5 @@
|
||||
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.
|
||||
211
lib/getid3/getid3/extension.cache.dbm.php
Normal file
211
lib/getid3/getid3/extension.cache.dbm.php
Normal file
@ -0,0 +1,211 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
173
lib/getid3/getid3/extension.cache.mysql.php
Normal file
173
lib/getid3/getid3/extension.cache.mysql.php
Normal file
@ -0,0 +1,173 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
1317
lib/getid3/getid3/getid3.lib.php
Normal file
1317
lib/getid3/getid3/getid3.lib.php
Normal file
File diff suppressed because it is too large
Load Diff
1747
lib/getid3/getid3/getid3.php
Normal file
1747
lib/getid3/getid3/getid3.php
Normal file
File diff suppressed because it is too large
Load Diff
280
lib/getid3/getid3/module.archive.gzip.php
Normal file
280
lib/getid3/getid3/module.archive.gzip.php
Normal file
@ -0,0 +1,280 @@
|
||||
<?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] : '');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
53
lib/getid3/getid3/module.archive.rar.php
Normal file
53
lib/getid3/getid3/module.archive.rar.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
96
lib/getid3/getid3/module.archive.szip.php
Normal file
96
lib/getid3/getid3/module.archive.szip.php
Normal file
@ -0,0 +1,96 @@
|
||||
<?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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
178
lib/getid3/getid3/module.archive.tar.php
Normal file
178
lib/getid3/getid3/module.archive.tar.php
Normal file
@ -0,0 +1,178 @@
|
||||
<?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] : '');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
424
lib/getid3/getid3/module.archive.zip.php
Normal file
424
lib/getid3/getid3/module.archive.zip.php
Normal file
@ -0,0 +1,424 @@
|
||||
<?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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
2021
lib/getid3/getid3/module.audio-video.asf.php
Normal file
2021
lib/getid3/getid3/module.audio-video.asf.php
Normal file
File diff suppressed because it is too large
Load Diff
73
lib/getid3/getid3/module.audio-video.bink.php
Normal file
73
lib/getid3/getid3/module.audio-video.bink.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
731
lib/getid3/getid3/module.audio-video.flv.php
Normal file
731
lib/getid3/getid3/module.audio-video.flv.php
Normal file
@ -0,0 +1,731 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
1706
lib/getid3/getid3/module.audio-video.matroska.php
Normal file
1706
lib/getid3/getid3/module.audio-video.matroska.php
Normal file
File diff suppressed because it is too large
Load Diff
299
lib/getid3/getid3/module.audio-video.mpeg.php
Normal file
299
lib/getid3/getid3/module.audio-video.mpeg.php
Normal file
@ -0,0 +1,299 @@
|
||||
<?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] : '');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
226
lib/getid3/getid3/module.audio-video.nsv.php
Normal file
226
lib/getid3/getid3/module.audio-video.nsv.php
Normal file
@ -0,0 +1,226 @@
|
||||
<?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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
2134
lib/getid3/getid3/module.audio-video.quicktime.php
Normal file
2134
lib/getid3/getid3/module.audio-video.quicktime.php
Normal file
File diff suppressed because it is too large
Load Diff
530
lib/getid3/getid3/module.audio-video.real.php
Normal file
530
lib/getid3/getid3/module.audio-video.real.php
Normal file
@ -0,0 +1,530 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
2409
lib/getid3/getid3/module.audio-video.riff.php
Normal file
2409
lib/getid3/getid3/module.audio-video.riff.php
Normal file
File diff suppressed because it is too large
Load Diff
142
lib/getid3/getid3/module.audio-video.swf.php
Normal file
142
lib/getid3/getid3/module.audio-video.swf.php
Normal file
@ -0,0 +1,142 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
59
lib/getid3/getid3/module.audio.aa.php
Normal file
59
lib/getid3/getid3/module.audio.aa.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
515
lib/getid3/getid3/module.audio.aac.php
Normal file
515
lib/getid3/getid3/module.audio.aac.php
Normal file
@ -0,0 +1,515 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
473
lib/getid3/getid3/module.audio.ac3.php
Normal file
473
lib/getid3/getid3/module.audio.ac3.php
Normal file
@ -0,0 +1,473 @@
|
||||
<?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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
165
lib/getid3/getid3/module.audio.au.php
Normal file
165
lib/getid3/getid3/module.audio.au.php
Normal file
@ -0,0 +1,165 @@
|
||||
<?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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
127
lib/getid3/getid3/module.audio.avr.php
Normal file
127
lib/getid3/getid3/module.audio.avr.php
Normal file
@ -0,0 +1,127 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
230
lib/getid3/getid3/module.audio.bonk.php
Normal file
230
lib/getid3/getid3/module.audio.bonk.php
Normal file
@ -0,0 +1,230 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
75
lib/getid3/getid3/module.audio.dss.php
Normal file
75
lib/getid3/getid3/module.audio.dss.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
246
lib/getid3/getid3/module.audio.dts.php
Normal file
246
lib/getid3/getid3/module.audio.dts.php
Normal file
@ -0,0 +1,246 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
480
lib/getid3/getid3/module.audio.flac.php
Normal file
480
lib/getid3/getid3/module.audio.flac.php
Normal file
@ -0,0 +1,480 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
229
lib/getid3/getid3/module.audio.la.php
Normal file
229
lib/getid3/getid3/module.audio.la.php
Normal file
@ -0,0 +1,229 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
130
lib/getid3/getid3/module.audio.lpac.php
Normal file
130
lib/getid3/getid3/module.audio.lpac.php
Normal file
@ -0,0 +1,130 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
526
lib/getid3/getid3/module.audio.midi.php
Normal file
526
lib/getid3/getid3/module.audio.midi.php
Normal file
@ -0,0 +1,526 @@
|
||||
<?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');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
101
lib/getid3/getid3/module.audio.mod.php
Normal file
101
lib/getid3/getid3/module.audio.mod.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
205
lib/getid3/getid3/module.audio.monkey.php
Normal file
205
lib/getid3/getid3/module.audio.monkey.php
Normal file
@ -0,0 +1,205 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
2011
lib/getid3/getid3/module.audio.mp3.php
Normal file
2011
lib/getid3/getid3/module.audio.mp3.php
Normal file
File diff suppressed because it is too large
Load Diff
509
lib/getid3/getid3/module.audio.mpc.php
Normal file
509
lib/getid3/getid3/module.audio.mpc.php
Normal file
@ -0,0 +1,509 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
705
lib/getid3/getid3/module.audio.ogg.php
Normal file
705
lib/getid3/getid3/module.audio.ogg.php
Normal file
@ -0,0 +1,705 @@
|
||||
<?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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
429
lib/getid3/getid3/module.audio.optimfrog.php
Normal file
429
lib/getid3/getid3/module.audio.optimfrog.php
Normal file
@ -0,0 +1,429 @@
|
||||
<?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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
94
lib/getid3/getid3/module.audio.rkau.php
Normal file
94
lib/getid3/getid3/module.audio.rkau.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
183
lib/getid3/getid3/module.audio.shorten.php
Normal file
183
lib/getid3/getid3/module.audio.shorten.php
Normal file
@ -0,0 +1,183 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
109
lib/getid3/getid3/module.audio.tta.php
Normal file
109
lib/getid3/getid3/module.audio.tta.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
207
lib/getid3/getid3/module.audio.voc.php
Normal file
207
lib/getid3/getid3/module.audio.voc.php
Normal file
@ -0,0 +1,207 @@
|
||||
<?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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
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