Handle Video: Flash/HTML5 video player
Requires getID3() and Jaris FLV Player
This commit is contained in:
parent
6cbf1b7865
commit
c9bacdf56d
118 changed files with 44098 additions and 0 deletions
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 |
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/");
|
||||
}
|
||||
}
|
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
1744
lib/getid3/getid3/getid3.php
Normal file
1744
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
162
lib/getid3/getid3/module.audio.vqf.php
Normal file
162
lib/getid3/getid3/module.audio.vqf.php
Normal file
|
@ -0,0 +1,162 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.vqf.php //
|
||||
// module for analyzing VQF audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_vqf extends getid3_handler
|
||||
{
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// based loosely on code from TTwinVQ by Jurgen Faul <jfaulØgmx*de>
|
||||
// http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html
|
||||
|
||||
$info['fileformat'] = 'vqf';
|
||||
$info['audio']['dataformat'] = 'vqf';
|
||||
$info['audio']['bitrate_mode'] = 'cbr';
|
||||
$info['audio']['lossless'] = false;
|
||||
|
||||
// shortcut
|
||||
$info['vqf']['raw'] = array();
|
||||
$thisfile_vqf = &$info['vqf'];
|
||||
$thisfile_vqf_raw = &$thisfile_vqf['raw'];
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$VQFheaderData = fread($this->getid3->fp, 16);
|
||||
|
||||
$offset = 0;
|
||||
$thisfile_vqf_raw['header_tag'] = substr($VQFheaderData, $offset, 4);
|
||||
$magic = 'TWIN';
|
||||
if ($thisfile_vqf_raw['header_tag'] != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_vqf_raw['header_tag']).'"';
|
||||
unset($info['vqf']);
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
$offset += 4;
|
||||
$thisfile_vqf_raw['version'] = substr($VQFheaderData, $offset, 8);
|
||||
$offset += 8;
|
||||
$thisfile_vqf_raw['size'] = getid3_lib::BigEndian2Int(substr($VQFheaderData, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
while (ftell($this->getid3->fp) < $info['avdataend']) {
|
||||
|
||||
$ChunkBaseOffset = ftell($this->getid3->fp);
|
||||
$chunkoffset = 0;
|
||||
$ChunkData = fread($this->getid3->fp, 8);
|
||||
$ChunkName = substr($ChunkData, $chunkoffset, 4);
|
||||
if ($ChunkName == 'DATA') {
|
||||
$info['avdataoffset'] = $ChunkBaseOffset;
|
||||
break;
|
||||
}
|
||||
$chunkoffset += 4;
|
||||
$ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
|
||||
$chunkoffset += 4;
|
||||
if ($ChunkSize > ($info['avdataend'] - ftell($this->getid3->fp))) {
|
||||
$info['error'][] = 'Invalid chunk size ('.$ChunkSize.') for chunk "'.$ChunkName.'" at offset '.$ChunkBaseOffset;
|
||||
break;
|
||||
}
|
||||
if ($ChunkSize > 0) {
|
||||
$ChunkData .= fread($this->getid3->fp, $ChunkSize);
|
||||
}
|
||||
|
||||
switch ($ChunkName) {
|
||||
case 'COMM':
|
||||
// shortcut
|
||||
$thisfile_vqf['COMM'] = array();
|
||||
$thisfile_vqf_COMM = &$thisfile_vqf['COMM'];
|
||||
|
||||
$thisfile_vqf_COMM['channel_mode'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
|
||||
$chunkoffset += 4;
|
||||
$thisfile_vqf_COMM['bitrate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
|
||||
$chunkoffset += 4;
|
||||
$thisfile_vqf_COMM['sample_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
|
||||
$chunkoffset += 4;
|
||||
$thisfile_vqf_COMM['security_level'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
|
||||
$chunkoffset += 4;
|
||||
|
||||
$info['audio']['channels'] = $thisfile_vqf_COMM['channel_mode'] + 1;
|
||||
$info['audio']['sample_rate'] = $this->VQFchannelFrequencyLookup($thisfile_vqf_COMM['sample_rate']);
|
||||
$info['audio']['bitrate'] = $thisfile_vqf_COMM['bitrate'] * 1000;
|
||||
$info['audio']['encoder_options'] = 'CBR' . ceil($info['audio']['bitrate']/1000);
|
||||
|
||||
if ($info['audio']['bitrate'] == 0) {
|
||||
$info['error'][] = 'Corrupt VQF file: bitrate_audio == zero';
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NAME':
|
||||
case 'AUTH':
|
||||
case '(c) ':
|
||||
case 'FILE':
|
||||
case 'COMT':
|
||||
case 'ALBM':
|
||||
$thisfile_vqf['comments'][$this->VQFcommentNiceNameLookup($ChunkName)][] = trim(substr($ChunkData, 8));
|
||||
break;
|
||||
|
||||
case 'DSIZ':
|
||||
$thisfile_vqf['DSIZ'] = getid3_lib::BigEndian2Int(substr($ChunkData, 8, 4));
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unhandled chunk type "'.$ChunkName.'" at offset '.$ChunkBaseOffset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate'];
|
||||
|
||||
if (isset($thisfile_vqf['DSIZ']) && (($thisfile_vqf['DSIZ'] != ($info['avdataend'] - $info['avdataoffset'] - strlen('DATA'))))) {
|
||||
switch ($thisfile_vqf['DSIZ']) {
|
||||
case 0:
|
||||
case 1:
|
||||
$info['warning'][] = 'Invalid DSIZ value "'.$thisfile_vqf['DSIZ'].'". This is known to happen with VQF files encoded by Ahead Nero, and seems to be its way of saying this is TwinVQF v'.($thisfile_vqf['DSIZ'] + 1).'.0';
|
||||
$info['audio']['encoder'] = 'Ahead Nero';
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Probable corrupted file - should be '.$thisfile_vqf['DSIZ'].' bytes, actually '.($info['avdataend'] - $info['avdataoffset'] - strlen('DATA'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function VQFchannelFrequencyLookup($frequencyid) {
|
||||
static $VQFchannelFrequencyLookup = array(
|
||||
11 => 11025,
|
||||
22 => 22050,
|
||||
44 => 44100
|
||||
);
|
||||
return (isset($VQFchannelFrequencyLookup[$frequencyid]) ? $VQFchannelFrequencyLookup[$frequencyid] : $frequencyid * 1000);
|
||||
}
|
||||
|
||||
function VQFcommentNiceNameLookup($shortname) {
|
||||
static $VQFcommentNiceNameLookup = array(
|
||||
'NAME' => 'title',
|
||||
'AUTH' => 'artist',
|
||||
'(c) ' => 'copyright',
|
||||
'FILE' => 'filename',
|
||||
'COMT' => 'comment',
|
||||
'ALBM' => 'album'
|
||||
);
|
||||
return (isset($VQFcommentNiceNameLookup[$shortname]) ? $VQFcommentNiceNameLookup[$shortname] : $shortname);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
400
lib/getid3/getid3/module.audio.wavpack.php
Normal file
400
lib/getid3/getid3/module.audio.wavpack.php
Normal file
|
@ -0,0 +1,400 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.wavpack.php //
|
||||
// module for analyzing WavPack v4.0+ Audio files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_wavpack extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
|
||||
while (true) {
|
||||
|
||||
$wavpackheader = fread($this->getid3->fp, 32);
|
||||
|
||||
if (ftell($this->getid3->fp) >= $info['avdataend']) {
|
||||
break;
|
||||
} elseif (feof($this->getid3->fp)) {
|
||||
break;
|
||||
} elseif (
|
||||
isset($info['wavpack']['blockheader']['total_samples']) &&
|
||||
isset($info['wavpack']['blockheader']['block_samples']) &&
|
||||
($info['wavpack']['blockheader']['total_samples'] > 0) &&
|
||||
($info['wavpack']['blockheader']['block_samples'] > 0) &&
|
||||
(!isset($info['wavpack']['riff_trailer_size']) || ($info['wavpack']['riff_trailer_size'] <= 0)) &&
|
||||
((isset($info['wavpack']['config_flags']['md5_checksum']) && ($info['wavpack']['config_flags']['md5_checksum'] === false)) || !empty($info['md5_data_source']))) {
|
||||
break;
|
||||
}
|
||||
|
||||
$blockheader_offset = ftell($this->getid3->fp) - 32;
|
||||
$blockheader_magic = substr($wavpackheader, 0, 4);
|
||||
$blockheader_size = getid3_lib::LittleEndian2Int(substr($wavpackheader, 4, 4));
|
||||
|
||||
$magic = 'wvpk';
|
||||
if ($blockheader_magic != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$blockheader_offset.', found "'.getid3_lib::PrintHexBytes($blockheader_magic).'"';
|
||||
switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') {
|
||||
case 'wavpack':
|
||||
case 'wvc':
|
||||
break;
|
||||
default:
|
||||
unset($info['fileformat']);
|
||||
unset($info['audio']);
|
||||
unset($info['wavpack']);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($info['wavpack']['blockheader']['block_samples']) ||
|
||||
empty($info['wavpack']['blockheader']['total_samples']) ||
|
||||
($info['wavpack']['blockheader']['block_samples'] <= 0) ||
|
||||
($info['wavpack']['blockheader']['total_samples'] <= 0)) {
|
||||
// Also, it is possible that the first block might not have
|
||||
// any samples (block_samples == 0) and in this case you should skip blocks
|
||||
// until you find one with samples because the other information (like
|
||||
// total_samples) are not guaranteed to be correct until (block_samples > 0)
|
||||
|
||||
// Finally, I have defined a format for files in which the length is not known
|
||||
// (for example when raw files are created using pipes). In these cases
|
||||
// total_samples will be -1 and you must seek to the final block to determine
|
||||
// the total number of samples.
|
||||
|
||||
|
||||
$info['audio']['dataformat'] = 'wavpack';
|
||||
$info['fileformat'] = 'wavpack';
|
||||
$info['audio']['lossless'] = true;
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
|
||||
$info['wavpack']['blockheader']['offset'] = $blockheader_offset;
|
||||
$info['wavpack']['blockheader']['magic'] = $blockheader_magic;
|
||||
$info['wavpack']['blockheader']['size'] = $blockheader_size;
|
||||
|
||||
if ($info['wavpack']['blockheader']['size'] >= 0x100000) {
|
||||
$info['error'][] = 'Expecting WavPack block size less than "0x100000", found "'.$info['wavpack']['blockheader']['size'].'" at offset '.$info['wavpack']['blockheader']['offset'];
|
||||
switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') {
|
||||
case 'wavpack':
|
||||
case 'wvc':
|
||||
break;
|
||||
default:
|
||||
unset($info['fileformat']);
|
||||
unset($info['audio']);
|
||||
unset($info['wavpack']);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['wavpack']['blockheader']['minor_version'] = ord($wavpackheader{8});
|
||||
$info['wavpack']['blockheader']['major_version'] = ord($wavpackheader{9});
|
||||
|
||||
if (($info['wavpack']['blockheader']['major_version'] != 4) ||
|
||||
(($info['wavpack']['blockheader']['minor_version'] < 4) &&
|
||||
($info['wavpack']['blockheader']['minor_version'] > 16))) {
|
||||
$info['error'][] = 'Expecting WavPack version between "4.2" and "4.16", found version "'.$info['wavpack']['blockheader']['major_version'].'.'.$info['wavpack']['blockheader']['minor_version'].'" at offset '.$info['wavpack']['blockheader']['offset'];
|
||||
switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') {
|
||||
case 'wavpack':
|
||||
case 'wvc':
|
||||
break;
|
||||
default:
|
||||
unset($info['fileformat']);
|
||||
unset($info['audio']);
|
||||
unset($info['wavpack']);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['wavpack']['blockheader']['track_number'] = ord($wavpackheader{10}); // unused
|
||||
$info['wavpack']['blockheader']['index_number'] = ord($wavpackheader{11}); // unused
|
||||
$info['wavpack']['blockheader']['total_samples'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 12, 4));
|
||||
$info['wavpack']['blockheader']['block_index'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 16, 4));
|
||||
$info['wavpack']['blockheader']['block_samples'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 20, 4));
|
||||
$info['wavpack']['blockheader']['flags_raw'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 24, 4));
|
||||
$info['wavpack']['blockheader']['crc'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 28, 4));
|
||||
|
||||
$info['wavpack']['blockheader']['flags']['bytes_per_sample'] = 1 + ($info['wavpack']['blockheader']['flags_raw'] & 0x00000003);
|
||||
$info['wavpack']['blockheader']['flags']['mono'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000004);
|
||||
$info['wavpack']['blockheader']['flags']['hybrid'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000008);
|
||||
$info['wavpack']['blockheader']['flags']['joint_stereo'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000010);
|
||||
$info['wavpack']['blockheader']['flags']['cross_decorrelation'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000020);
|
||||
$info['wavpack']['blockheader']['flags']['hybrid_noiseshape'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000040);
|
||||
$info['wavpack']['blockheader']['flags']['ieee_32bit_float'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000080);
|
||||
$info['wavpack']['blockheader']['flags']['int_32bit'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000100);
|
||||
$info['wavpack']['blockheader']['flags']['hybrid_bitrate_noise'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000200);
|
||||
$info['wavpack']['blockheader']['flags']['hybrid_balance_noise'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000400);
|
||||
$info['wavpack']['blockheader']['flags']['multichannel_initial'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000800);
|
||||
$info['wavpack']['blockheader']['flags']['multichannel_final'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00001000);
|
||||
|
||||
$info['audio']['lossless'] = !$info['wavpack']['blockheader']['flags']['hybrid'];
|
||||
}
|
||||
|
||||
while (!feof($this->getid3->fp) && (ftell($this->getid3->fp) < ($blockheader_offset + $blockheader_size + 8))) {
|
||||
|
||||
$metablock = array('offset'=>ftell($this->getid3->fp));
|
||||
$metablockheader = fread($this->getid3->fp, 2);
|
||||
if (feof($this->getid3->fp)) {
|
||||
break;
|
||||
}
|
||||
$metablock['id'] = ord($metablockheader{0});
|
||||
$metablock['function_id'] = ($metablock['id'] & 0x3F);
|
||||
$metablock['function_name'] = $this->WavPackMetablockNameLookup($metablock['function_id']);
|
||||
|
||||
// The 0x20 bit in the id of the meta subblocks (which is defined as
|
||||
// ID_OPTIONAL_DATA) is a permanent part of the id. The idea is that
|
||||
// if a decoder encounters an id that it does not know about, it uses
|
||||
// that "ID_OPTIONAL_DATA" flag to determine what to do. If it is set
|
||||
// then the decoder simply ignores the metadata, but if it is zero
|
||||
// then the decoder should quit because it means that an understanding
|
||||
// of the metadata is required to correctly decode the audio.
|
||||
$metablock['non_decoder'] = (bool) ($metablock['id'] & 0x20);
|
||||
|
||||
$metablock['padded_data'] = (bool) ($metablock['id'] & 0x40);
|
||||
$metablock['large_block'] = (bool) ($metablock['id'] & 0x80);
|
||||
if ($metablock['large_block']) {
|
||||
$metablockheader .= fread($this->getid3->fp, 2);
|
||||
}
|
||||
$metablock['size'] = getid3_lib::LittleEndian2Int(substr($metablockheader, 1)) * 2; // size is stored in words
|
||||
$metablock['data'] = null;
|
||||
|
||||
if ($metablock['size'] > 0) {
|
||||
|
||||
switch ($metablock['function_id']) {
|
||||
case 0x21: // ID_RIFF_HEADER
|
||||
case 0x22: // ID_RIFF_TRAILER
|
||||
case 0x23: // ID_REPLAY_GAIN
|
||||
case 0x24: // ID_CUESHEET
|
||||
case 0x25: // ID_CONFIG_BLOCK
|
||||
case 0x26: // ID_MD5_CHECKSUM
|
||||
$metablock['data'] = fread($this->getid3->fp, $metablock['size']);
|
||||
|
||||
if ($metablock['padded_data']) {
|
||||
// padded to the nearest even byte
|
||||
$metablock['size']--;
|
||||
$metablock['data'] = substr($metablock['data'], 0, -1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x00: // ID_DUMMY
|
||||
case 0x01: // ID_ENCODER_INFO
|
||||
case 0x02: // ID_DECORR_TERMS
|
||||
case 0x03: // ID_DECORR_WEIGHTS
|
||||
case 0x04: // ID_DECORR_SAMPLES
|
||||
case 0x05: // ID_ENTROPY_VARS
|
||||
case 0x06: // ID_HYBRID_PROFILE
|
||||
case 0x07: // ID_SHAPING_WEIGHTS
|
||||
case 0x08: // ID_FLOAT_INFO
|
||||
case 0x09: // ID_INT32_INFO
|
||||
case 0x0A: // ID_WV_BITSTREAM
|
||||
case 0x0B: // ID_WVC_BITSTREAM
|
||||
case 0x0C: // ID_WVX_BITSTREAM
|
||||
case 0x0D: // ID_CHANNEL_INFO
|
||||
fseek($this->getid3->fp, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET);
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unexpected metablock type "0x'.str_pad(dechex($metablock['function_id']), 2, '0', STR_PAD_LEFT).'" at offset '.$metablock['offset'];
|
||||
fseek($this->getid3->fp, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET);
|
||||
break;
|
||||
}
|
||||
|
||||
switch ($metablock['function_id']) {
|
||||
case 0x21: // ID_RIFF_HEADER
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
|
||||
$original_wav_filesize = getid3_lib::LittleEndian2Int(substr($metablock['data'], 4, 4));
|
||||
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_riff = new getid3_riff($getid3_temp);
|
||||
$getid3_riff->ParseRIFFdata($metablock['data']);
|
||||
$metablock['riff'] = $getid3_temp->info['riff'];
|
||||
$info['audio']['sample_rate'] = $getid3_temp->info['riff']['raw']['fmt ']['nSamplesPerSec'];
|
||||
unset($getid3_riff, $getid3_temp);
|
||||
|
||||
$metablock['riff']['original_filesize'] = $original_wav_filesize;
|
||||
$info['wavpack']['riff_trailer_size'] = $original_wav_filesize - $metablock['riff']['WAVE']['data'][0]['size'] - $metablock['riff']['header_size'];
|
||||
$info['playtime_seconds'] = $info['wavpack']['blockheader']['total_samples'] / $info['audio']['sample_rate'];
|
||||
|
||||
// Safe RIFF header in case there's a RIFF footer later
|
||||
$metablockRIFFheader = $metablock['data'];
|
||||
break;
|
||||
|
||||
|
||||
case 0x22: // ID_RIFF_TRAILER
|
||||
$metablockRIFFfooter = $metablockRIFFheader.$metablock['data'];
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
|
||||
|
||||
$startoffset = $metablock['offset'] + ($metablock['large_block'] ? 4 : 2);
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
$getid3_temp->info['avdataend'] = $info['avdataend'];
|
||||
$getid3_temp->info['fileformat'] = 'riff';
|
||||
$getid3_riff = new getid3_riff($getid3_temp);
|
||||
$metablock['riff'] = $getid3_riff->ParseRIFF($startoffset, $startoffset + $metablock['size']);
|
||||
|
||||
if (!empty($metablock['riff']['INFO'])) {
|
||||
$getid3_riff->RIFFcommentsParse($metablock['riff']['INFO'], $metablock['comments']);
|
||||
$info['tags']['riff'] = $metablock['comments'];
|
||||
}
|
||||
unset($getid3_temp, $getid3_riff);
|
||||
break;
|
||||
|
||||
|
||||
case 0x23: // ID_REPLAY_GAIN
|
||||
$info['warning'][] = 'WavPack "Replay Gain" contents not yet handled by getID3() in metablock at offset '.$metablock['offset'];
|
||||
break;
|
||||
|
||||
|
||||
case 0x24: // ID_CUESHEET
|
||||
$info['warning'][] = 'WavPack "Cuesheet" contents not yet handled by getID3() in metablock at offset '.$metablock['offset'];
|
||||
break;
|
||||
|
||||
|
||||
case 0x25: // ID_CONFIG_BLOCK
|
||||
$metablock['flags_raw'] = getid3_lib::LittleEndian2Int(substr($metablock['data'], 0, 3));
|
||||
|
||||
$metablock['flags']['adobe_mode'] = (bool) ($metablock['flags_raw'] & 0x000001); // "adobe" mode for 32-bit floats
|
||||
$metablock['flags']['fast_flag'] = (bool) ($metablock['flags_raw'] & 0x000002); // fast mode
|
||||
$metablock['flags']['very_fast_flag'] = (bool) ($metablock['flags_raw'] & 0x000004); // double fast
|
||||
$metablock['flags']['high_flag'] = (bool) ($metablock['flags_raw'] & 0x000008); // high quality mode
|
||||
$metablock['flags']['very_high_flag'] = (bool) ($metablock['flags_raw'] & 0x000010); // double high (not used yet)
|
||||
$metablock['flags']['bitrate_kbps'] = (bool) ($metablock['flags_raw'] & 0x000020); // bitrate is kbps, not bits / sample
|
||||
$metablock['flags']['auto_shaping'] = (bool) ($metablock['flags_raw'] & 0x000040); // automatic noise shaping
|
||||
$metablock['flags']['shape_override'] = (bool) ($metablock['flags_raw'] & 0x000080); // shaping mode specified
|
||||
$metablock['flags']['joint_override'] = (bool) ($metablock['flags_raw'] & 0x000100); // joint-stereo mode specified
|
||||
$metablock['flags']['copy_time'] = (bool) ($metablock['flags_raw'] & 0x000200); // copy file-time from source
|
||||
$metablock['flags']['create_exe'] = (bool) ($metablock['flags_raw'] & 0x000400); // create executable
|
||||
$metablock['flags']['create_wvc'] = (bool) ($metablock['flags_raw'] & 0x000800); // create correction file
|
||||
$metablock['flags']['optimize_wvc'] = (bool) ($metablock['flags_raw'] & 0x001000); // maximize bybrid compression
|
||||
$metablock['flags']['quality_mode'] = (bool) ($metablock['flags_raw'] & 0x002000); // psychoacoustic quality mode
|
||||
$metablock['flags']['raw_flag'] = (bool) ($metablock['flags_raw'] & 0x004000); // raw mode (not implemented yet)
|
||||
$metablock['flags']['calc_noise'] = (bool) ($metablock['flags_raw'] & 0x008000); // calc noise in hybrid mode
|
||||
$metablock['flags']['lossy_mode'] = (bool) ($metablock['flags_raw'] & 0x010000); // obsolete (for information)
|
||||
$metablock['flags']['extra_mode'] = (bool) ($metablock['flags_raw'] & 0x020000); // extra processing mode
|
||||
$metablock['flags']['skip_wvx'] = (bool) ($metablock['flags_raw'] & 0x040000); // no wvx stream w/ floats & big ints
|
||||
$metablock['flags']['md5_checksum'] = (bool) ($metablock['flags_raw'] & 0x080000); // compute & store MD5 signature
|
||||
$metablock['flags']['quiet_mode'] = (bool) ($metablock['flags_raw'] & 0x100000); // don't report progress %
|
||||
|
||||
$info['wavpack']['config_flags'] = $metablock['flags'];
|
||||
|
||||
|
||||
$info['audio']['encoder_options'] = '';
|
||||
if ($info['wavpack']['blockheader']['flags']['hybrid']) {
|
||||
$info['audio']['encoder_options'] .= ' -b???';
|
||||
}
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['adobe_mode'] ? ' -a' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['optimize_wvc'] ? ' -cc' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['create_exe'] ? ' -e' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['fast_flag'] ? ' -f' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['joint_override'] ? ' -j?' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['high_flag'] ? ' -h' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['md5_checksum'] ? ' -m' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['calc_noise'] ? ' -n' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['shape_override'] ? ' -s?' : '');
|
||||
$info['audio']['encoder_options'] .= ($metablock['flags']['extra_mode'] ? ' -x?' : '');
|
||||
if (!empty($info['audio']['encoder_options'])) {
|
||||
$info['audio']['encoder_options'] = trim($info['audio']['encoder_options']);
|
||||
} elseif (isset($info['audio']['encoder_options'])) {
|
||||
unset($info['audio']['encoder_options']);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0x26: // ID_MD5_CHECKSUM
|
||||
if (strlen($metablock['data']) == 16) {
|
||||
$info['md5_data_source'] = strtolower(getid3_lib::PrintHexBytes($metablock['data'], true, false, false));
|
||||
} else {
|
||||
$info['warning'][] = 'Expecting 16 bytes of WavPack "MD5 Checksum" in metablock at offset '.$metablock['offset'].', but found '.strlen($metablock['data']).' bytes';
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0x00: // ID_DUMMY
|
||||
case 0x01: // ID_ENCODER_INFO
|
||||
case 0x02: // ID_DECORR_TERMS
|
||||
case 0x03: // ID_DECORR_WEIGHTS
|
||||
case 0x04: // ID_DECORR_SAMPLES
|
||||
case 0x05: // ID_ENTROPY_VARS
|
||||
case 0x06: // ID_HYBRID_PROFILE
|
||||
case 0x07: // ID_SHAPING_WEIGHTS
|
||||
case 0x08: // ID_FLOAT_INFO
|
||||
case 0x09: // ID_INT32_INFO
|
||||
case 0x0A: // ID_WV_BITSTREAM
|
||||
case 0x0B: // ID_WVC_BITSTREAM
|
||||
case 0x0C: // ID_WVX_BITSTREAM
|
||||
case 0x0D: // ID_CHANNEL_INFO
|
||||
unset($metablock);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (!empty($metablock)) {
|
||||
$info['wavpack']['metablocks'][] = $metablock;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$info['audio']['encoder'] = 'WavPack v'.$info['wavpack']['blockheader']['major_version'].'.'.str_pad($info['wavpack']['blockheader']['minor_version'], 2, '0', STR_PAD_LEFT);
|
||||
$info['audio']['bits_per_sample'] = $info['wavpack']['blockheader']['flags']['bytes_per_sample'] * 8;
|
||||
$info['audio']['channels'] = ($info['wavpack']['blockheader']['flags']['mono'] ? 1 : 2);
|
||||
|
||||
if (!empty($info['playtime_seconds'])) {
|
||||
|
||||
$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
|
||||
} else {
|
||||
|
||||
$info['audio']['dataformat'] = 'wvc';
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function WavPackMetablockNameLookup(&$id) {
|
||||
static $WavPackMetablockNameLookup = array(
|
||||
0x00 => 'Dummy',
|
||||
0x01 => 'Encoder Info',
|
||||
0x02 => 'Decorrelation Terms',
|
||||
0x03 => 'Decorrelation Weights',
|
||||
0x04 => 'Decorrelation Samples',
|
||||
0x05 => 'Entropy Variables',
|
||||
0x06 => 'Hybrid Profile',
|
||||
0x07 => 'Shaping Weights',
|
||||
0x08 => 'Float Info',
|
||||
0x09 => 'Int32 Info',
|
||||
0x0A => 'WV Bitstream',
|
||||
0x0B => 'WVC Bitstream',
|
||||
0x0C => 'WVX Bitstream',
|
||||
0x0D => 'Channel Info',
|
||||
0x21 => 'RIFF header',
|
||||
0x22 => 'RIFF trailer',
|
||||
0x23 => 'Replay Gain',
|
||||
0x24 => 'Cuesheet',
|
||||
0x25 => 'Config Block',
|
||||
0x26 => 'MD5 Checksum',
|
||||
);
|
||||
return (isset($WavPackMetablockNameLookup[$id]) ? $WavPackMetablockNameLookup[$id] : '');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
690
lib/getid3/getid3/module.graphic.bmp.php
Normal file
690
lib/getid3/getid3/module.graphic.bmp.php
Normal file
|
@ -0,0 +1,690 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.graphic.bmp.php //
|
||||
// module for analyzing BMP Image files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_bmp extends getid3_handler
|
||||
{
|
||||
var $ExtractPalette = false;
|
||||
var $ExtractData = false;
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// shortcuts
|
||||
$info['bmp']['header']['raw'] = array();
|
||||
$thisfile_bmp = &$info['bmp'];
|
||||
$thisfile_bmp_header = &$thisfile_bmp['header'];
|
||||
$thisfile_bmp_header_raw = &$thisfile_bmp_header['raw'];
|
||||
|
||||
// BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp
|
||||
// all versions
|
||||
// WORD bfType;
|
||||
// DWORD bfSize;
|
||||
// WORD bfReserved1;
|
||||
// WORD bfReserved2;
|
||||
// DWORD bfOffBits;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$offset = 0;
|
||||
$BMPheader = fread($this->getid3->fp, 14 + 40);
|
||||
|
||||
$thisfile_bmp_header_raw['identifier'] = substr($BMPheader, $offset, 2);
|
||||
$offset += 2;
|
||||
|
||||
$magic = 'BM';
|
||||
if ($thisfile_bmp_header_raw['identifier'] != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_bmp_header_raw['identifier']).'"';
|
||||
unset($info['fileformat']);
|
||||
unset($info['bmp']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$thisfile_bmp_header_raw['filesize'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['reserved1'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['reserved2'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['data_offset'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['header_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
|
||||
// check if the hardcoded-to-1 "planes" is at offset 22 or 26
|
||||
$planes22 = getid3_lib::LittleEndian2Int(substr($BMPheader, 22, 2));
|
||||
$planes26 = getid3_lib::LittleEndian2Int(substr($BMPheader, 26, 2));
|
||||
if (($planes22 == 1) && ($planes26 != 1)) {
|
||||
$thisfile_bmp['type_os'] = 'OS/2';
|
||||
$thisfile_bmp['type_version'] = 1;
|
||||
} elseif (($planes26 == 1) && ($planes22 != 1)) {
|
||||
$thisfile_bmp['type_os'] = 'Windows';
|
||||
$thisfile_bmp['type_version'] = 1;
|
||||
} elseif ($thisfile_bmp_header_raw['header_size'] == 12) {
|
||||
$thisfile_bmp['type_os'] = 'OS/2';
|
||||
$thisfile_bmp['type_version'] = 1;
|
||||
} elseif ($thisfile_bmp_header_raw['header_size'] == 40) {
|
||||
$thisfile_bmp['type_os'] = 'Windows';
|
||||
$thisfile_bmp['type_version'] = 1;
|
||||
} elseif ($thisfile_bmp_header_raw['header_size'] == 84) {
|
||||
$thisfile_bmp['type_os'] = 'Windows';
|
||||
$thisfile_bmp['type_version'] = 4;
|
||||
} elseif ($thisfile_bmp_header_raw['header_size'] == 100) {
|
||||
$thisfile_bmp['type_os'] = 'Windows';
|
||||
$thisfile_bmp['type_version'] = 5;
|
||||
} else {
|
||||
$info['error'][] = 'Unknown BMP subtype (or not a BMP file)';
|
||||
unset($info['fileformat']);
|
||||
unset($info['bmp']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['fileformat'] = 'bmp';
|
||||
$info['video']['dataformat'] = 'bmp';
|
||||
$info['video']['lossless'] = true;
|
||||
$info['video']['pixel_aspect_ratio'] = (float) 1;
|
||||
|
||||
if ($thisfile_bmp['type_os'] == 'OS/2') {
|
||||
|
||||
// OS/2-format BMP
|
||||
// http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm
|
||||
|
||||
// DWORD Size; /* Size of this structure in bytes */
|
||||
// DWORD Width; /* Bitmap width in pixels */
|
||||
// DWORD Height; /* Bitmap height in pixel */
|
||||
// WORD NumPlanes; /* Number of bit planes (color depth) */
|
||||
// WORD BitsPerPixel; /* Number of bits per pixel per plane */
|
||||
|
||||
$thisfile_bmp_header_raw['width'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['height'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['planes'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['bits_per_pixel'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
|
||||
$info['video']['resolution_x'] = $thisfile_bmp_header_raw['width'];
|
||||
$info['video']['resolution_y'] = $thisfile_bmp_header_raw['height'];
|
||||
$info['video']['codec'] = 'BI_RGB '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit';
|
||||
$info['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel'];
|
||||
|
||||
if ($thisfile_bmp['type_version'] >= 2) {
|
||||
// DWORD Compression; /* Bitmap compression scheme */
|
||||
// DWORD ImageDataSize; /* Size of bitmap data in bytes */
|
||||
// DWORD XResolution; /* X resolution of display device */
|
||||
// DWORD YResolution; /* Y resolution of display device */
|
||||
// DWORD ColorsUsed; /* Number of color table indices used */
|
||||
// DWORD ColorsImportant; /* Number of important color indices */
|
||||
// WORD Units; /* Type of units used to measure resolution */
|
||||
// WORD Reserved; /* Pad structure to 4-byte boundary */
|
||||
// WORD Recording; /* Recording algorithm */
|
||||
// WORD Rendering; /* Halftoning algorithm used */
|
||||
// DWORD Size1; /* Reserved for halftoning algorithm use */
|
||||
// DWORD Size2; /* Reserved for halftoning algorithm use */
|
||||
// DWORD ColorEncoding; /* Color model used in bitmap */
|
||||
// DWORD Identifier; /* Reserved for application use */
|
||||
|
||||
$thisfile_bmp_header_raw['compression'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['bmp_data_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['resolution_h'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['resolution_v'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['colors_used'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['colors_important'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['resolution_units'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['reserved1'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['recording'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['rendering'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['size1'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['size2'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['color_encoding'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['identifier'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$thisfile_bmp_header['compression'] = $this->BMPcompressionOS2Lookup($thisfile_bmp_header_raw['compression']);
|
||||
|
||||
$info['video']['codec'] = $thisfile_bmp_header['compression'].' '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit';
|
||||
}
|
||||
|
||||
} elseif ($thisfile_bmp['type_os'] == 'Windows') {
|
||||
|
||||
// Windows-format BMP
|
||||
|
||||
// BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp
|
||||
// all versions
|
||||
// DWORD biSize;
|
||||
// LONG biWidth;
|
||||
// LONG biHeight;
|
||||
// WORD biPlanes;
|
||||
// WORD biBitCount;
|
||||
// DWORD biCompression;
|
||||
// DWORD biSizeImage;
|
||||
// LONG biXPelsPerMeter;
|
||||
// LONG biYPelsPerMeter;
|
||||
// DWORD biClrUsed;
|
||||
// DWORD biClrImportant;
|
||||
|
||||
// possibly integrate this section and module.audio-video.riff.php::ParseBITMAPINFOHEADER() ?
|
||||
|
||||
$thisfile_bmp_header_raw['width'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['height'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['planes'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['bits_per_pixel'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_bmp_header_raw['compression'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['bmp_data_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['resolution_h'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['resolution_v'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['colors_used'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['colors_important'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$thisfile_bmp_header['compression'] = $this->BMPcompressionWindowsLookup($thisfile_bmp_header_raw['compression']);
|
||||
$info['video']['resolution_x'] = $thisfile_bmp_header_raw['width'];
|
||||
$info['video']['resolution_y'] = $thisfile_bmp_header_raw['height'];
|
||||
$info['video']['codec'] = $thisfile_bmp_header['compression'].' '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit';
|
||||
$info['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel'];
|
||||
|
||||
if (($thisfile_bmp['type_version'] >= 4) || ($thisfile_bmp_header_raw['compression'] == 3)) {
|
||||
// should only be v4+, but BMPs with type_version==1 and BI_BITFIELDS compression have been seen
|
||||
$BMPheader .= fread($this->getid3->fp, 44);
|
||||
|
||||
// BITMAPV4HEADER - [44 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_2k1e.asp
|
||||
// Win95+, WinNT4.0+
|
||||
// DWORD bV4RedMask;
|
||||
// DWORD bV4GreenMask;
|
||||
// DWORD bV4BlueMask;
|
||||
// DWORD bV4AlphaMask;
|
||||
// DWORD bV4CSType;
|
||||
// CIEXYZTRIPLE bV4Endpoints;
|
||||
// DWORD bV4GammaRed;
|
||||
// DWORD bV4GammaGreen;
|
||||
// DWORD bV4GammaBlue;
|
||||
$thisfile_bmp_header_raw['red_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['green_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['blue_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['alpha_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['cs_type'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['ciexyz_red'] = substr($BMPheader, $offset, 4);
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['ciexyz_green'] = substr($BMPheader, $offset, 4);
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['ciexyz_blue'] = substr($BMPheader, $offset, 4);
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['gamma_red'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['gamma_green'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['gamma_blue'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$thisfile_bmp_header['ciexyz_red'] = getid3_lib::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_red']));
|
||||
$thisfile_bmp_header['ciexyz_green'] = getid3_lib::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_green']));
|
||||
$thisfile_bmp_header['ciexyz_blue'] = getid3_lib::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_blue']));
|
||||
}
|
||||
|
||||
if ($thisfile_bmp['type_version'] >= 5) {
|
||||
$BMPheader .= fread($this->getid3->fp, 16);
|
||||
|
||||
// BITMAPV5HEADER - [16 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_7c36.asp
|
||||
// Win98+, Win2000+
|
||||
// DWORD bV5Intent;
|
||||
// DWORD bV5ProfileData;
|
||||
// DWORD bV5ProfileSize;
|
||||
// DWORD bV5Reserved;
|
||||
$thisfile_bmp_header_raw['intent'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['profile_data_offset'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['profile_data_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_bmp_header_raw['reserved3'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$info['error'][] = 'Unknown BMP format in header.';
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
if ($this->ExtractPalette || $this->ExtractData) {
|
||||
$PaletteEntries = 0;
|
||||
if ($thisfile_bmp_header_raw['bits_per_pixel'] < 16) {
|
||||
$PaletteEntries = pow(2, $thisfile_bmp_header_raw['bits_per_pixel']);
|
||||
} elseif (isset($thisfile_bmp_header_raw['colors_used']) && ($thisfile_bmp_header_raw['colors_used'] > 0) && ($thisfile_bmp_header_raw['colors_used'] <= 256)) {
|
||||
$PaletteEntries = $thisfile_bmp_header_raw['colors_used'];
|
||||
}
|
||||
if ($PaletteEntries > 0) {
|
||||
$BMPpalette = fread($this->getid3->fp, 4 * $PaletteEntries);
|
||||
$paletteoffset = 0;
|
||||
for ($i = 0; $i < $PaletteEntries; $i++) {
|
||||
// RGBQUAD - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_5f8y.asp
|
||||
// BYTE rgbBlue;
|
||||
// BYTE rgbGreen;
|
||||
// BYTE rgbRed;
|
||||
// BYTE rgbReserved;
|
||||
$blue = getid3_lib::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
|
||||
$green = getid3_lib::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
|
||||
$red = getid3_lib::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
|
||||
if (($thisfile_bmp['type_os'] == 'OS/2') && ($thisfile_bmp['type_version'] == 1)) {
|
||||
// no padding byte
|
||||
} else {
|
||||
$paletteoffset++; // padding byte
|
||||
}
|
||||
$thisfile_bmp['palette'][$i] = (($red << 16) | ($green << 8) | $blue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->ExtractData) {
|
||||
fseek($this->getid3->fp, $thisfile_bmp_header_raw['data_offset'], SEEK_SET);
|
||||
$RowByteLength = ceil(($thisfile_bmp_header_raw['width'] * ($thisfile_bmp_header_raw['bits_per_pixel'] / 8)) / 4) * 4; // round up to nearest DWORD boundry
|
||||
$BMPpixelData = fread($this->getid3->fp, $thisfile_bmp_header_raw['height'] * $RowByteLength);
|
||||
$pixeldataoffset = 0;
|
||||
$thisfile_bmp_header_raw['compression'] = (isset($thisfile_bmp_header_raw['compression']) ? $thisfile_bmp_header_raw['compression'] : '');
|
||||
switch ($thisfile_bmp_header_raw['compression']) {
|
||||
|
||||
case 0: // BI_RGB
|
||||
switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
|
||||
case 1:
|
||||
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
|
||||
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
|
||||
$paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++});
|
||||
for ($i = 7; $i >= 0; $i--) {
|
||||
$paletteindex = ($paletteindexbyte & (0x01 << $i)) >> $i;
|
||||
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
|
||||
$col++;
|
||||
}
|
||||
}
|
||||
while (($pixeldataoffset % 4) != 0) {
|
||||
// lines are padded to nearest DWORD
|
||||
$pixeldataoffset++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
|
||||
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
|
||||
$paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++});
|
||||
for ($i = 1; $i >= 0; $i--) {
|
||||
$paletteindex = ($paletteindexbyte & (0x0F << (4 * $i))) >> (4 * $i);
|
||||
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
|
||||
$col++;
|
||||
}
|
||||
}
|
||||
while (($pixeldataoffset % 4) != 0) {
|
||||
// lines are padded to nearest DWORD
|
||||
$pixeldataoffset++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
|
||||
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
|
||||
$paletteindex = ord($BMPpixelData{$pixeldataoffset++});
|
||||
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
|
||||
}
|
||||
while (($pixeldataoffset % 4) != 0) {
|
||||
// lines are padded to nearest DWORD
|
||||
$pixeldataoffset++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 24:
|
||||
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
|
||||
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
|
||||
$thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData{$pixeldataoffset+2}) << 16) | (ord($BMPpixelData{$pixeldataoffset+1}) << 8) | ord($BMPpixelData{$pixeldataoffset});
|
||||
$pixeldataoffset += 3;
|
||||
}
|
||||
while (($pixeldataoffset % 4) != 0) {
|
||||
// lines are padded to nearest DWORD
|
||||
$pixeldataoffset++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 32:
|
||||
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
|
||||
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
|
||||
$thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData{$pixeldataoffset+3}) << 24) | (ord($BMPpixelData{$pixeldataoffset+2}) << 16) | (ord($BMPpixelData{$pixeldataoffset+1}) << 8) | ord($BMPpixelData{$pixeldataoffset});
|
||||
$pixeldataoffset += 4;
|
||||
}
|
||||
while (($pixeldataoffset % 4) != 0) {
|
||||
// lines are padded to nearest DWORD
|
||||
$pixeldataoffset++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 16:
|
||||
// ?
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 1: // BI_RLE8 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp
|
||||
switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
|
||||
case 8:
|
||||
$pixelcounter = 0;
|
||||
while ($pixeldataoffset < strlen($BMPpixelData)) {
|
||||
$firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
$secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
if ($firstbyte == 0) {
|
||||
|
||||
// escaped/absolute mode - the first byte of the pair can be set to zero to
|
||||
// indicate an escape character that denotes the end of a line, the end of
|
||||
// a bitmap, or a delta, depending on the value of the second byte.
|
||||
switch ($secondbyte) {
|
||||
case 0:
|
||||
// end of line
|
||||
// no need for special processing, just ignore
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// end of bitmap
|
||||
$pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// delta - The 2 bytes following the escape contain unsigned values
|
||||
// indicating the horizontal and vertical offsets of the next pixel
|
||||
// from the current position.
|
||||
$colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
$rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
$col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement;
|
||||
$row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement;
|
||||
$pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col;
|
||||
break;
|
||||
|
||||
default:
|
||||
// In absolute mode, the first byte is zero and the second byte is a
|
||||
// value in the range 03H through FFH. The second byte represents the
|
||||
// number of bytes that follow, each of which contains the color index
|
||||
// of a single pixel. Each run must be aligned on a word boundary.
|
||||
for ($i = 0; $i < $secondbyte; $i++) {
|
||||
$paletteindex = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
$col = $pixelcounter % $thisfile_bmp_header_raw['width'];
|
||||
$row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
|
||||
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
|
||||
$pixelcounter++;
|
||||
}
|
||||
while (($pixeldataoffset % 2) != 0) {
|
||||
// Each run must be aligned on a word boundary.
|
||||
$pixeldataoffset++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// encoded mode - the first byte specifies the number of consecutive pixels
|
||||
// to be drawn using the color index contained in the second byte.
|
||||
for ($i = 0; $i < $firstbyte; $i++) {
|
||||
$col = $pixelcounter % $thisfile_bmp_header_raw['width'];
|
||||
$row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
|
||||
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$secondbyte];
|
||||
$pixelcounter++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case 2: // BI_RLE4 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp
|
||||
switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
|
||||
case 4:
|
||||
$pixelcounter = 0;
|
||||
while ($pixeldataoffset < strlen($BMPpixelData)) {
|
||||
$firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
$secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
if ($firstbyte == 0) {
|
||||
|
||||
// escaped/absolute mode - the first byte of the pair can be set to zero to
|
||||
// indicate an escape character that denotes the end of a line, the end of
|
||||
// a bitmap, or a delta, depending on the value of the second byte.
|
||||
switch ($secondbyte) {
|
||||
case 0:
|
||||
// end of line
|
||||
// no need for special processing, just ignore
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// end of bitmap
|
||||
$pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// delta - The 2 bytes following the escape contain unsigned values
|
||||
// indicating the horizontal and vertical offsets of the next pixel
|
||||
// from the current position.
|
||||
$colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
$rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
$col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement;
|
||||
$row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement;
|
||||
$pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col;
|
||||
break;
|
||||
|
||||
default:
|
||||
// In absolute mode, the first byte is zero. The second byte contains the number
|
||||
// of color indexes that follow. Subsequent bytes contain color indexes in their
|
||||
// high- and low-order 4 bits, one color index for each pixel. In absolute mode,
|
||||
// each run must be aligned on a word boundary.
|
||||
unset($paletteindexes);
|
||||
for ($i = 0; $i < ceil($secondbyte / 2); $i++) {
|
||||
$paletteindexbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
|
||||
$paletteindexes[] = ($paletteindexbyte & 0xF0) >> 4;
|
||||
$paletteindexes[] = ($paletteindexbyte & 0x0F);
|
||||
}
|
||||
while (($pixeldataoffset % 2) != 0) {
|
||||
// Each run must be aligned on a word boundary.
|
||||
$pixeldataoffset++;
|
||||
}
|
||||
|
||||
foreach ($paletteindexes as $paletteindex) {
|
||||
$col = $pixelcounter % $thisfile_bmp_header_raw['width'];
|
||||
$row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
|
||||
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
|
||||
$pixelcounter++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// encoded mode - the first byte of the pair contains the number of pixels to be
|
||||
// drawn using the color indexes in the second byte. The second byte contains two
|
||||
// color indexes, one in its high-order 4 bits and one in its low-order 4 bits.
|
||||
// The first of the pixels is drawn using the color specified by the high-order
|
||||
// 4 bits, the second is drawn using the color in the low-order 4 bits, the third
|
||||
// is drawn using the color in the high-order 4 bits, and so on, until all the
|
||||
// pixels specified by the first byte have been drawn.
|
||||
$paletteindexes[0] = ($secondbyte & 0xF0) >> 4;
|
||||
$paletteindexes[1] = ($secondbyte & 0x0F);
|
||||
for ($i = 0; $i < $firstbyte; $i++) {
|
||||
$col = $pixelcounter % $thisfile_bmp_header_raw['width'];
|
||||
$row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
|
||||
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindexes[($i % 2)]];
|
||||
$pixelcounter++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 3: // BI_BITFIELDS
|
||||
switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
|
||||
case 16:
|
||||
case 32:
|
||||
$redshift = 0;
|
||||
$greenshift = 0;
|
||||
$blueshift = 0;
|
||||
while ((($thisfile_bmp_header_raw['red_mask'] >> $redshift) & 0x01) == 0) {
|
||||
$redshift++;
|
||||
}
|
||||
while ((($thisfile_bmp_header_raw['green_mask'] >> $greenshift) & 0x01) == 0) {
|
||||
$greenshift++;
|
||||
}
|
||||
while ((($thisfile_bmp_header_raw['blue_mask'] >> $blueshift) & 0x01) == 0) {
|
||||
$blueshift++;
|
||||
}
|
||||
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
|
||||
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
|
||||
$pixelvalue = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset, $thisfile_bmp_header_raw['bits_per_pixel'] / 8));
|
||||
$pixeldataoffset += $thisfile_bmp_header_raw['bits_per_pixel'] / 8;
|
||||
|
||||
$red = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['red_mask']) >> $redshift) / ($thisfile_bmp_header_raw['red_mask'] >> $redshift)) * 255));
|
||||
$green = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['green_mask']) >> $greenshift) / ($thisfile_bmp_header_raw['green_mask'] >> $greenshift)) * 255));
|
||||
$blue = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['blue_mask']) >> $blueshift) / ($thisfile_bmp_header_raw['blue_mask'] >> $blueshift)) * 255));
|
||||
$thisfile_bmp['data'][$row][$col] = (($red << 16) | ($green << 8) | ($blue));
|
||||
}
|
||||
while (($pixeldataoffset % 4) != 0) {
|
||||
// lines are padded to nearest DWORD
|
||||
$pixeldataoffset++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default: // unhandled compression type
|
||||
$info['error'][] = 'Unknown/unhandled compression type value ('.$thisfile_bmp_header_raw['compression'].') - cannot decompress pixel data';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function PlotBMP(&$BMPinfo) {
|
||||
$starttime = time();
|
||||
if (!isset($BMPinfo['bmp']['data']) || !is_array($BMPinfo['bmp']['data'])) {
|
||||
echo 'ERROR: no pixel data<BR>';
|
||||
return false;
|
||||
}
|
||||
set_time_limit(intval(round($BMPinfo['resolution_x'] * $BMPinfo['resolution_y'] / 10000)));
|
||||
if ($im = ImageCreateTrueColor($BMPinfo['resolution_x'], $BMPinfo['resolution_y'])) {
|
||||
for ($row = 0; $row < $BMPinfo['resolution_y']; $row++) {
|
||||
for ($col = 0; $col < $BMPinfo['resolution_x']; $col++) {
|
||||
if (isset($BMPinfo['bmp']['data'][$row][$col])) {
|
||||
$red = ($BMPinfo['bmp']['data'][$row][$col] & 0x00FF0000) >> 16;
|
||||
$green = ($BMPinfo['bmp']['data'][$row][$col] & 0x0000FF00) >> 8;
|
||||
$blue = ($BMPinfo['bmp']['data'][$row][$col] & 0x000000FF);
|
||||
$pixelcolor = ImageColorAllocate($im, $red, $green, $blue);
|
||||
ImageSetPixel($im, $col, $row, $pixelcolor);
|
||||
} else {
|
||||
//echo 'ERROR: no data for pixel '.$row.' x '.$col.'<BR>';
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (headers_sent()) {
|
||||
echo 'plotted '.($BMPinfo['resolution_x'] * $BMPinfo['resolution_y']).' pixels in '.(time() - $starttime).' seconds<BR>';
|
||||
ImageDestroy($im);
|
||||
exit;
|
||||
} else {
|
||||
header('Content-type: image/png');
|
||||
ImagePNG($im);
|
||||
ImageDestroy($im);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function BMPcompressionWindowsLookup($compressionid) {
|
||||
static $BMPcompressionWindowsLookup = array(
|
||||
0 => 'BI_RGB',
|
||||
1 => 'BI_RLE8',
|
||||
2 => 'BI_RLE4',
|
||||
3 => 'BI_BITFIELDS',
|
||||
4 => 'BI_JPEG',
|
||||
5 => 'BI_PNG'
|
||||
);
|
||||
return (isset($BMPcompressionWindowsLookup[$compressionid]) ? $BMPcompressionWindowsLookup[$compressionid] : 'invalid');
|
||||
}
|
||||
|
||||
function BMPcompressionOS2Lookup($compressionid) {
|
||||
static $BMPcompressionOS2Lookup = array(
|
||||
0 => 'BI_RGB',
|
||||
1 => 'BI_RLE8',
|
||||
2 => 'BI_RLE4',
|
||||
3 => 'Huffman 1D',
|
||||
4 => 'BI_RLE24',
|
||||
);
|
||||
return (isset($BMPcompressionOS2Lookup[$compressionid]) ? $BMPcompressionOS2Lookup[$compressionid] : 'invalid');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
53
lib/getid3/getid3/module.graphic.efax.php
Normal file
53
lib/getid3/getid3/module.graphic.efax.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.efax.php //
|
||||
// module for analyzing eFax files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_efax extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$efaxheader = fread($this->getid3->fp, 1024);
|
||||
|
||||
$info['efax']['header']['magic'] = substr($efaxheader, 0, 2);
|
||||
if ($info['efax']['header']['magic'] != "\xDC\xFE") {
|
||||
$info['error'][] = 'Invalid eFax byte order identifier (expecting DC FE, found '.getid3_lib::PrintHexBytes($info['efax']['header']['magic']).') at offset '.$info['avdataoffset'];
|
||||
return false;
|
||||
}
|
||||
$info['fileformat'] = 'efax';
|
||||
|
||||
$info['efax']['header']['filesize'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 2, 4));
|
||||
if ($info['efax']['header']['filesize'] != $info['filesize']) {
|
||||
$info['error'][] = 'Probable '.(($info['efax']['header']['filesize'] > $info['filesize']) ? 'truncated' : 'corrupt').' file, expecting '.$info['efax']['header']['filesize'].' bytes, found '.$info['filesize'].' bytes';
|
||||
}
|
||||
$info['efax']['header']['software1'] = rtrim(substr($efaxheader, 26, 32), "\x00");
|
||||
$info['efax']['header']['software2'] = rtrim(substr($efaxheader, 58, 32), "\x00");
|
||||
$info['efax']['header']['software3'] = rtrim(substr($efaxheader, 90, 32), "\x00");
|
||||
|
||||
$info['efax']['header']['pages'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 198, 2));
|
||||
$info['efax']['header']['data_bytes'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 202, 4));
|
||||
|
||||
$info['error'][] = 'eFax parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
184
lib/getid3/getid3/module.graphic.gif.php
Normal file
184
lib/getid3/getid3/module.graphic.gif.php
Normal file
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.graphic.gif.php //
|
||||
// module for analyzing GIF Image files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_gif extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'gif';
|
||||
$info['video']['dataformat'] = 'gif';
|
||||
$info['video']['lossless'] = true;
|
||||
$info['video']['pixel_aspect_ratio'] = (float) 1;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$GIFheader = fread($this->getid3->fp, 13);
|
||||
$offset = 0;
|
||||
|
||||
$info['gif']['header']['raw']['identifier'] = substr($GIFheader, $offset, 3);
|
||||
$offset += 3;
|
||||
|
||||
$magic = 'GIF';
|
||||
if ($info['gif']['header']['raw']['identifier'] != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['gif']['header']['raw']['identifier']).'"';
|
||||
unset($info['fileformat']);
|
||||
unset($info['gif']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['gif']['header']['raw']['version'] = substr($GIFheader, $offset, 3);
|
||||
$offset += 3;
|
||||
$info['gif']['header']['raw']['width'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$info['gif']['header']['raw']['height'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$info['gif']['header']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1));
|
||||
$offset += 1;
|
||||
$info['gif']['header']['raw']['bg_color_index'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1));
|
||||
$offset += 1;
|
||||
$info['gif']['header']['raw']['aspect_ratio'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1));
|
||||
$offset += 1;
|
||||
|
||||
$info['video']['resolution_x'] = $info['gif']['header']['raw']['width'];
|
||||
$info['video']['resolution_y'] = $info['gif']['header']['raw']['height'];
|
||||
$info['gif']['version'] = $info['gif']['header']['raw']['version'];
|
||||
$info['gif']['header']['flags']['global_color_table'] = (bool) ($info['gif']['header']['raw']['flags'] & 0x80);
|
||||
if ($info['gif']['header']['raw']['flags'] & 0x80) {
|
||||
// Number of bits per primary color available to the original image, minus 1
|
||||
$info['gif']['header']['bits_per_pixel'] = 3 * ((($info['gif']['header']['raw']['flags'] & 0x70) >> 4) + 1);
|
||||
} else {
|
||||
$info['gif']['header']['bits_per_pixel'] = 0;
|
||||
}
|
||||
$info['gif']['header']['flags']['global_color_sorted'] = (bool) ($info['gif']['header']['raw']['flags'] & 0x40);
|
||||
if ($info['gif']['header']['flags']['global_color_table']) {
|
||||
// the number of bytes contained in the Global Color Table. To determine that
|
||||
// actual size of the color table, raise 2 to [the value of the field + 1]
|
||||
$info['gif']['header']['global_color_size'] = pow(2, ($info['gif']['header']['raw']['flags'] & 0x07) + 1);
|
||||
$info['video']['bits_per_sample'] = ($info['gif']['header']['raw']['flags'] & 0x07) + 1;
|
||||
} else {
|
||||
$info['gif']['header']['global_color_size'] = 0;
|
||||
}
|
||||
if ($info['gif']['header']['raw']['aspect_ratio'] != 0) {
|
||||
// Aspect Ratio = (Pixel Aspect Ratio + 15) / 64
|
||||
$info['gif']['header']['aspect_ratio'] = ($info['gif']['header']['raw']['aspect_ratio'] + 15) / 64;
|
||||
}
|
||||
|
||||
// if ($info['gif']['header']['flags']['global_color_table']) {
|
||||
// $GIFcolorTable = fread($this->getid3->fp, 3 * $info['gif']['header']['global_color_size']);
|
||||
// $offset = 0;
|
||||
// for ($i = 0; $i < $info['gif']['header']['global_color_size']; $i++) {
|
||||
// $red = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
|
||||
// $green = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
|
||||
// $blue = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
|
||||
// $info['gif']['global_color_table'][$i] = (($red << 16) | ($green << 8) | ($blue));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Image Descriptor
|
||||
// while (!feof($this->getid3->fp)) {
|
||||
// $NextBlockTest = fread($this->getid3->fp, 1);
|
||||
// switch ($NextBlockTest) {
|
||||
//
|
||||
// case ',': // ',' - Image separator character
|
||||
//
|
||||
// $ImageDescriptorData = $NextBlockTest.fread($this->getid3->fp, 9);
|
||||
// $ImageDescriptor = array();
|
||||
// $ImageDescriptor['image_left'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 1, 2));
|
||||
// $ImageDescriptor['image_top'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 3, 2));
|
||||
// $ImageDescriptor['image_width'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 5, 2));
|
||||
// $ImageDescriptor['image_height'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 7, 2));
|
||||
// $ImageDescriptor['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 9, 1));
|
||||
// $ImageDescriptor['flags']['use_local_color_map'] = (bool) ($ImageDescriptor['flags_raw'] & 0x80);
|
||||
// $ImageDescriptor['flags']['image_interlaced'] = (bool) ($ImageDescriptor['flags_raw'] & 0x40);
|
||||
// $info['gif']['image_descriptor'][] = $ImageDescriptor;
|
||||
//
|
||||
// if ($ImageDescriptor['flags']['use_local_color_map']) {
|
||||
//
|
||||
// $info['warning'][] = 'This version of getID3() cannot parse local color maps for GIFs';
|
||||
// return true;
|
||||
//
|
||||
// }
|
||||
//echo 'Start of raster data: '.ftell($this->getid3->fp).'<BR>';
|
||||
// $RasterData = array();
|
||||
// $RasterData['code_size'] = getid3_lib::LittleEndian2Int(fread($this->getid3->fp, 1));
|
||||
// $RasterData['block_byte_count'] = getid3_lib::LittleEndian2Int(fread($this->getid3->fp, 1));
|
||||
// $info['gif']['raster_data'][count($info['gif']['image_descriptor']) - 1] = $RasterData;
|
||||
//
|
||||
// $CurrentCodeSize = $RasterData['code_size'] + 1;
|
||||
// for ($i = 0; $i < pow(2, $RasterData['code_size']); $i++) {
|
||||
// $DefaultDataLookupTable[$i] = chr($i);
|
||||
// }
|
||||
// $DefaultDataLookupTable[pow(2, $RasterData['code_size']) + 0] = ''; // Clear Code
|
||||
// $DefaultDataLookupTable[pow(2, $RasterData['code_size']) + 1] = ''; // End Of Image Code
|
||||
//
|
||||
//
|
||||
// $NextValue = $this->GetLSBits($CurrentCodeSize);
|
||||
// echo 'Clear Code: '.$NextValue.'<BR>';
|
||||
//
|
||||
// $NextValue = $this->GetLSBits($CurrentCodeSize);
|
||||
// echo 'First Color: '.$NextValue.'<BR>';
|
||||
//
|
||||
// $Prefix = $NextValue;
|
||||
//$i = 0;
|
||||
// while ($i++ < 20) {
|
||||
// $NextValue = $this->GetLSBits($CurrentCodeSize);
|
||||
// echo $NextValue.'<BR>';
|
||||
// }
|
||||
//return true;
|
||||
// break;
|
||||
//
|
||||
// case '!':
|
||||
// // GIF Extension Block
|
||||
// $ExtensionBlockData = $NextBlockTest.fread($this->getid3->fp, 2);
|
||||
// $ExtensionBlock = array();
|
||||
// $ExtensionBlock['function_code'] = getid3_lib::LittleEndian2Int(substr($ExtensionBlockData, 1, 1));
|
||||
// $ExtensionBlock['byte_length'] = getid3_lib::LittleEndian2Int(substr($ExtensionBlockData, 2, 1));
|
||||
// $ExtensionBlock['data'] = fread($this->getid3->fp, $ExtensionBlock['byte_length']);
|
||||
// $info['gif']['extension_blocks'][] = $ExtensionBlock;
|
||||
// break;
|
||||
//
|
||||
// case ';':
|
||||
// $info['gif']['terminator_offset'] = ftell($this->getid3->fp) - 1;
|
||||
// // GIF Terminator
|
||||
// break;
|
||||
//
|
||||
// default:
|
||||
// break;
|
||||
//
|
||||
//
|
||||
// }
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function GetLSBits($bits) {
|
||||
static $bitbuffer = '';
|
||||
while (strlen($bitbuffer) < $bits) {
|
||||
$bitbuffer = str_pad(decbin(ord(fread($this->getid3->fp, 1))), 8, '0', STR_PAD_LEFT).$bitbuffer;
|
||||
}
|
||||
$value = bindec(substr($bitbuffer, 0 - $bits));
|
||||
$bitbuffer = substr($bitbuffer, 0, 0 - $bits);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
338
lib/getid3/getid3/module.graphic.jpg.php
Normal file
338
lib/getid3/getid3/module.graphic.jpg.php
Normal file
|
@ -0,0 +1,338 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.graphic.jpg.php //
|
||||
// module for analyzing JPEG Image files //
|
||||
// dependencies: PHP compiled with --enable-exif (optional) //
|
||||
// module.tag.xmp.php (optional) //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_jpg extends getid3_handler
|
||||
{
|
||||
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'jpg';
|
||||
$info['video']['dataformat'] = 'jpg';
|
||||
$info['video']['lossless'] = false;
|
||||
$info['video']['bits_per_sample'] = 24;
|
||||
$info['video']['pixel_aspect_ratio'] = (float) 1;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
|
||||
$imageinfo = array();
|
||||
list($width, $height, $type) = getid3_lib::GetDataImageSize(fread($this->getid3->fp, $info['filesize']), $imageinfo);
|
||||
|
||||
|
||||
if (isset($imageinfo['APP13'])) {
|
||||
// http://php.net/iptcparse
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
|
||||
$iptc_parsed = iptcparse($imageinfo['APP13']);
|
||||
if (is_array($iptc_parsed)) {
|
||||
foreach ($iptc_parsed as $iptc_key_raw => $iptc_values) {
|
||||
list($iptc_record, $iptc_tagkey) = explode('#', $iptc_key_raw);
|
||||
$iptc_tagkey = intval(ltrim($iptc_tagkey, '0'));
|
||||
foreach ($iptc_values as $key => $value) {
|
||||
$IPTCrecordName = $this->IPTCrecordName($iptc_record);
|
||||
$IPTCrecordTagName = $this->IPTCrecordTagName($iptc_record, $iptc_tagkey);
|
||||
if (isset($info['iptc'][$IPTCrecordName][$IPTCrecordTagName])) {
|
||||
$info['iptc'][$IPTCrecordName][$IPTCrecordTagName][] = $value;
|
||||
} else {
|
||||
$info['iptc'][$IPTCrecordName][$IPTCrecordTagName] = array($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$returnOK = false;
|
||||
switch ($type) {
|
||||
case IMG_JPG:
|
||||
$info['video']['resolution_x'] = $width;
|
||||
$info['video']['resolution_y'] = $height;
|
||||
|
||||
if (isset($imageinfo['APP1'])) {
|
||||
if (function_exists('exif_read_data')) {
|
||||
if (substr($imageinfo['APP1'], 0, 4) == 'Exif') {
|
||||
$info['jpg']['exif'] = @exif_read_data($info['filenamepath'], '', true, false);
|
||||
} else {
|
||||
$info['warning'][] = 'exif_read_data() cannot parse non-EXIF data in APP1 (expected "Exif", found "'.substr($imageinfo['APP1'], 0, 4).'")';
|
||||
}
|
||||
} else {
|
||||
$info['warning'][] = 'EXIF parsing only available when '.(GETID3_OS_ISWINDOWS ? 'php_exif.dll enabled' : 'compiled with --enable-exif');
|
||||
}
|
||||
}
|
||||
$returnOK = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
$cast_as_appropriate_keys = array('EXIF', 'IFD0', 'THUMBNAIL');
|
||||
foreach ($cast_as_appropriate_keys as $exif_key) {
|
||||
if (isset($info['jpg']['exif'][$exif_key])) {
|
||||
foreach ($info['jpg']['exif'][$exif_key] as $key => $value) {
|
||||
$info['jpg']['exif'][$exif_key][$key] = $this->CastAsAppropriate($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isset($info['jpg']['exif']['GPS'])) {
|
||||
|
||||
if (isset($info['jpg']['exif']['GPS']['GPSVersion'])) {
|
||||
for ($i = 0; $i < 4; $i++) {
|
||||
$version_subparts[$i] = ord(substr($info['jpg']['exif']['GPS']['GPSVersion'], $i, 1));
|
||||
}
|
||||
$info['jpg']['exif']['GPS']['computed']['version'] = 'v'.implode('.', $version_subparts);
|
||||
}
|
||||
|
||||
if (isset($info['jpg']['exif']['GPS']['GPSDateStamp'])) {
|
||||
$explodedGPSDateStamp = explode(':', $info['jpg']['exif']['GPS']['GPSDateStamp']);
|
||||
$computed_time[5] = (isset($explodedGPSDateStamp[0]) ? $explodedGPSDateStamp[0] : '');
|
||||
$computed_time[3] = (isset($explodedGPSDateStamp[1]) ? $explodedGPSDateStamp[1] : '');
|
||||
$computed_time[4] = (isset($explodedGPSDateStamp[2]) ? $explodedGPSDateStamp[2] : '');
|
||||
|
||||
if (function_exists('date_default_timezone_set')) {
|
||||
date_default_timezone_set('UTC');
|
||||
} else {
|
||||
ini_set('date.timezone', 'UTC');
|
||||
}
|
||||
|
||||
$computed_time = array(0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0);
|
||||
if (isset($info['jpg']['exif']['GPS']['GPSTimeStamp']) && is_array($info['jpg']['exif']['GPS']['GPSTimeStamp'])) {
|
||||
foreach ($info['jpg']['exif']['GPS']['GPSTimeStamp'] as $key => $value) {
|
||||
$computed_time[$key] = getid3_lib::DecimalizeFraction($value);
|
||||
}
|
||||
}
|
||||
$info['jpg']['exif']['GPS']['computed']['timestamp'] = mktime($computed_time[0], $computed_time[1], $computed_time[2], $computed_time[3], $computed_time[4], $computed_time[5]);
|
||||
}
|
||||
|
||||
if (isset($info['jpg']['exif']['GPS']['GPSLatitude']) && is_array($info['jpg']['exif']['GPS']['GPSLatitude'])) {
|
||||
$direction_multiplier = ((isset($info['jpg']['exif']['GPS']['GPSLatitudeRef']) && ($info['jpg']['exif']['GPS']['GPSLatitudeRef'] == 'S')) ? -1 : 1);
|
||||
foreach ($info['jpg']['exif']['GPS']['GPSLatitude'] as $key => $value) {
|
||||
$computed_latitude[$key] = getid3_lib::DecimalizeFraction($value);
|
||||
}
|
||||
$info['jpg']['exif']['GPS']['computed']['latitude'] = $direction_multiplier * ($computed_latitude[0] + ($computed_latitude[1] / 60) + ($computed_latitude[2] / 3600));
|
||||
}
|
||||
|
||||
if (isset($info['jpg']['exif']['GPS']['GPSLongitude']) && is_array($info['jpg']['exif']['GPS']['GPSLongitude'])) {
|
||||
$direction_multiplier = ((isset($info['jpg']['exif']['GPS']['GPSLongitudeRef']) && ($info['jpg']['exif']['GPS']['GPSLongitudeRef'] == 'W')) ? -1 : 1);
|
||||
foreach ($info['jpg']['exif']['GPS']['GPSLongitude'] as $key => $value) {
|
||||
$computed_longitude[$key] = getid3_lib::DecimalizeFraction($value);
|
||||
}
|
||||
$info['jpg']['exif']['GPS']['computed']['longitude'] = $direction_multiplier * ($computed_longitude[0] + ($computed_longitude[1] / 60) + ($computed_longitude[2] / 3600));
|
||||
}
|
||||
|
||||
if (isset($info['jpg']['exif']['GPS']['GPSAltitude'])) {
|
||||
$direction_multiplier = ((isset($info['jpg']['exif']['GPS']['GPSAltitudeRef']) && ($info['jpg']['exif']['GPS']['GPSAltitudeRef'] === chr(1))) ? -1 : 1);
|
||||
$info['jpg']['exif']['GPS']['computed']['altitude'] = $direction_multiplier * getid3_lib::DecimalizeFraction($info['jpg']['exif']['GPS']['GPSAltitude']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.xmp.php', __FILE__, false)) {
|
||||
if (isset($info['filenamepath'])) {
|
||||
$image_xmp = new Image_XMP($info['filenamepath']);
|
||||
$xmp_raw = $image_xmp->getAllTags();
|
||||
foreach ($xmp_raw as $key => $value) {
|
||||
list($subsection, $tagname) = explode(':', $key);
|
||||
$info['xmp'][$subsection][$tagname] = $this->CastAsAppropriate($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$returnOK) {
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function CastAsAppropriate($value) {
|
||||
if (is_array($value)) {
|
||||
return $value;
|
||||
} elseif (preg_match('#^[0-9]+/[0-9]+$#', $value)) {
|
||||
return getid3_lib::DecimalizeFraction($value);
|
||||
} elseif (preg_match('#^[0-9]+$#', $value)) {
|
||||
return getid3_lib::CastAsInt($value);
|
||||
} elseif (preg_match('#^[0-9\.]+$#', $value)) {
|
||||
return (float) $value;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
function IPTCrecordName($iptc_record) {
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
|
||||
static $IPTCrecordName = array();
|
||||
if (empty($IPTCrecordName)) {
|
||||
$IPTCrecordName = array(
|
||||
1 => 'IPTCEnvelope',
|
||||
2 => 'IPTCApplication',
|
||||
3 => 'IPTCNewsPhoto',
|
||||
7 => 'IPTCPreObjectData',
|
||||
8 => 'IPTCObjectData',
|
||||
9 => 'IPTCPostObjectData',
|
||||
);
|
||||
}
|
||||
return (isset($IPTCrecordName[$iptc_record]) ? $IPTCrecordName[$iptc_record] : '');
|
||||
}
|
||||
|
||||
|
||||
function IPTCrecordTagName($iptc_record, $iptc_tagkey) {
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
|
||||
static $IPTCrecordTagName = array();
|
||||
if (empty($IPTCrecordTagName)) {
|
||||
$IPTCrecordTagName = array(
|
||||
1 => array( // IPTC EnvelopeRecord Tags
|
||||
0 => 'EnvelopeRecordVersion',
|
||||
5 => 'Destination',
|
||||
20 => 'FileFormat',
|
||||
22 => 'FileVersion',
|
||||
30 => 'ServiceIdentifier',
|
||||
40 => 'EnvelopeNumber',
|
||||
50 => 'ProductID',
|
||||
60 => 'EnvelopePriority',
|
||||
70 => 'DateSent',
|
||||
80 => 'TimeSent',
|
||||
90 => 'CodedCharacterSet',
|
||||
100 => 'UniqueObjectName',
|
||||
120 => 'ARMIdentifier',
|
||||
122 => 'ARMVersion',
|
||||
),
|
||||
2 => array( // IPTC ApplicationRecord Tags
|
||||
0 => 'ApplicationRecordVersion',
|
||||
3 => 'ObjectTypeReference',
|
||||
4 => 'ObjectAttributeReference',
|
||||
5 => 'ObjectName',
|
||||
7 => 'EditStatus',
|
||||
8 => 'EditorialUpdate',
|
||||
10 => 'Urgency',
|
||||
12 => 'SubjectReference',
|
||||
15 => 'Category',
|
||||
20 => 'SupplementalCategories',
|
||||
22 => 'FixtureIdentifier',
|
||||
25 => 'Keywords',
|
||||
26 => 'ContentLocationCode',
|
||||
27 => 'ContentLocationName',
|
||||
30 => 'ReleaseDate',
|
||||
35 => 'ReleaseTime',
|
||||
37 => 'ExpirationDate',
|
||||
38 => 'ExpirationTime',
|
||||
40 => 'SpecialInstructions',
|
||||
42 => 'ActionAdvised',
|
||||
45 => 'ReferenceService',
|
||||
47 => 'ReferenceDate',
|
||||
50 => 'ReferenceNumber',
|
||||
55 => 'DateCreated',
|
||||
60 => 'TimeCreated',
|
||||
62 => 'DigitalCreationDate',
|
||||
63 => 'DigitalCreationTime',
|
||||
65 => 'OriginatingProgram',
|
||||
70 => 'ProgramVersion',
|
||||
75 => 'ObjectCycle',
|
||||
80 => 'By-line',
|
||||
85 => 'By-lineTitle',
|
||||
90 => 'City',
|
||||
92 => 'Sub-location',
|
||||
95 => 'Province-State',
|
||||
100 => 'Country-PrimaryLocationCode',
|
||||
101 => 'Country-PrimaryLocationName',
|
||||
103 => 'OriginalTransmissionReference',
|
||||
105 => 'Headline',
|
||||
110 => 'Credit',
|
||||
115 => 'Source',
|
||||
116 => 'CopyrightNotice',
|
||||
118 => 'Contact',
|
||||
120 => 'Caption-Abstract',
|
||||
121 => 'LocalCaption',
|
||||
122 => 'Writer-Editor',
|
||||
125 => 'RasterizedCaption',
|
||||
130 => 'ImageType',
|
||||
131 => 'ImageOrientation',
|
||||
135 => 'LanguageIdentifier',
|
||||
150 => 'AudioType',
|
||||
151 => 'AudioSamplingRate',
|
||||
152 => 'AudioSamplingResolution',
|
||||
153 => 'AudioDuration',
|
||||
154 => 'AudioOutcue',
|
||||
184 => 'JobID',
|
||||
185 => 'MasterDocumentID',
|
||||
186 => 'ShortDocumentID',
|
||||
187 => 'UniqueDocumentID',
|
||||
188 => 'OwnerID',
|
||||
200 => 'ObjectPreviewFileFormat',
|
||||
201 => 'ObjectPreviewFileVersion',
|
||||
202 => 'ObjectPreviewData',
|
||||
221 => 'Prefs',
|
||||
225 => 'ClassifyState',
|
||||
228 => 'SimilarityIndex',
|
||||
230 => 'DocumentNotes',
|
||||
231 => 'DocumentHistory',
|
||||
232 => 'ExifCameraInfo',
|
||||
),
|
||||
3 => array( // IPTC NewsPhoto Tags
|
||||
0 => 'NewsPhotoVersion',
|
||||
10 => 'IPTCPictureNumber',
|
||||
20 => 'IPTCImageWidth',
|
||||
30 => 'IPTCImageHeight',
|
||||
40 => 'IPTCPixelWidth',
|
||||
50 => 'IPTCPixelHeight',
|
||||
55 => 'SupplementalType',
|
||||
60 => 'ColorRepresentation',
|
||||
64 => 'InterchangeColorSpace',
|
||||
65 => 'ColorSequence',
|
||||
66 => 'ICC_Profile',
|
||||
70 => 'ColorCalibrationMatrix',
|
||||
80 => 'LookupTable',
|
||||
84 => 'NumIndexEntries',
|
||||
85 => 'ColorPalette',
|
||||
86 => 'IPTCBitsPerSample',
|
||||
90 => 'SampleStructure',
|
||||
100 => 'ScanningDirection',
|
||||
102 => 'IPTCImageRotation',
|
||||
110 => 'DataCompressionMethod',
|
||||
120 => 'QuantizationMethod',
|
||||
125 => 'EndPoints',
|
||||
130 => 'ExcursionTolerance',
|
||||
135 => 'BitsPerComponent',
|
||||
140 => 'MaximumDensityRange',
|
||||
145 => 'GammaCompensatedValue',
|
||||
),
|
||||
7 => array( // IPTC PreObjectData Tags
|
||||
10 => 'SizeMode',
|
||||
20 => 'MaxSubfileSize',
|
||||
90 => 'ObjectSizeAnnounced',
|
||||
95 => 'MaximumObjectSize',
|
||||
),
|
||||
8 => array( // IPTC ObjectData Tags
|
||||
10 => 'SubFile',
|
||||
),
|
||||
9 => array( // IPTC PostObjectData Tags
|
||||
10 => 'ConfirmedObjectSize',
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
return (isset($IPTCrecordTagName[$iptc_record][$iptc_tagkey]) ? $IPTCrecordTagName[$iptc_record][$iptc_tagkey] : $iptc_tagkey);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
134
lib/getid3/getid3/module.graphic.pcd.php
Normal file
134
lib/getid3/getid3/module.graphic.pcd.php
Normal file
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.graphic.pcd.php //
|
||||
// module for analyzing PhotoCD (PCD) Image files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_pcd extends getid3_handler
|
||||
{
|
||||
var $ExtractData = 0;
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'pcd';
|
||||
$info['video']['dataformat'] = 'pcd';
|
||||
$info['video']['lossless'] = false;
|
||||
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'] + 72, SEEK_SET);
|
||||
|
||||
$PCDflags = fread($this->getid3->fp, 1);
|
||||
$PCDisVertical = ((ord($PCDflags) & 0x01) ? true : false);
|
||||
|
||||
|
||||
if ($PCDisVertical) {
|
||||
$info['video']['resolution_x'] = 3072;
|
||||
$info['video']['resolution_y'] = 2048;
|
||||
} else {
|
||||
$info['video']['resolution_x'] = 2048;
|
||||
$info['video']['resolution_y'] = 3072;
|
||||
}
|
||||
|
||||
|
||||
if ($this->ExtractData > 3) {
|
||||
|
||||
$info['error'][] = 'Cannot extract PSD image data for detail levels above BASE (level-3) because encrypted with Kodak-proprietary compression/encryption.';
|
||||
|
||||
} elseif ($this->ExtractData > 0) {
|
||||
|
||||
$PCD_levels[1] = array( 192, 128, 0x02000); // BASE/16
|
||||
$PCD_levels[2] = array( 384, 256, 0x0B800); // BASE/4
|
||||
$PCD_levels[3] = array( 768, 512, 0x30000); // BASE
|
||||
//$PCD_levels[4] = array(1536, 1024, ??); // BASE*4 - encrypted with Kodak-proprietary compression/encryption
|
||||
//$PCD_levels[5] = array(3072, 2048, ??); // BASE*16 - encrypted with Kodak-proprietary compression/encryption
|
||||
//$PCD_levels[6] = array(6144, 4096, ??); // BASE*64 - encrypted with Kodak-proprietary compression/encryption; PhotoCD-Pro only
|
||||
|
||||
list($PCD_width, $PCD_height, $PCD_dataOffset) = $PCD_levels[3];
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'] + $PCD_dataOffset, SEEK_SET);
|
||||
|
||||
for ($y = 0; $y < $PCD_height; $y += 2) {
|
||||
// The image-data of these subtypes start at the respective offsets of 02000h, 0b800h and 30000h.
|
||||
// To decode the YcbYr to the more usual RGB-code, three lines of data have to be read, each
|
||||
// consisting of ‘w’ bytes, where ‘w’ is the width of the image-subtype. The first ‘w’ bytes and
|
||||
// the first half of the third ‘w’ bytes contain data for the first RGB-line, the second ‘w’ bytes
|
||||
// and the second half of the third ‘w’ bytes contain data for a second RGB-line.
|
||||
|
||||
$PCD_data_Y1 = fread($this->getid3->fp, $PCD_width);
|
||||
$PCD_data_Y2 = fread($this->getid3->fp, $PCD_width);
|
||||
$PCD_data_Cb = fread($this->getid3->fp, intval(round($PCD_width / 2)));
|
||||
$PCD_data_Cr = fread($this->getid3->fp, intval(round($PCD_width / 2)));
|
||||
|
||||
for ($x = 0; $x < $PCD_width; $x++) {
|
||||
if ($PCDisVertical) {
|
||||
$info['pcd']['data'][$PCD_width - $x][$y] = $this->YCbCr2RGB(ord($PCD_data_Y1{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)}));
|
||||
$info['pcd']['data'][$PCD_width - $x][$y + 1] = $this->YCbCr2RGB(ord($PCD_data_Y2{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)}));
|
||||
} else {
|
||||
$info['pcd']['data'][$y][$x] = $this->YCbCr2RGB(ord($PCD_data_Y1{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)}));
|
||||
$info['pcd']['data'][$y + 1][$x] = $this->YCbCr2RGB(ord($PCD_data_Y2{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example for plotting extracted data
|
||||
//getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
|
||||
//if ($PCDisVertical) {
|
||||
// $BMPinfo['resolution_x'] = $PCD_height;
|
||||
// $BMPinfo['resolution_y'] = $PCD_width;
|
||||
//} else {
|
||||
// $BMPinfo['resolution_x'] = $PCD_width;
|
||||
// $BMPinfo['resolution_y'] = $PCD_height;
|
||||
//}
|
||||
//$BMPinfo['bmp']['data'] = $info['pcd']['data'];
|
||||
//getid3_bmp::PlotBMP($BMPinfo);
|
||||
//exit;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function YCbCr2RGB($Y, $Cb, $Cr) {
|
||||
static $YCbCr_constants = array();
|
||||
if (empty($YCbCr_constants)) {
|
||||
$YCbCr_constants['red']['Y'] = 0.0054980 * 256;
|
||||
$YCbCr_constants['red']['Cb'] = 0.0000000 * 256;
|
||||
$YCbCr_constants['red']['Cr'] = 0.0051681 * 256;
|
||||
$YCbCr_constants['green']['Y'] = 0.0054980 * 256;
|
||||
$YCbCr_constants['green']['Cb'] = -0.0015446 * 256;
|
||||
$YCbCr_constants['green']['Cr'] = -0.0026325 * 256;
|
||||
$YCbCr_constants['blue']['Y'] = 0.0054980 * 256;
|
||||
$YCbCr_constants['blue']['Cb'] = 0.0079533 * 256;
|
||||
$YCbCr_constants['blue']['Cr'] = 0.0000000 * 256;
|
||||
}
|
||||
|
||||
$RGBcolor = array('red'=>0, 'green'=>0, 'blue'=>0);
|
||||
foreach ($RGBcolor as $rgbname => $dummy) {
|
||||
$RGBcolor[$rgbname] = max(0,
|
||||
min(255,
|
||||
intval(
|
||||
round(
|
||||
($YCbCr_constants[$rgbname]['Y'] * $Y) +
|
||||
($YCbCr_constants[$rgbname]['Cb'] * ($Cb - 156)) +
|
||||
($YCbCr_constants[$rgbname]['Cr'] * ($Cr - 137))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
return (($RGBcolor['red'] * 65536) + ($RGBcolor['green'] * 256) + $RGBcolor['blue']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
520
lib/getid3/getid3/module.graphic.png.php
Normal file
520
lib/getid3/getid3/module.graphic.png.php
Normal file
|
@ -0,0 +1,520 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.graphic.png.php //
|
||||
// module for analyzing PNG Image files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_png extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// shortcut
|
||||
$info['png'] = array();
|
||||
$thisfile_png = &$info['png'];
|
||||
|
||||
$info['fileformat'] = 'png';
|
||||
$info['video']['dataformat'] = 'png';
|
||||
$info['video']['lossless'] = false;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$PNGfiledata = fread($this->getid3->fp, $this->getid3->fread_buffer_size());
|
||||
$offset = 0;
|
||||
|
||||
$PNGidentifier = substr($PNGfiledata, $offset, 8); // $89 $50 $4E $47 $0D $0A $1A $0A
|
||||
$offset += 8;
|
||||
|
||||
if ($PNGidentifier != "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") {
|
||||
$info['error'][] = 'First 8 bytes of file ('.getid3_lib::PrintHexBytes($PNGidentifier).') did not match expected PNG identifier';
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (((ftell($this->getid3->fp) - (strlen($PNGfiledata) - $offset)) < $info['filesize'])) {
|
||||
$chunk['data_length'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4));
|
||||
$offset += 4;
|
||||
while (((strlen($PNGfiledata) - $offset) < ($chunk['data_length'] + 4)) && (ftell($this->getid3->fp) < $info['filesize'])) {
|
||||
$PNGfiledata .= fread($this->getid3->fp, $this->getid3->fread_buffer_size());
|
||||
}
|
||||
$chunk['type_text'] = substr($PNGfiledata, $offset, 4);
|
||||
$offset += 4;
|
||||
$chunk['type_raw'] = getid3_lib::BigEndian2Int($chunk['type_text']);
|
||||
$chunk['data'] = substr($PNGfiledata, $offset, $chunk['data_length']);
|
||||
$offset += $chunk['data_length'];
|
||||
$chunk['crc'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4));
|
||||
$offset += 4;
|
||||
|
||||
$chunk['flags']['ancilliary'] = (bool) ($chunk['type_raw'] & 0x20000000);
|
||||
$chunk['flags']['private'] = (bool) ($chunk['type_raw'] & 0x00200000);
|
||||
$chunk['flags']['reserved'] = (bool) ($chunk['type_raw'] & 0x00002000);
|
||||
$chunk['flags']['safe_to_copy'] = (bool) ($chunk['type_raw'] & 0x00000020);
|
||||
|
||||
// shortcut
|
||||
$thisfile_png[$chunk['type_text']] = array();
|
||||
$thisfile_png_chunk_type_text = &$thisfile_png[$chunk['type_text']];
|
||||
|
||||
switch ($chunk['type_text']) {
|
||||
|
||||
case 'IHDR': // Image Header
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text['width'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4));
|
||||
$thisfile_png_chunk_type_text['height'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4));
|
||||
$thisfile_png_chunk_type_text['raw']['bit_depth'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1));
|
||||
$thisfile_png_chunk_type_text['raw']['color_type'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 9, 1));
|
||||
$thisfile_png_chunk_type_text['raw']['compression_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 10, 1));
|
||||
$thisfile_png_chunk_type_text['raw']['filter_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 11, 1));
|
||||
$thisfile_png_chunk_type_text['raw']['interlace_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 12, 1));
|
||||
|
||||
$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['raw']['compression_method']);
|
||||
$thisfile_png_chunk_type_text['color_type']['palette'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x01);
|
||||
$thisfile_png_chunk_type_text['color_type']['true_color'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x02);
|
||||
$thisfile_png_chunk_type_text['color_type']['alpha'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x04);
|
||||
|
||||
$info['video']['resolution_x'] = $thisfile_png_chunk_type_text['width'];
|
||||
$info['video']['resolution_y'] = $thisfile_png_chunk_type_text['height'];
|
||||
|
||||
$info['video']['bits_per_sample'] = $this->IHDRcalculateBitsPerSample($thisfile_png_chunk_type_text['raw']['color_type'], $thisfile_png_chunk_type_text['raw']['bit_depth']);
|
||||
break;
|
||||
|
||||
|
||||
case 'PLTE': // Palette
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$paletteoffset = 0;
|
||||
for ($i = 0; $i <= 255; $i++) {
|
||||
//$thisfile_png_chunk_type_text['red'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
|
||||
//$thisfile_png_chunk_type_text['green'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
|
||||
//$thisfile_png_chunk_type_text['blue'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
|
||||
$red = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
|
||||
$green = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
|
||||
$blue = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
|
||||
$thisfile_png_chunk_type_text[$i] = (($red << 16) | ($green << 8) | ($blue));
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'tRNS': // Transparency
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
switch ($thisfile_png['IHDR']['raw']['color_type']) {
|
||||
case 0:
|
||||
$thisfile_png_chunk_type_text['transparent_color_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2));
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$thisfile_png_chunk_type_text['transparent_color_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2));
|
||||
$thisfile_png_chunk_type_text['transparent_color_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 2));
|
||||
$thisfile_png_chunk_type_text['transparent_color_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 2));
|
||||
break;
|
||||
|
||||
case 3:
|
||||
for ($i = 0; $i < strlen($chunk['data']); $i++) {
|
||||
$thisfile_png_chunk_type_text['palette_opacity'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $i, 1));
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 6:
|
||||
$info['error'][] = 'Invalid color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type'];
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unhandled color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type'];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'gAMA': // Image Gamma
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text['gamma'] = getid3_lib::BigEndian2Int($chunk['data']) / 100000;
|
||||
break;
|
||||
|
||||
|
||||
case 'cHRM': // Primary Chromaticities
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text['white_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4)) / 100000;
|
||||
$thisfile_png_chunk_type_text['white_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4)) / 100000;
|
||||
$thisfile_png_chunk_type_text['red_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 4)) / 100000;
|
||||
$thisfile_png_chunk_type_text['red_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 12, 4)) / 100000;
|
||||
$thisfile_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 16, 4)) / 100000;
|
||||
$thisfile_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 20, 4)) / 100000;
|
||||
$thisfile_png_chunk_type_text['blue_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 24, 4)) / 100000;
|
||||
$thisfile_png_chunk_type_text['blue_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 28, 4)) / 100000;
|
||||
break;
|
||||
|
||||
|
||||
case 'sRGB': // Standard RGB Color Space
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text['reindering_intent'] = getid3_lib::BigEndian2Int($chunk['data']);
|
||||
$thisfile_png_chunk_type_text['reindering_intent_text'] = $this->PNGsRGBintentLookup($thisfile_png_chunk_type_text['reindering_intent']);
|
||||
break;
|
||||
|
||||
|
||||
case 'iCCP': // Embedded ICC Profile
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($profilename, $compressiondata) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['profile_name'] = $profilename;
|
||||
$thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($compressiondata, 0, 1));
|
||||
$thisfile_png_chunk_type_text['compression_profile'] = substr($compressiondata, 1);
|
||||
|
||||
$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
|
||||
break;
|
||||
|
||||
|
||||
case 'tEXt': // Textual Data
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($keyword, $text) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['keyword'] = $keyword;
|
||||
$thisfile_png_chunk_type_text['text'] = $text;
|
||||
|
||||
$thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
|
||||
break;
|
||||
|
||||
|
||||
case 'zTXt': // Compressed Textual Data
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($keyword, $otherdata) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['keyword'] = $keyword;
|
||||
$thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($otherdata, 0, 1));
|
||||
$thisfile_png_chunk_type_text['compressed_text'] = substr($otherdata, 1);
|
||||
$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
|
||||
switch ($thisfile_png_chunk_type_text['compression_method']) {
|
||||
case 0:
|
||||
$thisfile_png_chunk_type_text['text'] = gzuncompress($thisfile_png_chunk_type_text['compressed_text']);
|
||||
break;
|
||||
|
||||
default:
|
||||
// unknown compression method
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset($thisfile_png_chunk_type_text['text'])) {
|
||||
$thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'iTXt': // International Textual Data
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($keyword, $otherdata) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['keyword'] = $keyword;
|
||||
$thisfile_png_chunk_type_text['compression'] = (bool) getid3_lib::BigEndian2Int(substr($otherdata, 0, 1));
|
||||
$thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($otherdata, 1, 1));
|
||||
$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
|
||||
list($languagetag, $translatedkeyword, $text) = explode("\x00", substr($otherdata, 2), 3);
|
||||
$thisfile_png_chunk_type_text['language_tag'] = $languagetag;
|
||||
$thisfile_png_chunk_type_text['translated_keyword'] = $translatedkeyword;
|
||||
|
||||
if ($thisfile_png_chunk_type_text['compression']) {
|
||||
|
||||
switch ($thisfile_png_chunk_type_text['compression_method']) {
|
||||
case 0:
|
||||
$thisfile_png_chunk_type_text['text'] = gzuncompress($text);
|
||||
break;
|
||||
|
||||
default:
|
||||
// unknown compression method
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$thisfile_png_chunk_type_text['text'] = $text;
|
||||
|
||||
}
|
||||
|
||||
if (isset($thisfile_png_chunk_type_text['text'])) {
|
||||
$thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'bKGD': // Background Color
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
switch ($thisfile_png['IHDR']['raw']['color_type']) {
|
||||
case 0:
|
||||
case 4:
|
||||
$thisfile_png_chunk_type_text['background_gray'] = getid3_lib::BigEndian2Int($chunk['data']);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 6:
|
||||
$thisfile_png_chunk_type_text['background_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
|
||||
$thisfile_png_chunk_type_text['background_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
|
||||
$thisfile_png_chunk_type_text['background_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$thisfile_png_chunk_type_text['background_index'] = getid3_lib::BigEndian2Int($chunk['data']);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'pHYs': // Physical Pixel Dimensions
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text['pixels_per_unit_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4));
|
||||
$thisfile_png_chunk_type_text['pixels_per_unit_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4));
|
||||
$thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1));
|
||||
$thisfile_png_chunk_type_text['unit'] = $this->PNGpHYsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
|
||||
break;
|
||||
|
||||
|
||||
case 'sBIT': // Significant Bits
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
switch ($thisfile_png['IHDR']['raw']['color_type']) {
|
||||
case 0:
|
||||
$thisfile_png_chunk_type_text['significant_bits_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
$thisfile_png_chunk_type_text['significant_bits_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
|
||||
$thisfile_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
|
||||
$thisfile_png_chunk_type_text['significant_bits_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
$thisfile_png_chunk_type_text['significant_bits_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
|
||||
$thisfile_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
|
||||
break;
|
||||
|
||||
case 6:
|
||||
$thisfile_png_chunk_type_text['significant_bits_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
|
||||
$thisfile_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
|
||||
$thisfile_png_chunk_type_text['significant_bits_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1));
|
||||
$thisfile_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 3, 1));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'sPLT': // Suggested Palette
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($palettename, $otherdata) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['palette_name'] = $palettename;
|
||||
$sPLToffset = 0;
|
||||
$thisfile_png_chunk_type_text['sample_depth_bits'] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, 1));
|
||||
$sPLToffset += 1;
|
||||
$thisfile_png_chunk_type_text['sample_depth_bytes'] = $thisfile_png_chunk_type_text['sample_depth_bits'] / 8;
|
||||
$paletteCounter = 0;
|
||||
while ($sPLToffset < strlen($otherdata)) {
|
||||
$thisfile_png_chunk_type_text['red'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
|
||||
$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
|
||||
$thisfile_png_chunk_type_text['green'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
|
||||
$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
|
||||
$thisfile_png_chunk_type_text['blue'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
|
||||
$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
|
||||
$thisfile_png_chunk_type_text['alpha'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
|
||||
$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
|
||||
$thisfile_png_chunk_type_text['frequency'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, 2));
|
||||
$sPLToffset += 2;
|
||||
$paletteCounter++;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'hIST': // Palette Histogram
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$hISTcounter = 0;
|
||||
while ($hISTcounter < strlen($chunk['data'])) {
|
||||
$thisfile_png_chunk_type_text[$hISTcounter] = getid3_lib::BigEndian2Int(substr($chunk['data'], $hISTcounter / 2, 2));
|
||||
$hISTcounter += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'tIME': // Image Last-Modification Time
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text['year'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2));
|
||||
$thisfile_png_chunk_type_text['month'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1));
|
||||
$thisfile_png_chunk_type_text['day'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 3, 1));
|
||||
$thisfile_png_chunk_type_text['hour'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 1));
|
||||
$thisfile_png_chunk_type_text['minute'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 5, 1));
|
||||
$thisfile_png_chunk_type_text['second'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 6, 1));
|
||||
$thisfile_png_chunk_type_text['unix'] = gmmktime($thisfile_png_chunk_type_text['hour'], $thisfile_png_chunk_type_text['minute'], $thisfile_png_chunk_type_text['second'], $thisfile_png_chunk_type_text['month'], $thisfile_png_chunk_type_text['day'], $thisfile_png_chunk_type_text['year']);
|
||||
break;
|
||||
|
||||
|
||||
case 'oFFs': // Image Offset
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text['position_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4), false, true);
|
||||
$thisfile_png_chunk_type_text['position_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4), false, true);
|
||||
$thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1));
|
||||
$thisfile_png_chunk_type_text['unit'] = $this->PNGoFFsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
|
||||
break;
|
||||
|
||||
|
||||
case 'pCAL': // Calibration Of Pixel Values
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($calibrationname, $otherdata) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['calibration_name'] = $calibrationname;
|
||||
$pCALoffset = 0;
|
||||
$thisfile_png_chunk_type_text['original_zero'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 4), false, true);
|
||||
$pCALoffset += 4;
|
||||
$thisfile_png_chunk_type_text['original_max'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 4), false, true);
|
||||
$pCALoffset += 4;
|
||||
$thisfile_png_chunk_type_text['equation_type'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 1));
|
||||
$pCALoffset += 1;
|
||||
$thisfile_png_chunk_type_text['equation_type_text'] = $this->PNGpCALequationTypeLookup($thisfile_png_chunk_type_text['equation_type']);
|
||||
$thisfile_png_chunk_type_text['parameter_count'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 1));
|
||||
$pCALoffset += 1;
|
||||
$thisfile_png_chunk_type_text['parameters'] = explode("\x00", substr($chunk['data'], $pCALoffset));
|
||||
break;
|
||||
|
||||
|
||||
case 'sCAL': // Physical Scale Of Image Subject
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
|
||||
$thisfile_png_chunk_type_text['unit'] = $this->PNGsCALUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
|
||||
list($pixelwidth, $pixelheight) = explode("\x00", substr($chunk['data'], 1));
|
||||
$thisfile_png_chunk_type_text['pixel_width'] = $pixelwidth;
|
||||
$thisfile_png_chunk_type_text['pixel_height'] = $pixelheight;
|
||||
break;
|
||||
|
||||
|
||||
case 'gIFg': // GIF Graphic Control Extension
|
||||
$gIFgCounter = 0;
|
||||
if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) {
|
||||
$gIFgCounter = count($thisfile_png_chunk_type_text);
|
||||
}
|
||||
$thisfile_png_chunk_type_text[$gIFgCounter]['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text[$gIFgCounter]['disposal_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
|
||||
$thisfile_png_chunk_type_text[$gIFgCounter]['user_input_flag'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
|
||||
$thisfile_png_chunk_type_text[$gIFgCounter]['delay_time'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 2));
|
||||
break;
|
||||
|
||||
|
||||
case 'gIFx': // GIF Application Extension
|
||||
$gIFxCounter = 0;
|
||||
if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) {
|
||||
$gIFxCounter = count($thisfile_png_chunk_type_text);
|
||||
}
|
||||
$thisfile_png_chunk_type_text[$gIFxCounter]['header'] = $chunk;
|
||||
$thisfile_png_chunk_type_text[$gIFxCounter]['application_identifier'] = substr($chunk['data'], 0, 8);
|
||||
$thisfile_png_chunk_type_text[$gIFxCounter]['authentication_code'] = substr($chunk['data'], 8, 3);
|
||||
$thisfile_png_chunk_type_text[$gIFxCounter]['application_data'] = substr($chunk['data'], 11);
|
||||
break;
|
||||
|
||||
|
||||
case 'IDAT': // Image Data
|
||||
$idatinformationfieldindex = 0;
|
||||
if (isset($thisfile_png['IDAT']) && is_array($thisfile_png['IDAT'])) {
|
||||
$idatinformationfieldindex = count($thisfile_png['IDAT']);
|
||||
}
|
||||
unset($chunk['data']);
|
||||
$thisfile_png_chunk_type_text[$idatinformationfieldindex]['header'] = $chunk;
|
||||
break;
|
||||
|
||||
|
||||
case 'IEND': // Image Trailer
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
//unset($chunk['data']);
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$info['warning'][] = 'Unhandled chunk type: '.$chunk['type_text'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function PNGsRGBintentLookup($sRGB) {
|
||||
static $PNGsRGBintentLookup = array(
|
||||
0 => 'Perceptual',
|
||||
1 => 'Relative colorimetric',
|
||||
2 => 'Saturation',
|
||||
3 => 'Absolute colorimetric'
|
||||
);
|
||||
return (isset($PNGsRGBintentLookup[$sRGB]) ? $PNGsRGBintentLookup[$sRGB] : 'invalid');
|
||||
}
|
||||
|
||||
function PNGcompressionMethodLookup($compressionmethod) {
|
||||
static $PNGcompressionMethodLookup = array(
|
||||
0 => 'deflate/inflate'
|
||||
);
|
||||
return (isset($PNGcompressionMethodLookup[$compressionmethod]) ? $PNGcompressionMethodLookup[$compressionmethod] : 'invalid');
|
||||
}
|
||||
|
||||
function PNGpHYsUnitLookup($unitid) {
|
||||
static $PNGpHYsUnitLookup = array(
|
||||
0 => 'unknown',
|
||||
1 => 'meter'
|
||||
);
|
||||
return (isset($PNGpHYsUnitLookup[$unitid]) ? $PNGpHYsUnitLookup[$unitid] : 'invalid');
|
||||
}
|
||||
|
||||
function PNGoFFsUnitLookup($unitid) {
|
||||
static $PNGoFFsUnitLookup = array(
|
||||
0 => 'pixel',
|
||||
1 => 'micrometer'
|
||||
);
|
||||
return (isset($PNGoFFsUnitLookup[$unitid]) ? $PNGoFFsUnitLookup[$unitid] : 'invalid');
|
||||
}
|
||||
|
||||
function PNGpCALequationTypeLookup($equationtype) {
|
||||
static $PNGpCALequationTypeLookup = array(
|
||||
0 => 'Linear mapping',
|
||||
1 => 'Base-e exponential mapping',
|
||||
2 => 'Arbitrary-base exponential mapping',
|
||||
3 => 'Hyperbolic mapping'
|
||||
);
|
||||
return (isset($PNGpCALequationTypeLookup[$equationtype]) ? $PNGpCALequationTypeLookup[$equationtype] : 'invalid');
|
||||
}
|
||||
|
||||
function PNGsCALUnitLookup($unitid) {
|
||||
static $PNGsCALUnitLookup = array(
|
||||
0 => 'meter',
|
||||
1 => 'radian'
|
||||
);
|
||||
return (isset($PNGsCALUnitLookup[$unitid]) ? $PNGsCALUnitLookup[$unitid] : 'invalid');
|
||||
}
|
||||
|
||||
function IHDRcalculateBitsPerSample($color_type, $bit_depth) {
|
||||
switch ($color_type) {
|
||||
case 0: // Each pixel is a grayscale sample.
|
||||
return $bit_depth;
|
||||
break;
|
||||
|
||||
case 2: // Each pixel is an R,G,B triple
|
||||
return 3 * $bit_depth;
|
||||
break;
|
||||
|
||||
case 3: // Each pixel is a palette index; a PLTE chunk must appear.
|
||||
return $bit_depth;
|
||||
break;
|
||||
|
||||
case 4: // Each pixel is a grayscale sample, followed by an alpha sample.
|
||||
return 2 * $bit_depth;
|
||||
break;
|
||||
|
||||
case 6: // Each pixel is an R,G,B triple, followed by an alpha sample.
|
||||
return 4 * $bit_depth;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
104
lib/getid3/getid3/module.graphic.svg.php
Normal file
104
lib/getid3/getid3/module.graphic.svg.php
Normal file
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.graphic.svg.php //
|
||||
// module for analyzing SVG Image files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_svg extends getid3_handler
|
||||
{
|
||||
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
|
||||
$SVGheader = fread($this->getid3->fp, 4096);
|
||||
if (preg_match('#\<\?xml([^\>]+)\?\>#i', $SVGheader, $matches)) {
|
||||
$info['svg']['xml']['raw'] = $matches;
|
||||
}
|
||||
if (preg_match('#\<\!DOCTYPE([^\>]+)\>#i', $SVGheader, $matches)) {
|
||||
$info['svg']['doctype']['raw'] = $matches;
|
||||
}
|
||||
if (preg_match('#\<svg([^\>]+)\>#i', $SVGheader, $matches)) {
|
||||
$info['svg']['svg']['raw'] = $matches;
|
||||
}
|
||||
if (isset($info['svg']['svg']['raw'])) {
|
||||
|
||||
$sections_to_fix = array('xml', 'doctype', 'svg');
|
||||
foreach ($sections_to_fix as $section_to_fix) {
|
||||
if (!isset($info['svg'][$section_to_fix])) {
|
||||
continue;
|
||||
}
|
||||
$section_data = array();
|
||||
while (preg_match('/ "([^"]+)"/', $info['svg'][$section_to_fix]['raw'][1], $matches)) {
|
||||
$section_data[] = $matches[1];
|
||||
$info['svg'][$section_to_fix]['raw'][1] = str_replace($matches[0], '', $info['svg'][$section_to_fix]['raw'][1]);
|
||||
}
|
||||
while (preg_match('/([^\s]+)="([^"]+)"/', $info['svg'][$section_to_fix]['raw'][1], $matches)) {
|
||||
$section_data[] = $matches[0];
|
||||
$info['svg'][$section_to_fix]['raw'][1] = str_replace($matches[0], '', $info['svg'][$section_to_fix]['raw'][1]);
|
||||
}
|
||||
$section_data = array_merge($section_data, preg_split('/[\s,]+/', $info['svg'][$section_to_fix]['raw'][1]));
|
||||
foreach ($section_data as $keyvaluepair) {
|
||||
$keyvaluepair = trim($keyvaluepair);
|
||||
if ($keyvaluepair) {
|
||||
$keyvalueexploded = explode('=', $keyvaluepair);
|
||||
$key = (isset($keyvalueexploded[0]) ? $keyvalueexploded[0] : '');
|
||||
$value = (isset($keyvalueexploded[1]) ? $keyvalueexploded[1] : '');
|
||||
$info['svg'][$section_to_fix]['sections'][$key] = trim($value, '"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$info['fileformat'] = 'svg';
|
||||
$info['video']['dataformat'] = 'svg';
|
||||
$info['video']['lossless'] = true;
|
||||
//$info['video']['bits_per_sample'] = 24;
|
||||
$info['video']['pixel_aspect_ratio'] = (float) 1;
|
||||
|
||||
if (!empty($info['svg']['svg']['sections']['width'])) {
|
||||
$info['svg']['width'] = intval($info['svg']['svg']['sections']['width']);
|
||||
}
|
||||
if (!empty($info['svg']['svg']['sections']['height'])) {
|
||||
$info['svg']['height'] = intval($info['svg']['svg']['sections']['height']);
|
||||
}
|
||||
if (!empty($info['svg']['svg']['sections']['version'])) {
|
||||
$info['svg']['version'] = $info['svg']['svg']['sections']['version'];
|
||||
}
|
||||
if (!isset($info['svg']['version']) && isset($info['svg']['doctype']['sections'])) {
|
||||
foreach ($info['svg']['doctype']['sections'] as $key => $value) {
|
||||
if (preg_match('#//W3C//DTD SVG ([0-9\.]+)//#i', $key, $matches)) {
|
||||
$info['svg']['version'] = $matches[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($info['svg']['width'])) {
|
||||
$info['video']['resolution_x'] = $info['svg']['width'];
|
||||
}
|
||||
if (!empty($info['svg']['height'])) {
|
||||
$info['video']['resolution_y'] = $info['svg']['height'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
$info['error'][] = 'Did not find expected <svg> tag';
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
227
lib/getid3/getid3/module.graphic.tiff.php
Normal file
227
lib/getid3/getid3/module.graphic.tiff.php
Normal file
|
@ -0,0 +1,227 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.archive.tiff.php //
|
||||
// module for analyzing TIFF files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_tiff extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$TIFFheader = fread($this->getid3->fp, 4);
|
||||
|
||||
switch (substr($TIFFheader, 0, 2)) {
|
||||
case 'II':
|
||||
$info['tiff']['byte_order'] = 'Intel';
|
||||
break;
|
||||
case 'MM':
|
||||
$info['tiff']['byte_order'] = 'Motorola';
|
||||
break;
|
||||
default:
|
||||
$info['error'][] = 'Invalid TIFF byte order identifier ('.substr($TIFFheader, 0, 2).') at offset '.$info['avdataoffset'];
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
$info['fileformat'] = 'tiff';
|
||||
$info['video']['dataformat'] = 'tiff';
|
||||
$info['video']['lossless'] = true;
|
||||
$info['tiff']['ifd'] = array();
|
||||
$CurrentIFD = array();
|
||||
|
||||
$FieldTypeByteLength = array(1=>1, 2=>1, 3=>2, 4=>4, 5=>8);
|
||||
|
||||
$nextIFDoffset = $this->TIFFendian2Int(fread($this->getid3->fp, 4), $info['tiff']['byte_order']);
|
||||
|
||||
while ($nextIFDoffset > 0) {
|
||||
|
||||
$CurrentIFD['offset'] = $nextIFDoffset;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'] + $nextIFDoffset, SEEK_SET);
|
||||
$CurrentIFD['fieldcount'] = $this->TIFFendian2Int(fread($this->getid3->fp, 2), $info['tiff']['byte_order']);
|
||||
|
||||
for ($i = 0; $i < $CurrentIFD['fieldcount']; $i++) {
|
||||
$CurrentIFD['fields'][$i]['raw']['tag'] = $this->TIFFendian2Int(fread($this->getid3->fp, 2), $info['tiff']['byte_order']);
|
||||
$CurrentIFD['fields'][$i]['raw']['type'] = $this->TIFFendian2Int(fread($this->getid3->fp, 2), $info['tiff']['byte_order']);
|
||||
$CurrentIFD['fields'][$i]['raw']['length'] = $this->TIFFendian2Int(fread($this->getid3->fp, 4), $info['tiff']['byte_order']);
|
||||
$CurrentIFD['fields'][$i]['raw']['offset'] = fread($this->getid3->fp, 4);
|
||||
|
||||
switch ($CurrentIFD['fields'][$i]['raw']['type']) {
|
||||
case 1: // BYTE An 8-bit unsigned integer.
|
||||
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
|
||||
$CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 1), $info['tiff']['byte_order']);
|
||||
} else {
|
||||
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // ASCII 8-bit bytes that store ASCII codes; the last byte must be null.
|
||||
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
|
||||
$CurrentIFD['fields'][$i]['value'] = substr($CurrentIFD['fields'][$i]['raw']['offset'], 3);
|
||||
} else {
|
||||
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // SHORT A 16-bit (2-byte) unsigned integer.
|
||||
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 2) {
|
||||
$CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 2), $info['tiff']['byte_order']);
|
||||
} else {
|
||||
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // LONG A 32-bit (4-byte) unsigned integer.
|
||||
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 1) {
|
||||
$CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
|
||||
} else {
|
||||
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 5: // RATIONAL Two LONG_s: the first represents the numerator of a fraction, the second the denominator.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$info['tiff']['ifd'][] = $CurrentIFD;
|
||||
$CurrentIFD = array();
|
||||
$nextIFDoffset = $this->TIFFendian2Int(fread($this->getid3->fp, 4), $info['tiff']['byte_order']);
|
||||
|
||||
}
|
||||
|
||||
foreach ($info['tiff']['ifd'] as $IFDid => $IFDarray) {
|
||||
foreach ($IFDarray['fields'] as $key => $fieldarray) {
|
||||
switch ($fieldarray['raw']['tag']) {
|
||||
case 256: // ImageWidth
|
||||
case 257: // ImageLength
|
||||
case 258: // BitsPerSample
|
||||
case 259: // Compression
|
||||
if (!isset($fieldarray['value'])) {
|
||||
fseek($this->getid3->fp, $fieldarray['offset'], SEEK_SET);
|
||||
$info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = fread($this->getid3->fp, $fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case 270: // ImageDescription
|
||||
case 271: // Make
|
||||
case 272: // Model
|
||||
case 305: // Software
|
||||
case 306: // DateTime
|
||||
case 315: // Artist
|
||||
case 316: // HostComputer
|
||||
if (isset($fieldarray['value'])) {
|
||||
$info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $fieldarray['value'];
|
||||
} else {
|
||||
fseek($this->getid3->fp, $fieldarray['offset'], SEEK_SET);
|
||||
$info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = fread($this->getid3->fp, $fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch ($fieldarray['raw']['tag']) {
|
||||
case 256: // ImageWidth
|
||||
$info['video']['resolution_x'] = $fieldarray['value'];
|
||||
break;
|
||||
|
||||
case 257: // ImageLength
|
||||
$info['video']['resolution_y'] = $fieldarray['value'];
|
||||
break;
|
||||
|
||||
case 258: // BitsPerSample
|
||||
if (isset($fieldarray['value'])) {
|
||||
$info['video']['bits_per_sample'] = $fieldarray['value'];
|
||||
} else {
|
||||
$info['video']['bits_per_sample'] = 0;
|
||||
for ($i = 0; $i < $fieldarray['raw']['length']; $i++) {
|
||||
$info['video']['bits_per_sample'] += $this->TIFFendian2Int(substr($info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'], $i * $FieldTypeByteLength[$fieldarray['raw']['type']], $FieldTypeByteLength[$fieldarray['raw']['type']]), $info['tiff']['byte_order']);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 259: // Compression
|
||||
$info['video']['codec'] = $this->TIFFcompressionMethod($fieldarray['value']);
|
||||
break;
|
||||
|
||||
case 270: // ImageDescription
|
||||
case 271: // Make
|
||||
case 272: // Model
|
||||
case 305: // Software
|
||||
case 306: // DateTime
|
||||
case 315: // Artist
|
||||
case 316: // HostComputer
|
||||
$TIFFcommentName = $this->TIFFcommentName($fieldarray['raw']['tag']);
|
||||
if (isset($info['tiff']['comments'][$TIFFcommentName])) {
|
||||
$info['tiff']['comments'][$TIFFcommentName][] = $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'];
|
||||
} else {
|
||||
$info['tiff']['comments'][$TIFFcommentName] = array($info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data']);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function TIFFendian2Int($bytestring, $byteorder) {
|
||||
if ($byteorder == 'Intel') {
|
||||
return getid3_lib::LittleEndian2Int($bytestring);
|
||||
} elseif ($byteorder == 'Motorola') {
|
||||
return getid3_lib::BigEndian2Int($bytestring);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function TIFFcompressionMethod($id) {
|
||||
static $TIFFcompressionMethod = array();
|
||||
if (empty($TIFFcompressionMethod)) {
|
||||
$TIFFcompressionMethod = array(
|
||||
1 => 'Uncompressed',
|
||||
2 => 'Huffman',
|
||||
3 => 'Fax - CCITT 3',
|
||||
5 => 'LZW',
|
||||
32773 => 'PackBits',
|
||||
);
|
||||
}
|
||||
return (isset($TIFFcompressionMethod[$id]) ? $TIFFcompressionMethod[$id] : 'unknown/invalid ('.$id.')');
|
||||
}
|
||||
|
||||
function TIFFcommentName($id) {
|
||||
static $TIFFcommentName = array();
|
||||
if (empty($TIFFcommentName)) {
|
||||
$TIFFcommentName = array(
|
||||
270 => 'imagedescription',
|
||||
271 => 'make',
|
||||
272 => 'model',
|
||||
305 => 'software',
|
||||
306 => 'datetime',
|
||||
315 => 'artist',
|
||||
316 => 'hostcomputer',
|
||||
);
|
||||
}
|
||||
return (isset($TIFFcommentName[$id]) ? $TIFFcommentName[$id] : 'unknown/invalid ('.$id.')');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
312
lib/getid3/getid3/module.misc.cue.php
Normal file
312
lib/getid3/getid3/module.misc.cue.php
Normal file
|
@ -0,0 +1,312 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.misc.cue.php //
|
||||
// module for analyzing CUEsheet files //
|
||||
// dependencies: NONE //
|
||||
// //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Module originally written [2009-Mar-25] by //
|
||||
// Nigel Barnes <ngbarnesØhotmail*com> //
|
||||
// Minor reformatting and similar small changes to integrate //
|
||||
// into getID3 by James Heinrich <info@getid3.org> //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* CueSheet parser by Nigel Barnes.
|
||||
*
|
||||
* This is a PHP conversion of CueSharp 0.5 by Wyatt O'Day (wyday.com/cuesharp)
|
||||
*/
|
||||
|
||||
/**
|
||||
* A CueSheet class used to open and parse cuesheets.
|
||||
*
|
||||
*/
|
||||
class getid3_cue extends getid3_handler
|
||||
{
|
||||
var $cuesheet = array();
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'cue';
|
||||
$this->readCueSheetFilename($info['filenamepath']);
|
||||
$info['cue'] = $this->cuesheet;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function readCueSheetFilename($filename)
|
||||
{
|
||||
$filedata = file_get_contents($filename);
|
||||
return $this->readCueSheet($filedata);
|
||||
}
|
||||
/**
|
||||
* Parses a cue sheet file.
|
||||
*
|
||||
* @param string $filename - The filename for the cue sheet to open.
|
||||
*/
|
||||
function readCueSheet(&$filedata)
|
||||
{
|
||||
$cue_lines = array();
|
||||
foreach (explode("\n", str_replace("\r", null, $filedata)) as $line)
|
||||
{
|
||||
if ( (strlen($line) > 0) && ($line[0] != '#'))
|
||||
{
|
||||
$cue_lines[] = trim($line);
|
||||
}
|
||||
}
|
||||
$this->parseCueSheet($cue_lines);
|
||||
|
||||
return $this->cuesheet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the cue sheet array.
|
||||
*
|
||||
* @param array $file - The cuesheet as an array of each line.
|
||||
*/
|
||||
function parseCueSheet($file)
|
||||
{
|
||||
//-1 means still global, all others are track specific
|
||||
$track_on = -1;
|
||||
|
||||
for ($i=0; $i < count($file); $i++)
|
||||
{
|
||||
list($key) = explode(' ', strtolower($file[$i]), 2);
|
||||
switch ($key)
|
||||
{
|
||||
case 'catalog':
|
||||
case 'cdtextfile':
|
||||
case 'isrc':
|
||||
case 'performer':
|
||||
case 'songwriter':
|
||||
case 'title':
|
||||
$this->parseString($file[$i], $track_on);
|
||||
break;
|
||||
case 'file':
|
||||
$currentFile = $this->parseFile($file[$i]);
|
||||
break;
|
||||
case 'flags':
|
||||
$this->parseFlags($file[$i], $track_on);
|
||||
break;
|
||||
case 'index':
|
||||
case 'postgap':
|
||||
case 'pregap':
|
||||
$this->parseIndex($file[$i], $track_on);
|
||||
break;
|
||||
case 'rem':
|
||||
$this->parseComment($file[$i], $track_on);
|
||||
break;
|
||||
case 'track':
|
||||
$track_on++;
|
||||
$this->parseTrack($file[$i], $track_on);
|
||||
if (isset($currentFile)) // if there's a file
|
||||
{
|
||||
$this->cuesheet['tracks'][$track_on]['datafile'] = $currentFile;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//save discarded junk and place string[] with track it was found in
|
||||
$this->parseGarbage($file[$i], $track_on);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the REM command.
|
||||
*
|
||||
* @param string $line - The line in the cue file that contains the TRACK command.
|
||||
* @param integer $track_on - The track currently processing.
|
||||
*/
|
||||
function parseComment($line, $track_on)
|
||||
{
|
||||
$explodedline = explode(' ', $line, 3);
|
||||
$comment_REM = (isset($explodedline[0]) ? $explodedline[0] : '');
|
||||
$comment_type = (isset($explodedline[1]) ? $explodedline[1] : '');
|
||||
$comment_data = (isset($explodedline[2]) ? $explodedline[2] : '');
|
||||
if (($comment_REM == 'REM') && $comment_type) {
|
||||
$comment_type = strtolower($comment_type);
|
||||
$commment_data = trim($comment_data, ' "');
|
||||
if ($track_on != -1) {
|
||||
$this->cuesheet['tracks'][$track_on]['comments'][$comment_type][] = $comment_data;
|
||||
} else {
|
||||
$this->cuesheet['comments'][$comment_type][] = $comment_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the FILE command.
|
||||
*
|
||||
* @param string $line - The line in the cue file that contains the FILE command.
|
||||
* @return array - Array of FILENAME and TYPE of file..
|
||||
*/
|
||||
function parseFile($line)
|
||||
{
|
||||
$line = substr($line, strpos($line, ' ') + 1);
|
||||
$type = strtolower(substr($line, strrpos($line, ' ')));
|
||||
|
||||
//remove type
|
||||
$line = substr($line, 0, strrpos($line, ' ') - 1);
|
||||
|
||||
//if quotes around it, remove them.
|
||||
$line = trim($line, '"');
|
||||
|
||||
return array('filename'=>$line, 'type'=>$type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the FLAG command.
|
||||
*
|
||||
* @param string $line - The line in the cue file that contains the TRACK command.
|
||||
* @param integer $track_on - The track currently processing.
|
||||
*/
|
||||
function parseFlags($line, $track_on)
|
||||
{
|
||||
if ($track_on != -1)
|
||||
{
|
||||
foreach (explode(' ', strtolower($line)) as $type)
|
||||
{
|
||||
switch ($type)
|
||||
{
|
||||
case 'flags':
|
||||
// first entry in this line
|
||||
$this->cuesheet['tracks'][$track_on]['flags'] = array(
|
||||
'4ch' => false,
|
||||
'data' => false,
|
||||
'dcp' => false,
|
||||
'pre' => false,
|
||||
'scms' => false,
|
||||
);
|
||||
break;
|
||||
case 'data':
|
||||
case 'dcp':
|
||||
case '4ch':
|
||||
case 'pre':
|
||||
case 'scms':
|
||||
$this->cuesheet['tracks'][$track_on]['flags'][$type] = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect any unidentified data.
|
||||
*
|
||||
* @param string $line - The line in the cue file that contains the TRACK command.
|
||||
* @param integer $track_on - The track currently processing.
|
||||
*/
|
||||
function parseGarbage($line, $track_on)
|
||||
{
|
||||
if ( strlen($line) > 0 )
|
||||
{
|
||||
if ($track_on == -1)
|
||||
{
|
||||
$this->cuesheet['garbage'][] = $line;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->cuesheet['tracks'][$track_on]['garbage'][] = $line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the INDEX command of a TRACK.
|
||||
*
|
||||
* @param string $line - The line in the cue file that contains the TRACK command.
|
||||
* @param integer $track_on - The track currently processing.
|
||||
*/
|
||||
function parseIndex($line, $track_on)
|
||||
{
|
||||
$type = strtolower(substr($line, 0, strpos($line, ' ')));
|
||||
$line = substr($line, strpos($line, ' ') + 1);
|
||||
|
||||
if ($type == 'index')
|
||||
{
|
||||
//read the index number
|
||||
$number = intval(substr($line, 0, strpos($line, ' ')));
|
||||
$line = substr($line, strpos($line, ' ') + 1);
|
||||
}
|
||||
|
||||
//extract the minutes, seconds, and frames
|
||||
$explodedline = explode(':', $line);
|
||||
$minutes = (isset($explodedline[0]) ? $explodedline[0] : '');
|
||||
$seconds = (isset($explodedline[1]) ? $explodedline[1] : '');
|
||||
$frames = (isset($explodedline[2]) ? $explodedline[2] : '');
|
||||
|
||||
switch ($type) {
|
||||
case 'index':
|
||||
$this->cuesheet['tracks'][$track_on][$type][$number] = array('minutes'=>intval($minutes), 'seconds'=>intval($seconds), 'frames'=>intval($frames));
|
||||
break;
|
||||
case 'pregap':
|
||||
case 'postgap':
|
||||
$this->cuesheet['tracks'][$track_on][$type] = array('minutes'=>intval($minutes), 'seconds'=>intval($seconds), 'frames'=>intval($frames));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function parseString($line, $track_on)
|
||||
{
|
||||
$category = strtolower(substr($line, 0, strpos($line, ' ')));
|
||||
$line = substr($line, strpos($line, ' ') + 1);
|
||||
|
||||
//get rid of the quotes
|
||||
$line = trim($line, '"');
|
||||
|
||||
switch ($category)
|
||||
{
|
||||
case 'catalog':
|
||||
case 'cdtextfile':
|
||||
case 'isrc':
|
||||
case 'performer':
|
||||
case 'songwriter':
|
||||
case 'title':
|
||||
if ($track_on == -1)
|
||||
{
|
||||
$this->cuesheet[$category] = $line;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->cuesheet['tracks'][$track_on][$category] = $line;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the TRACK command.
|
||||
*
|
||||
* @param string $line - The line in the cue file that contains the TRACK command.
|
||||
* @param integer $track_on - The track currently processing.
|
||||
*/
|
||||
function parseTrack($line, $track_on)
|
||||
{
|
||||
$line = substr($line, strpos($line, ' ') + 1);
|
||||
$track = ltrim(substr($line, 0, strpos($line, ' ')), '0');
|
||||
|
||||
//find the data type.
|
||||
$datatype = strtolower(substr($line, strpos($line, ' ') + 1));
|
||||
|
||||
$this->cuesheet['tracks'][$track_on] = array('track_number'=>$track, 'datatype'=>$datatype);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
61
lib/getid3/getid3/module.misc.exe.php
Normal file
61
lib/getid3/getid3/module.misc.exe.php
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.misc.exe.php //
|
||||
// module for analyzing EXE files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_exe extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
|
||||
$EXEheader = fread($this->getid3->fp, 28);
|
||||
|
||||
$magic = 'MZ';
|
||||
if (substr($EXEheader, 0, 2) != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($EXEheader, 0, 2)).'"';
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['fileformat'] = 'exe';
|
||||
$info['exe']['mz']['magic'] = 'MZ';
|
||||
|
||||
$info['exe']['mz']['raw']['last_page_size'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 2, 2));
|
||||
$info['exe']['mz']['raw']['page_count'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 4, 2));
|
||||
$info['exe']['mz']['raw']['relocation_count'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 6, 2));
|
||||
$info['exe']['mz']['raw']['header_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 8, 2));
|
||||
$info['exe']['mz']['raw']['min_memory_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 10, 2));
|
||||
$info['exe']['mz']['raw']['max_memory_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 12, 2));
|
||||
$info['exe']['mz']['raw']['initial_ss'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 14, 2));
|
||||
$info['exe']['mz']['raw']['initial_sp'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 16, 2));
|
||||
$info['exe']['mz']['raw']['checksum'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 18, 2));
|
||||
$info['exe']['mz']['raw']['cs_ip'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 20, 4));
|
||||
$info['exe']['mz']['raw']['relocation_table_offset'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 24, 2));
|
||||
$info['exe']['mz']['raw']['overlay_number'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 26, 2));
|
||||
|
||||
$info['exe']['mz']['byte_size'] = (($info['exe']['mz']['raw']['page_count'] - 1)) * 512 + $info['exe']['mz']['raw']['last_page_size'];
|
||||
$info['exe']['mz']['header_size'] = $info['exe']['mz']['raw']['header_paragraphs'] * 16;
|
||||
$info['exe']['mz']['memory_minimum'] = $info['exe']['mz']['raw']['min_memory_paragraphs'] * 16;
|
||||
$info['exe']['mz']['memory_recommended'] = $info['exe']['mz']['raw']['max_memory_paragraphs'] * 16;
|
||||
|
||||
$info['error'][] = 'EXE parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
389
lib/getid3/getid3/module.misc.iso.php
Normal file
389
lib/getid3/getid3/module.misc.iso.php
Normal file
|
@ -0,0 +1,389 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.misc.iso.php //
|
||||
// module for analyzing ISO files //
|
||||
// dependencies: NONE //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_iso extends getid3_handler
|
||||
{
|
||||
|
||||
function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'iso';
|
||||
|
||||
for ($i = 16; $i <= 19; $i++) {
|
||||
fseek($this->getid3->fp, 2048 * $i, SEEK_SET);
|
||||
$ISOheader = fread($this->getid3->fp, 2048);
|
||||
if (substr($ISOheader, 1, 5) == 'CD001') {
|
||||
switch (ord($ISOheader{0})) {
|
||||
case 1:
|
||||
$info['iso']['primary_volume_descriptor']['offset'] = 2048 * $i;
|
||||
$this->ParsePrimaryVolumeDescriptor($ISOheader);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$info['iso']['supplementary_volume_descriptor']['offset'] = 2048 * $i;
|
||||
$this->ParseSupplementaryVolumeDescriptor($ISOheader);
|
||||
break;
|
||||
|
||||
default:
|
||||
// skip
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->ParsePathTable();
|
||||
|
||||
$info['iso']['files'] = array();
|
||||
foreach ($info['iso']['path_table']['directories'] as $directorynum => $directorydata) {
|
||||
$info['iso']['directories'][$directorynum] = $this->ParseDirectoryRecord($directorydata);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function ParsePrimaryVolumeDescriptor(&$ISOheader) {
|
||||
// ISO integer values are stored *BOTH* Little-Endian AND Big-Endian format!!
|
||||
// ie 12345 == 0x3039 is stored as $39 $30 $30 $39 in a 4-byte field
|
||||
|
||||
// shortcuts
|
||||
$info = &$this->getid3->info;
|
||||
$info['iso']['primary_volume_descriptor']['raw'] = array();
|
||||
$thisfile_iso_primaryVD = &$info['iso']['primary_volume_descriptor'];
|
||||
$thisfile_iso_primaryVD_raw = &$thisfile_iso_primaryVD['raw'];
|
||||
|
||||
$thisfile_iso_primaryVD_raw['volume_descriptor_type'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 0, 1));
|
||||
$thisfile_iso_primaryVD_raw['standard_identifier'] = substr($ISOheader, 1, 5);
|
||||
if ($thisfile_iso_primaryVD_raw['standard_identifier'] != 'CD001') {
|
||||
$info['error'][] = 'Expected "CD001" at offset ('.($thisfile_iso_primaryVD['offset'] + 1).'), found "'.$thisfile_iso_primaryVD_raw['standard_identifier'].'" instead';
|
||||
unset($info['fileformat']);
|
||||
unset($info['iso']);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
$thisfile_iso_primaryVD_raw['volume_descriptor_version'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 6, 1));
|
||||
//$thisfile_iso_primaryVD_raw['unused_1'] = substr($ISOheader, 7, 1);
|
||||
$thisfile_iso_primaryVD_raw['system_identifier'] = substr($ISOheader, 8, 32);
|
||||
$thisfile_iso_primaryVD_raw['volume_identifier'] = substr($ISOheader, 40, 32);
|
||||
//$thisfile_iso_primaryVD_raw['unused_2'] = substr($ISOheader, 72, 8);
|
||||
$thisfile_iso_primaryVD_raw['volume_space_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 80, 4));
|
||||
//$thisfile_iso_primaryVD_raw['unused_3'] = substr($ISOheader, 88, 32);
|
||||
$thisfile_iso_primaryVD_raw['volume_set_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 120, 2));
|
||||
$thisfile_iso_primaryVD_raw['volume_sequence_number'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 124, 2));
|
||||
$thisfile_iso_primaryVD_raw['logical_block_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 128, 2));
|
||||
$thisfile_iso_primaryVD_raw['path_table_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 132, 4));
|
||||
$thisfile_iso_primaryVD_raw['path_table_l_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 140, 2));
|
||||
$thisfile_iso_primaryVD_raw['path_table_l_opt_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 144, 2));
|
||||
$thisfile_iso_primaryVD_raw['path_table_m_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 148, 2));
|
||||
$thisfile_iso_primaryVD_raw['path_table_m_opt_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 152, 2));
|
||||
$thisfile_iso_primaryVD_raw['root_directory_record'] = substr($ISOheader, 156, 34);
|
||||
$thisfile_iso_primaryVD_raw['volume_set_identifier'] = substr($ISOheader, 190, 128);
|
||||
$thisfile_iso_primaryVD_raw['publisher_identifier'] = substr($ISOheader, 318, 128);
|
||||
$thisfile_iso_primaryVD_raw['data_preparer_identifier'] = substr($ISOheader, 446, 128);
|
||||
$thisfile_iso_primaryVD_raw['application_identifier'] = substr($ISOheader, 574, 128);
|
||||
$thisfile_iso_primaryVD_raw['copyright_file_identifier'] = substr($ISOheader, 702, 37);
|
||||
$thisfile_iso_primaryVD_raw['abstract_file_identifier'] = substr($ISOheader, 739, 37);
|
||||
$thisfile_iso_primaryVD_raw['bibliographic_file_identifier'] = substr($ISOheader, 776, 37);
|
||||
$thisfile_iso_primaryVD_raw['volume_creation_date_time'] = substr($ISOheader, 813, 17);
|
||||
$thisfile_iso_primaryVD_raw['volume_modification_date_time'] = substr($ISOheader, 830, 17);
|
||||
$thisfile_iso_primaryVD_raw['volume_expiration_date_time'] = substr($ISOheader, 847, 17);
|
||||
$thisfile_iso_primaryVD_raw['volume_effective_date_time'] = substr($ISOheader, 864, 17);
|
||||
$thisfile_iso_primaryVD_raw['file_structure_version'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 881, 1));
|
||||
//$thisfile_iso_primaryVD_raw['unused_4'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 882, 1));
|
||||
$thisfile_iso_primaryVD_raw['application_data'] = substr($ISOheader, 883, 512);
|
||||
//$thisfile_iso_primaryVD_raw['unused_5'] = substr($ISOheader, 1395, 653);
|
||||
|
||||
$thisfile_iso_primaryVD['system_identifier'] = trim($thisfile_iso_primaryVD_raw['system_identifier']);
|
||||
$thisfile_iso_primaryVD['volume_identifier'] = trim($thisfile_iso_primaryVD_raw['volume_identifier']);
|
||||
$thisfile_iso_primaryVD['volume_set_identifier'] = trim($thisfile_iso_primaryVD_raw['volume_set_identifier']);
|
||||
$thisfile_iso_primaryVD['publisher_identifier'] = trim($thisfile_iso_primaryVD_raw['publisher_identifier']);
|
||||
$thisfile_iso_primaryVD['data_preparer_identifier'] = trim($thisfile_iso_primaryVD_raw['data_preparer_identifier']);
|
||||
$thisfile_iso_primaryVD['application_identifier'] = trim($thisfile_iso_primaryVD_raw['application_identifier']);
|
||||
$thisfile_iso_primaryVD['copyright_file_identifier'] = trim($thisfile_iso_primaryVD_raw['copyright_file_identifier']);
|
||||
$thisfile_iso_primaryVD['abstract_file_identifier'] = trim($thisfile_iso_primaryVD_raw['abstract_file_identifier']);
|
||||
$thisfile_iso_primaryVD['bibliographic_file_identifier'] = trim($thisfile_iso_primaryVD_raw['bibliographic_file_identifier']);
|
||||
$thisfile_iso_primaryVD['volume_creation_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_primaryVD_raw['volume_creation_date_time']);
|
||||
$thisfile_iso_primaryVD['volume_modification_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_primaryVD_raw['volume_modification_date_time']);
|
||||
$thisfile_iso_primaryVD['volume_expiration_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_primaryVD_raw['volume_expiration_date_time']);
|
||||
$thisfile_iso_primaryVD['volume_effective_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_primaryVD_raw['volume_effective_date_time']);
|
||||
|
||||
if (($thisfile_iso_primaryVD_raw['volume_space_size'] * 2048) > $info['filesize']) {
|
||||
$info['error'][] = 'Volume Space Size ('.($thisfile_iso_primaryVD_raw['volume_space_size'] * 2048).' bytes) is larger than the file size ('.$info['filesize'].' bytes) (truncated file?)';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function ParseSupplementaryVolumeDescriptor(&$ISOheader) {
|
||||
// ISO integer values are stored Both-Endian format!!
|
||||
// ie 12345 == 0x3039 is stored as $39 $30 $30 $39 in a 4-byte field
|
||||
|
||||
// shortcuts
|
||||
$info = &$this->getid3->info;
|
||||
$info['iso']['supplementary_volume_descriptor']['raw'] = array();
|
||||
$thisfile_iso_supplementaryVD = &$info['iso']['supplementary_volume_descriptor'];
|
||||
$thisfile_iso_supplementaryVD_raw = &$thisfile_iso_supplementaryVD['raw'];
|
||||
|
||||
$thisfile_iso_supplementaryVD_raw['volume_descriptor_type'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 0, 1));
|
||||
$thisfile_iso_supplementaryVD_raw['standard_identifier'] = substr($ISOheader, 1, 5);
|
||||
if ($thisfile_iso_supplementaryVD_raw['standard_identifier'] != 'CD001') {
|
||||
$info['error'][] = 'Expected "CD001" at offset ('.($thisfile_iso_supplementaryVD['offset'] + 1).'), found "'.$thisfile_iso_supplementaryVD_raw['standard_identifier'].'" instead';
|
||||
unset($info['fileformat']);
|
||||
unset($info['iso']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$thisfile_iso_supplementaryVD_raw['volume_descriptor_version'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 6, 1));
|
||||
//$thisfile_iso_supplementaryVD_raw['unused_1'] = substr($ISOheader, 7, 1);
|
||||
$thisfile_iso_supplementaryVD_raw['system_identifier'] = substr($ISOheader, 8, 32);
|
||||
$thisfile_iso_supplementaryVD_raw['volume_identifier'] = substr($ISOheader, 40, 32);
|
||||
//$thisfile_iso_supplementaryVD_raw['unused_2'] = substr($ISOheader, 72, 8);
|
||||
$thisfile_iso_supplementaryVD_raw['volume_space_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 80, 4));
|
||||
if ($thisfile_iso_supplementaryVD_raw['volume_space_size'] == 0) {
|
||||
// Supplementary Volume Descriptor not used
|
||||
//unset($thisfile_iso_supplementaryVD);
|
||||
//return false;
|
||||
}
|
||||
|
||||
//$thisfile_iso_supplementaryVD_raw['unused_3'] = substr($ISOheader, 88, 32);
|
||||
$thisfile_iso_supplementaryVD_raw['volume_set_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 120, 2));
|
||||
$thisfile_iso_supplementaryVD_raw['volume_sequence_number'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 124, 2));
|
||||
$thisfile_iso_supplementaryVD_raw['logical_block_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 128, 2));
|
||||
$thisfile_iso_supplementaryVD_raw['path_table_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 132, 4));
|
||||
$thisfile_iso_supplementaryVD_raw['path_table_l_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 140, 2));
|
||||
$thisfile_iso_supplementaryVD_raw['path_table_l_opt_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 144, 2));
|
||||
$thisfile_iso_supplementaryVD_raw['path_table_m_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 148, 2));
|
||||
$thisfile_iso_supplementaryVD_raw['path_table_m_opt_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 152, 2));
|
||||
$thisfile_iso_supplementaryVD_raw['root_directory_record'] = substr($ISOheader, 156, 34);
|
||||
$thisfile_iso_supplementaryVD_raw['volume_set_identifier'] = substr($ISOheader, 190, 128);
|
||||
$thisfile_iso_supplementaryVD_raw['publisher_identifier'] = substr($ISOheader, 318, 128);
|
||||
$thisfile_iso_supplementaryVD_raw['data_preparer_identifier'] = substr($ISOheader, 446, 128);
|
||||
$thisfile_iso_supplementaryVD_raw['application_identifier'] = substr($ISOheader, 574, 128);
|
||||
$thisfile_iso_supplementaryVD_raw['copyright_file_identifier'] = substr($ISOheader, 702, 37);
|
||||
$thisfile_iso_supplementaryVD_raw['abstract_file_identifier'] = substr($ISOheader, 739, 37);
|
||||
$thisfile_iso_supplementaryVD_raw['bibliographic_file_identifier'] = substr($ISOheader, 776, 37);
|
||||
$thisfile_iso_supplementaryVD_raw['volume_creation_date_time'] = substr($ISOheader, 813, 17);
|
||||
$thisfile_iso_supplementaryVD_raw['volume_modification_date_time'] = substr($ISOheader, 830, 17);
|
||||
$thisfile_iso_supplementaryVD_raw['volume_expiration_date_time'] = substr($ISOheader, 847, 17);
|
||||
$thisfile_iso_supplementaryVD_raw['volume_effective_date_time'] = substr($ISOheader, 864, 17);
|
||||
$thisfile_iso_supplementaryVD_raw['file_structure_version'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 881, 1));
|
||||
//$thisfile_iso_supplementaryVD_raw['unused_4'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 882, 1));
|
||||
$thisfile_iso_supplementaryVD_raw['application_data'] = substr($ISOheader, 883, 512);
|
||||
//$thisfile_iso_supplementaryVD_raw['unused_5'] = substr($ISOheader, 1395, 653);
|
||||
|
||||
$thisfile_iso_supplementaryVD['system_identifier'] = trim($thisfile_iso_supplementaryVD_raw['system_identifier']);
|
||||
$thisfile_iso_supplementaryVD['volume_identifier'] = trim($thisfile_iso_supplementaryVD_raw['volume_identifier']);
|
||||
$thisfile_iso_supplementaryVD['volume_set_identifier'] = trim($thisfile_iso_supplementaryVD_raw['volume_set_identifier']);
|
||||
$thisfile_iso_supplementaryVD['publisher_identifier'] = trim($thisfile_iso_supplementaryVD_raw['publisher_identifier']);
|
||||
$thisfile_iso_supplementaryVD['data_preparer_identifier'] = trim($thisfile_iso_supplementaryVD_raw['data_preparer_identifier']);
|
||||
$thisfile_iso_supplementaryVD['application_identifier'] = trim($thisfile_iso_supplementaryVD_raw['application_identifier']);
|
||||
$thisfile_iso_supplementaryVD['copyright_file_identifier'] = trim($thisfile_iso_supplementaryVD_raw['copyright_file_identifier']);
|
||||
$thisfile_iso_supplementaryVD['abstract_file_identifier'] = trim($thisfile_iso_supplementaryVD_raw['abstract_file_identifier']);
|
||||
$thisfile_iso_supplementaryVD['bibliographic_file_identifier'] = trim($thisfile_iso_supplementaryVD_raw['bibliographic_file_identifier']);
|
||||
$thisfile_iso_supplementaryVD['volume_creation_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_supplementaryVD_raw['volume_creation_date_time']);
|
||||
$thisfile_iso_supplementaryVD['volume_modification_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_supplementaryVD_raw['volume_modification_date_time']);
|
||||
$thisfile_iso_supplementaryVD['volume_expiration_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_supplementaryVD_raw['volume_expiration_date_time']);
|
||||
$thisfile_iso_supplementaryVD['volume_effective_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_supplementaryVD_raw['volume_effective_date_time']);
|
||||
|
||||
if (($thisfile_iso_supplementaryVD_raw['volume_space_size'] * $thisfile_iso_supplementaryVD_raw['logical_block_size']) > $info['filesize']) {
|
||||
$info['error'][] = 'Volume Space Size ('.($thisfile_iso_supplementaryVD_raw['volume_space_size'] * $thisfile_iso_supplementaryVD_raw['logical_block_size']).' bytes) is larger than the file size ('.$info['filesize'].' bytes) (truncated file?)';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function ParsePathTable() {
|
||||
$info = &$this->getid3->info;
|
||||
if (!isset($info['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location']) && !isset($info['iso']['primary_volume_descriptor']['raw']['path_table_l_location'])) {
|
||||
return false;
|
||||
}
|
||||
if (isset($info['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location'])) {
|
||||
$PathTableLocation = $info['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location'];
|
||||
$PathTableSize = $info['iso']['supplementary_volume_descriptor']['raw']['path_table_size'];
|
||||
$TextEncoding = 'UTF-16BE'; // Big-Endian Unicode
|
||||
} else {
|
||||
$PathTableLocation = $info['iso']['primary_volume_descriptor']['raw']['path_table_l_location'];
|
||||
$PathTableSize = $info['iso']['primary_volume_descriptor']['raw']['path_table_size'];
|
||||
$TextEncoding = 'ISO-8859-1'; // Latin-1
|
||||
}
|
||||
|
||||
if (($PathTableLocation * 2048) > $info['filesize']) {
|
||||
$info['error'][] = 'Path Table Location specifies an offset ('.($PathTableLocation * 2048).') beyond the end-of-file ('.$info['filesize'].')';
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['iso']['path_table']['offset'] = $PathTableLocation * 2048;
|
||||
fseek($this->getid3->fp, $info['iso']['path_table']['offset'], SEEK_SET);
|
||||
$info['iso']['path_table']['raw'] = fread($this->getid3->fp, $PathTableSize);
|
||||
|
||||
$offset = 0;
|
||||
$pathcounter = 1;
|
||||
while ($offset < $PathTableSize) {
|
||||
// shortcut
|
||||
$info['iso']['path_table']['directories'][$pathcounter] = array();
|
||||
$thisfile_iso_pathtable_directories_current = &$info['iso']['path_table']['directories'][$pathcounter];
|
||||
|
||||
$thisfile_iso_pathtable_directories_current['length'] = getid3_lib::LittleEndian2Int(substr($info['iso']['path_table']['raw'], $offset, 1));
|
||||
$offset += 1;
|
||||
$thisfile_iso_pathtable_directories_current['extended_length'] = getid3_lib::LittleEndian2Int(substr($info['iso']['path_table']['raw'], $offset, 1));
|
||||
$offset += 1;
|
||||
$thisfile_iso_pathtable_directories_current['location_logical'] = getid3_lib::LittleEndian2Int(substr($info['iso']['path_table']['raw'], $offset, 4));
|
||||
$offset += 4;
|
||||
$thisfile_iso_pathtable_directories_current['parent_directory'] = getid3_lib::LittleEndian2Int(substr($info['iso']['path_table']['raw'], $offset, 2));
|
||||
$offset += 2;
|
||||
$thisfile_iso_pathtable_directories_current['name'] = substr($info['iso']['path_table']['raw'], $offset, $thisfile_iso_pathtable_directories_current['length']);
|
||||
$offset += $thisfile_iso_pathtable_directories_current['length'] + ($thisfile_iso_pathtable_directories_current['length'] % 2);
|
||||
|
||||
$thisfile_iso_pathtable_directories_current['name_ascii'] = getid3_lib::iconv_fallback($TextEncoding, $info['encoding'], $thisfile_iso_pathtable_directories_current['name']);
|
||||
|
||||
$thisfile_iso_pathtable_directories_current['location_bytes'] = $thisfile_iso_pathtable_directories_current['location_logical'] * 2048;
|
||||
if ($pathcounter == 1) {
|
||||
$thisfile_iso_pathtable_directories_current['full_path'] = '/';
|
||||
} else {
|
||||
$thisfile_iso_pathtable_directories_current['full_path'] = $info['iso']['path_table']['directories'][$thisfile_iso_pathtable_directories_current['parent_directory']]['full_path'].$thisfile_iso_pathtable_directories_current['name_ascii'].'/';
|
||||
}
|
||||
$FullPathArray[] = $thisfile_iso_pathtable_directories_current['full_path'];
|
||||
|
||||
$pathcounter++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function ParseDirectoryRecord($directorydata) {
|
||||
$info = &$this->getid3->info;
|
||||
if (isset($info['iso']['supplementary_volume_descriptor'])) {
|
||||
$TextEncoding = 'UTF-16BE'; // Big-Endian Unicode
|
||||
} else {
|
||||
$TextEncoding = 'ISO-8859-1'; // Latin-1
|
||||
}
|
||||
|
||||
fseek($this->getid3->fp, $directorydata['location_bytes'], SEEK_SET);
|
||||
$DirectoryRecordData = fread($this->getid3->fp, 1);
|
||||
|
||||
while (ord($DirectoryRecordData{0}) > 33) {
|
||||
|
||||
$DirectoryRecordData .= fread($this->getid3->fp, ord($DirectoryRecordData{0}) - 1);
|
||||
|
||||
$ThisDirectoryRecord['raw']['length'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 0, 1));
|
||||
$ThisDirectoryRecord['raw']['extended_attribute_length'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 1, 1));
|
||||
$ThisDirectoryRecord['raw']['offset_logical'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 2, 4));
|
||||
$ThisDirectoryRecord['raw']['filesize'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 10, 4));
|
||||
$ThisDirectoryRecord['raw']['recording_date_time'] = substr($DirectoryRecordData, 18, 7);
|
||||
$ThisDirectoryRecord['raw']['file_flags'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 25, 1));
|
||||
$ThisDirectoryRecord['raw']['file_unit_size'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 26, 1));
|
||||
$ThisDirectoryRecord['raw']['interleave_gap_size'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 27, 1));
|
||||
$ThisDirectoryRecord['raw']['volume_sequence_number'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 28, 2));
|
||||
$ThisDirectoryRecord['raw']['file_identifier_length'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 32, 1));
|
||||
$ThisDirectoryRecord['raw']['file_identifier'] = substr($DirectoryRecordData, 33, $ThisDirectoryRecord['raw']['file_identifier_length']);
|
||||
|
||||
$ThisDirectoryRecord['file_identifier_ascii'] = getid3_lib::iconv_fallback($TextEncoding, $info['encoding'], $ThisDirectoryRecord['raw']['file_identifier']);
|
||||
|
||||
$ThisDirectoryRecord['filesize'] = $ThisDirectoryRecord['raw']['filesize'];
|
||||
$ThisDirectoryRecord['offset_bytes'] = $ThisDirectoryRecord['raw']['offset_logical'] * 2048;
|
||||
$ThisDirectoryRecord['file_flags']['hidden'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x01);
|
||||
$ThisDirectoryRecord['file_flags']['directory'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x02);
|
||||
$ThisDirectoryRecord['file_flags']['associated'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x04);
|
||||
$ThisDirectoryRecord['file_flags']['extended'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x08);
|
||||
$ThisDirectoryRecord['file_flags']['permissions'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x10);
|
||||
$ThisDirectoryRecord['file_flags']['multiple'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x80);
|
||||
$ThisDirectoryRecord['recording_timestamp'] = $this->ISOtime2UNIXtime($ThisDirectoryRecord['raw']['recording_date_time']);
|
||||
|
||||
if ($ThisDirectoryRecord['file_flags']['directory']) {
|
||||
$ThisDirectoryRecord['filename'] = $directorydata['full_path'];
|
||||
} else {
|
||||
$ThisDirectoryRecord['filename'] = $directorydata['full_path'].$this->ISOstripFilenameVersion($ThisDirectoryRecord['file_identifier_ascii']);
|
||||
$info['iso']['files'] = getid3_lib::array_merge_clobber($info['iso']['files'], getid3_lib::CreateDeepArray($ThisDirectoryRecord['filename'], '/', $ThisDirectoryRecord['filesize']));
|
||||
}
|
||||
|
||||
$DirectoryRecord[] = $ThisDirectoryRecord;
|
||||
$DirectoryRecordData = fread($this->getid3->fp, 1);
|
||||
}
|
||||
|
||||
return $DirectoryRecord;
|
||||
}
|
||||
|
||||
function ISOstripFilenameVersion($ISOfilename) {
|
||||
// convert 'filename.ext;1' to 'filename.ext'
|
||||
if (!strstr($ISOfilename, ';')) {
|
||||
return $ISOfilename;
|
||||
} else {
|
||||
return substr($ISOfilename, 0, strpos($ISOfilename, ';'));
|
||||
}
|
||||
}
|
||||
|
||||
function ISOtimeText2UNIXtime($ISOtime) {
|
||||
|
||||
$UNIXyear = (int) substr($ISOtime, 0, 4);
|
||||
$UNIXmonth = (int) substr($ISOtime, 4, 2);
|
||||
$UNIXday = (int) substr($ISOtime, 6, 2);
|
||||
$UNIXhour = (int) substr($ISOtime, 8, 2);
|
||||
$UNIXminute = (int) substr($ISOtime, 10, 2);
|
||||
$UNIXsecond = (int) substr($ISOtime, 12, 2);
|
||||
|
||||
if (!$UNIXyear) {
|
||||
return false;
|
||||
}
|
||||
return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
|
||||
}
|
||||
|
||||
function ISOtime2UNIXtime($ISOtime) {
|
||||
// Represented by seven bytes:
|
||||
// 1: Number of years since 1900
|
||||
// 2: Month of the year from 1 to 12
|
||||
// 3: Day of the Month from 1 to 31
|
||||
// 4: Hour of the day from 0 to 23
|
||||
// 5: Minute of the hour from 0 to 59
|
||||
// 6: second of the minute from 0 to 59
|
||||
// 7: Offset from Greenwich Mean Time in number of 15 minute intervals from -48 (West) to +52 (East)
|
||||
|
||||
$UNIXyear = ord($ISOtime{0}) + 1900;
|
||||
$UNIXmonth = ord($ISOtime{1});
|
||||
$UNIXday = ord($ISOtime{2});
|
||||
$UNIXhour = ord($ISOtime{3});
|
||||
$UNIXminute = ord($ISOtime{4});
|
||||
$UNIXsecond = ord($ISOtime{5});
|
||||
$GMToffset = $this->TwosCompliment2Decimal(ord($ISOtime{5}));
|
||||
|
||||
return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
|
||||
}
|
||||
|
||||
function TwosCompliment2Decimal($BinaryValue) {
|
||||
// http://sandbox.mc.edu/~bennet/cs110/tc/tctod.html
|
||||
// First check if the number is negative or positive by looking at the sign bit.
|
||||
// If it is positive, simply convert it to decimal.
|
||||
// If it is negative, make it positive by inverting the bits and adding one.
|
||||
// Then, convert the result to decimal.
|
||||
// The negative of this number is the value of the original binary.
|
||||
|
||||
if ($BinaryValue & 0x80) {
|
||||
|
||||
// negative number
|
||||
return (0 - ((~$BinaryValue & 0xFF) + 1));
|
||||
} else {
|
||||
// positive number
|
||||
return $BinaryValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue