mirror of
https://github.com/Poniverse/Pony.fm.git
synced 2024-11-22 04:58:01 +01:00
commit
b89a0344d4
97 changed files with 40204 additions and 38098 deletions
|
@ -43,6 +43,8 @@ class UploadTrackCommand extends CommandBase
|
|||
private $_version;
|
||||
private $_isReplacingTrack;
|
||||
|
||||
public $_file;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
|
@ -94,7 +96,16 @@ class UploadTrackCommand extends CommandBase
|
|||
*/
|
||||
public function execute()
|
||||
{
|
||||
$trackFile = null;
|
||||
$source = 'direct_upload';
|
||||
|
||||
if ($this->_file !== null) {
|
||||
$trackFile = $this->_file;
|
||||
$source = 'ponify';
|
||||
} else {
|
||||
$trackFile = Request::file('track', null);
|
||||
}
|
||||
|
||||
if (!$this->_isReplacingTrack) {
|
||||
$coverFile = Request::file('cover', null);
|
||||
}
|
||||
|
@ -114,7 +125,7 @@ class UploadTrackCommand extends CommandBase
|
|||
$this->_track->user_id = $this->_artist->id;
|
||||
// The title set here is a placeholder; it'll be replaced by ParseTrackTagsCommand
|
||||
// if the file contains a title tag.
|
||||
$this->_track->title = Request::get('title', pathinfo($trackFile->getClientOriginalName(), PATHINFO_FILENAME));
|
||||
$this->_track->title = mb_strimwidth(Request::get('title', pathinfo($trackFile->getClientOriginalName(), PATHINFO_FILENAME)), 0, 100, '...');
|
||||
// The duration/version of the track cannot be changed until the encoding is successful
|
||||
$this->_track->duration = $audio->getDuration();
|
||||
$this->_track->current_version = $this->_version;
|
||||
|
@ -129,6 +140,7 @@ class UploadTrackCommand extends CommandBase
|
|||
if (!is_dir(Config::get('ponyfm.files_directory').'/queued-tracks')) {
|
||||
mkdir(Config::get('ponyfm.files_directory').'/queued-tracks', 0755, true);
|
||||
}
|
||||
|
||||
$trackFile = $trackFile->move(Config::get('ponyfm.files_directory') . '/queued-tracks', $this->_track->id . 'v' . $this->_version);
|
||||
|
||||
$input = Request::all();
|
||||
|
@ -183,7 +195,7 @@ class UploadTrackCommand extends CommandBase
|
|||
$this->_track->metadata = json_decode(Request::get('metadata', null));
|
||||
}
|
||||
$autoPublish = (bool)($input['auto_publish'] ?? $this->_autoPublishByDefault);
|
||||
$this->_track->source = $this->_customTrackSource ?? 'direct_upload';
|
||||
$this->_track->source = $this->_customTrackSource ?? $source;
|
||||
$this->_track->save();
|
||||
|
||||
if (!$this->_isReplacingTrack) {
|
||||
|
|
778
app/Console/Commands/ImportPonify.php
Normal file
778
app/Console/Commands/ImportPonify.php
Normal file
|
@ -0,0 +1,778 @@
|
|||
<?php
|
||||
|
||||
namespace Poniverse\Ponyfm\Console\Commands;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use DB;
|
||||
use File;
|
||||
use Input;
|
||||
use getID3;
|
||||
use Poniverse\Ponyfm\Models\Image;
|
||||
use Poniverse\Ponyfm\Models\Track;
|
||||
use Poniverse\Ponyfm\Models\User;
|
||||
use Poniverse\Ponyfm\Models\Genre;
|
||||
use Poniverse\Ponyfm\Models\Album;
|
||||
use Poniverse\Ponyfm\Commands\UploadTrackCommand;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
|
||||
class ImportPonify extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'ponify:import
|
||||
{--startAt=1 : Track to start importing from. Useful for resuming an interrupted import.}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Imports the Ponify archive';
|
||||
|
||||
/**
|
||||
* File extensions to ignore when importing the archive.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $allowedExtensions = ['mp3', 'aif', 'aiff', 'wav', 'flac', 'm4a', 'ogg'];
|
||||
/**
|
||||
* Used to stop the import process when a SIGINT is received.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $isInterrupted = false;
|
||||
/**
|
||||
* A counter for the number of processed tracks.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $currentFile;
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function handleInterrupt($signo)
|
||||
{
|
||||
$this->error('Import aborted!');
|
||||
$this->error('Resume it from here using: --startAt=' . $this->currentFile);
|
||||
$this->isInterrupted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// Most of this is the same as the old ImportMLPMA.php command with a few tweaks
|
||||
// to use the new upload system and the newer version of Laravel
|
||||
|
||||
pcntl_signal(SIGINT, [$this, 'handleInterrupt']);
|
||||
|
||||
$ponifyPath = Config::get('ponyfm.ponify_directory');
|
||||
$tmpPath = Config::get('ponyfm.files_directory').'/tmp';
|
||||
|
||||
if (!File::exists($tmpPath)) {
|
||||
File::makeDirectory($tmpPath);
|
||||
}
|
||||
|
||||
$UNKNOWN_GENRE = Genre::firstOrCreate([
|
||||
'name' => 'Unknown',
|
||||
'slug' => 'unknown'
|
||||
]);
|
||||
|
||||
//==========================================================================================================
|
||||
// Get the list of files and artists
|
||||
//==========================================================================================================
|
||||
$this->comment('Enumerating Ponify files...');
|
||||
$files = File::allFiles($ponifyPath);
|
||||
$this->info(sizeof($files) . ' files found!');
|
||||
|
||||
$this->comment('Enumerating artists...');
|
||||
$artists = File::directories($ponifyPath);
|
||||
$this->info(sizeof($artists) . ' artists found!');
|
||||
|
||||
$this->comment('Importing tracks...');
|
||||
|
||||
$totalFiles = sizeof($files);
|
||||
|
||||
$fileToStartAt = (int)$this->option('startAt') - 1;
|
||||
$this->comment("Skipping $fileToStartAt files..." . PHP_EOL);
|
||||
|
||||
$files = array_slice($files, $fileToStartAt);
|
||||
$this->currentFile = $fileToStartAt;
|
||||
|
||||
foreach ($files as $file) {
|
||||
$this->currentFile++;
|
||||
|
||||
pcntl_signal_dispatch();
|
||||
|
||||
if ($this->isInterrupted) {
|
||||
break;
|
||||
}
|
||||
|
||||
$this->comment('[' . $this->currentFile . '/' . $totalFiles . '] Importing track [' . $file->getFilename() . ']...');
|
||||
|
||||
if (!in_array($file->getExtension(), $this->allowedExtensions)) {
|
||||
$this->comment('This is not an audio file! Skipping...' . PHP_EOL);
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->info('Path to file: ' . $file->getRelativePath());
|
||||
$path_components = explode(DIRECTORY_SEPARATOR, $file->getRelativePath());
|
||||
$artist_name = $path_components[0];
|
||||
$album_name = array_key_exists(1, $path_components) ? $path_components[1] : null;
|
||||
|
||||
$this->info('Artist: ' . $artist_name);
|
||||
$this->info('Album: ' . $album_name);
|
||||
|
||||
//==========================================================================================================
|
||||
// Analyse the track so we can find the MIME type and album art
|
||||
//==========================================================================================================
|
||||
|
||||
$getId3 = new getID3;
|
||||
|
||||
// all tags read by getID3, including the cover art
|
||||
$allTags = $getId3->analyze($file->getPathname());
|
||||
|
||||
// tags specific to a file format (ID3 or Atom), pre-normalization but with cover art removed
|
||||
$rawTags = [];
|
||||
|
||||
// normalized tags used by Pony.fm
|
||||
$parsedTags = [];
|
||||
|
||||
list($parsedTags, $rawTags) = $this->parseTags($file, $allTags);
|
||||
|
||||
//$imageFilename = $file->getFilename() . ".tags.txt";
|
||||
//$imageFilePath = "$tmpPath/" . $imageFilename;
|
||||
//File::put($imageFilePath, print_r($allTags, true));
|
||||
|
||||
// Parse out the hyphen in the file name
|
||||
$hyphen = ' - ';
|
||||
if (is_null($parsedTags['title'])) {
|
||||
$fileName = pathinfo($file->getFilename(), PATHINFO_FILENAME);
|
||||
$parsedTags['title'] = substr($fileName, strpos($fileName, $hyphen) + strlen($hyphen));
|
||||
}
|
||||
|
||||
$this->info('Title: ' . $parsedTags['title']);
|
||||
|
||||
//==========================================================================================================
|
||||
// Determine the release date.
|
||||
//==========================================================================================================
|
||||
$modifiedDate = Carbon::createFromTimeStampUTC(File::lastModified($file->getPathname()));
|
||||
$taggedYear = $parsedTags['year'];
|
||||
|
||||
$this->info('Modification year: '.$modifiedDate->year);
|
||||
$this->info('Tagged year: '.$taggedYear);
|
||||
|
||||
if ($taggedYear !== null && $modifiedDate->year === $taggedYear) {
|
||||
$releasedAt = $modifiedDate;
|
||||
|
||||
} else if ($taggedYear !== null && $modifiedDate->year !== $taggedYear) {
|
||||
$this->warn('Release years don\'t match! Using the tagged year...');
|
||||
$releasedAt = Carbon::create($taggedYear);
|
||||
|
||||
} else {
|
||||
// $taggedYear is null
|
||||
$this->warn('This track isn\'t tagged with its release year! Using the track\'s last modified date...');
|
||||
$releasedAt = $modifiedDate;
|
||||
}
|
||||
|
||||
// This is later used by the classification/publishing script to determine the publication date.
|
||||
$parsedTags['released_at'] = $releasedAt->toDateTimeString();
|
||||
|
||||
//==========================================================================================================
|
||||
// Does this track have vocals?
|
||||
//==========================================================================================================
|
||||
$isVocal = $parsedTags['lyrics'] !== null;
|
||||
|
||||
//==========================================================================================================
|
||||
// Determine the genre
|
||||
//==========================================================================================================
|
||||
$genreName = $parsedTags['genre'];
|
||||
$this->info('Genre: '.$genreName);
|
||||
|
||||
if ($genreName) {
|
||||
$genre = Genre::where('name', '=', $genreName)->first();
|
||||
if ($genre) {
|
||||
$genreId = $genre->id;
|
||||
|
||||
} else {
|
||||
$genre = new Genre();
|
||||
$genre->name = $genreName;
|
||||
$genre->slug = Str::slug($genreName);
|
||||
$genre->save();
|
||||
$genreId = $genre->id;
|
||||
$this->comment('Created a new genre!');
|
||||
}
|
||||
|
||||
} else {
|
||||
$genreId = $UNKNOWN_GENRE->id; // "Unknown" genre ID
|
||||
}
|
||||
|
||||
//==========================================================================================================
|
||||
// Check to see if we have this track already, if so, compare hashes of the two files
|
||||
//==========================================================================================================
|
||||
|
||||
$artist = User::where('display_name', '=', $artist_name)->first();
|
||||
$artistId = null;
|
||||
|
||||
$this->comment("Checking for duplicates");
|
||||
|
||||
if ($artist) {
|
||||
$artistId = $artist->id;
|
||||
}
|
||||
|
||||
$existingTrack = Track::where('title', '=', $parsedTags['title'])
|
||||
->where('user_id', '=', $artistId)
|
||||
->first();
|
||||
|
||||
if ($existingTrack) {
|
||||
// We got one!!
|
||||
// Ok, let's not get too excited
|
||||
// First let's see if we have a matching file type
|
||||
|
||||
$importFormat = $this->getFormat($file->getExtension());
|
||||
if ($importFormat == null) {
|
||||
// No idea what this is, skip file
|
||||
$this->comment(sprintf("Not an audio file (%s), skipping...", $importFormat));
|
||||
continue;
|
||||
}
|
||||
|
||||
$existingFile = null;
|
||||
|
||||
foreach ($existingTrack->trackFiles as $trackFile) {
|
||||
if ($trackFile->format == $importFormat) {
|
||||
$existingFile = $trackFile;
|
||||
}
|
||||
}
|
||||
|
||||
if ($existingFile === null) {
|
||||
// Can't find a matching format
|
||||
// See if we have a higher quality source file
|
||||
if (Track::$Formats[$importFormat]['is_lossless']) {
|
||||
// Source is lossless, is the existing track lossy?
|
||||
if ($existingFile->isMasterLossy()) {
|
||||
// Cool! Let's replace it
|
||||
$this->comment('Replacing (' . $existingTrack->id . ') ' . $existingTrack->title);
|
||||
|
||||
$this->replaceTrack($file, $existingTrack, $artist, $allTags['mime_type']);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
} else {
|
||||
$this->comment("Found existing file");
|
||||
|
||||
// Found a matching format, are they the same?
|
||||
// Before we check it, see if it came from MLPMA
|
||||
// We're only replacing tracks with the same format if they're archived
|
||||
$mlpmaTrack = DB::table('mlpma_tracks')->where('track_id', '=', $existingTrack->id)->first();
|
||||
|
||||
if (!is_null($mlpmaTrack)) {
|
||||
$getId3_source = new getID3;
|
||||
|
||||
$getId3_source->option_md5_data = true;
|
||||
$getId3_source->option_md5_data_source = true;
|
||||
|
||||
$sourceWithMd5 = $getId3_source->analyze($file->getPathname());
|
||||
|
||||
$getId3_existing = new getID3;
|
||||
$getId3_existing->option_md5_data = true;
|
||||
$getId3_existing->option_md5_data_source = true;
|
||||
$existingFileTags = $getId3_existing->analyze($existingFile->getFile());
|
||||
|
||||
$importHash = array_key_exists('md5_data_source', $sourceWithMd5) ? $sourceWithMd5['md5_data_source'] : $sourceWithMd5['md5_data'];
|
||||
$targetHash = array_key_exists('md5_data_source', $existingFileTags) ? $existingFileTags['md5_data_source'] : $existingFileTags['md5_data'];
|
||||
|
||||
$this->info("Archive hash: " . $importHash);
|
||||
$this->info("Pony.fm hash: " . $targetHash);
|
||||
|
||||
if ($importHash == $targetHash) {
|
||||
// Audio is identical, no need to reupload
|
||||
// We can update the metadata though
|
||||
$this->comment("Versions are the same. Updating metadata...\n");
|
||||
$changedMetadata = false;
|
||||
|
||||
if (strlen($existingTrack->description) < strlen($parsedTags['comments'])) {
|
||||
$existingTrack->description = $parsedTags['comments'];
|
||||
$changedMetadata = true;
|
||||
$this->comment("Updated description");
|
||||
}
|
||||
|
||||
if (strlen($existingTrack->lyrics) < strlen($parsedTags['lyrics'])) {
|
||||
$existingTrack->lyrics = $parsedTags['lyrics'];
|
||||
$changedMetadata = true;
|
||||
$this->comment("Updated lyrics");
|
||||
}
|
||||
|
||||
if ($changedMetadata) $existingTrack->save();
|
||||
|
||||
continue;
|
||||
} else {
|
||||
// Audio is different, let's replace it
|
||||
$this->comment('Replacing (' . $existingTrack->id . ') ' . $existingTrack->title);
|
||||
|
||||
$this->replaceTrack($file, $existingTrack, $artist, $allTags['mime_type']);
|
||||
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$this->comment("Not replacing, user uploaded");
|
||||
|
||||
// We can update the metadata though
|
||||
$changedMetadata = false;
|
||||
|
||||
if (strlen($existingTrack->description) < strlen($parsedTags['comments'])) {
|
||||
$existingTrack->description = $parsedTags['comments'];
|
||||
$changedMetadata = true;
|
||||
$this->comment("Updated description");
|
||||
}
|
||||
|
||||
if (strlen($existingTrack->lyrics) < strlen($parsedTags['lyrics'])) {
|
||||
$existingTrack->lyrics = $parsedTags['lyrics'];
|
||||
$changedMetadata = true;
|
||||
$this->comment("Updated lyrics");
|
||||
}
|
||||
|
||||
if ($changedMetadata) $existingTrack->save();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->comment("No duplicates");
|
||||
}
|
||||
|
||||
//==========================================================================================================
|
||||
// Create new user for the artist if one doesn't exist
|
||||
//==========================================================================================================
|
||||
|
||||
if (!$artist) {
|
||||
$artist = new User;
|
||||
$artist->display_name = $artist_name;
|
||||
$artist->email = null;
|
||||
$artist->is_archived = true;
|
||||
|
||||
$artist->slug = Str::slug($artist_name);
|
||||
|
||||
$slugExists = User::where('slug', '=', $artist->slug)->first();
|
||||
if ($slugExists) {
|
||||
$this->error('Horsefeathers! The slug ' . $artist->slug . ' is already taken!');
|
||||
$artist->slug = $artist->slug . '-' . Str::random(4);
|
||||
}
|
||||
|
||||
$artist->save();
|
||||
}
|
||||
|
||||
//==========================================================================================================
|
||||
// Grab the image and save it so we can pass that along when the track gets uploaded
|
||||
//==========================================================================================================
|
||||
|
||||
$this->comment('Extracting cover art!');
|
||||
$coverId = null;
|
||||
$image = null;
|
||||
|
||||
if (array_key_exists('comments', $allTags) && array_key_exists('picture', $allTags['comments'])) {
|
||||
$image = $allTags['comments']['picture'][0];
|
||||
} else if (array_key_exists('id3v2', $allTags) && array_key_exists('APIC', $allTags['id3v2'])) {
|
||||
$image = $allTags['id3v2']['APIC'][0];
|
||||
}
|
||||
|
||||
if ($image !== null) {
|
||||
if ($image['image_mime'] === 'image/png') {
|
||||
$extension = 'png';
|
||||
} else {
|
||||
if ($image['image_mime'] === 'image/jpeg') {
|
||||
$extension = 'jpg';
|
||||
} else {
|
||||
if ($image['image_mime'] === 'image/gif') {
|
||||
$extension = 'gif';
|
||||
} else {
|
||||
$this->error('Unknown cover art format!');
|
||||
}
|
||||
}
|
||||
}
|
||||
// write temporary image file
|
||||
$imageFilename = $file->getFilename() . ".cover.$extension";
|
||||
$imageFilePath = "$tmpPath/" . $imageFilename;
|
||||
File::put($imageFilePath, $image['data']);
|
||||
|
||||
$imageFile = new UploadedFile($imageFilePath, $imageFilename, $image['image_mime'], null, null, true);
|
||||
$cover = Image::upload($imageFile, $artist);
|
||||
$coverId = $cover->id;
|
||||
} else {
|
||||
$this->comment('No cover art found!');
|
||||
}
|
||||
|
||||
//==========================================================================================================
|
||||
// Is this part of an album?
|
||||
//==========================================================================================================
|
||||
$albumId = null;
|
||||
$albumName = $parsedTags['album'];
|
||||
|
||||
if ($albumName !== null) {
|
||||
$album = Album::where('user_id', '=', $artist->id)
|
||||
->where('title', '=', $albumName)
|
||||
->first();
|
||||
|
||||
if (!$album) {
|
||||
$album = new Album;
|
||||
|
||||
$album->title = $albumName;
|
||||
$album->user_id = $artist->id;
|
||||
$album->cover_id = $coverId;
|
||||
$album->description = "";
|
||||
|
||||
$album->save();
|
||||
}
|
||||
|
||||
$albumId = $album->id;
|
||||
}
|
||||
|
||||
//==========================================================================================================
|
||||
// Send the track into the upload system like a user just uploaded a track
|
||||
//==========================================================================================================
|
||||
|
||||
$this->comment('Transcoding the track!');
|
||||
Auth::loginUsingId($artist->id);
|
||||
|
||||
$mime = $allTags['mime_type'];
|
||||
|
||||
File::copy($file->getPathname(), "$tmpPath/" . $file->getFilename());
|
||||
$trackFile = new UploadedFile("$tmpPath/" . $file->getFilename(), $file->getFilename(), $mime, null, null, true);
|
||||
|
||||
$upload = new UploadTrackCommand(true);
|
||||
$upload->_file = $trackFile;
|
||||
$result = $upload->execute();
|
||||
|
||||
if ($result->didFail()) {
|
||||
$this->error(json_encode($result->getValidator()->messages()->getMessages(), JSON_PRETTY_PRINT));
|
||||
} else {
|
||||
$track = Track::find($result->getResponse()['id']);
|
||||
$track->cover_id = $coverId;
|
||||
$track->album_id = $albumId;
|
||||
$track->genre_id = $genreId;
|
||||
$track->track_number = $parsedTags['track_number'];
|
||||
$track->released_at = $releasedAt;
|
||||
$track->is_downloadable = true;
|
||||
$track->is_vocal = $isVocal;
|
||||
$track->license_id = 2;
|
||||
$track->description = "";
|
||||
$track->lyrics = "";
|
||||
|
||||
if (!is_null($parsedTags['comments'])) {
|
||||
$track->description = $parsedTags['comments'];
|
||||
}
|
||||
|
||||
if (!is_null($parsedTags['lyrics'])) {
|
||||
$track->lyrics = $parsedTags['lyrics'];
|
||||
}
|
||||
|
||||
if (!is_null($parsedTags['title'])) {
|
||||
$track->title = $parsedTags['title'];
|
||||
}
|
||||
|
||||
$track->save();
|
||||
|
||||
// If we made it to here, the track is intact! Log the import.
|
||||
DB::table('ponify_tracks')
|
||||
->insert([
|
||||
'track_id' => $result->getResponse()['id'],
|
||||
'path' => $file->getRelativePath(),
|
||||
'filename' => $file->getFilename(),
|
||||
'extension' => $file->getExtension(),
|
||||
'imported_at' => Carbon::now(),
|
||||
'parsed_tags' => json_encode($parsedTags),
|
||||
'raw_tags' => json_encode($rawTags),
|
||||
]);
|
||||
}
|
||||
|
||||
echo PHP_EOL . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
protected function hashAudio($filepath) {
|
||||
$hash = hash_file('crc32b', $filepath);
|
||||
$array = unpack('N', pack('H*', $hash));
|
||||
return $array[1];
|
||||
}
|
||||
|
||||
protected function getFormat($extension) {
|
||||
foreach(Track::$Formats as $name => $format) {
|
||||
if ($format['extension'] == $extension) {
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function parseTags($file, $allTags)
|
||||
{
|
||||
$audioCodec = $file->getExtension();
|
||||
|
||||
//==========================================================================================================
|
||||
// Extract the original tags.
|
||||
//==========================================================================================================
|
||||
|
||||
// $rawTags => tags specific to a file format (ID3 or Atom), pre-normalization but with cover art removed
|
||||
// $parsedTags => normalized tags used by Pony.fm
|
||||
|
||||
if ($audioCodec === 'mp3') {
|
||||
list($parsedTags, $rawTags) = $this->getId3Tags($allTags);
|
||||
} elseif (Str::startsWith($audioCodec, ['aac', 'alac'])) {
|
||||
list($parsedTags, $rawTags) = $this->getAtomTags($allTags);
|
||||
} elseif (in_array($audioCodec, ['vorbis', 'flac'])) {
|
||||
list($parsedTags, $rawTags) = $this->getVorbisTags($allTags);
|
||||
} elseif (Str::startsWith($audioCodec, ['pcm', 'adpcm'])) {
|
||||
list($parsedTags, $rawTags) = $this->getAtomTags($allTags);
|
||||
} else {
|
||||
// Assume the file is untagged if it's in an unknown format.
|
||||
$parsedTags = [
|
||||
'title' => null,
|
||||
'artist' => null,
|
||||
'band' => null,
|
||||
'genre' => null,
|
||||
'track_number' => null,
|
||||
'album' => null,
|
||||
'year' => null,
|
||||
'release_date' => null,
|
||||
'comments' => null,
|
||||
'lyrics' => null,
|
||||
];
|
||||
$rawTags = [];
|
||||
}
|
||||
|
||||
|
||||
return [$parsedTags, $rawTags];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $rawTags
|
||||
* @return array
|
||||
*/
|
||||
protected function getId3Tags($rawTags)
|
||||
{
|
||||
$tags = [];
|
||||
|
||||
if (array_key_exists('tags', $rawTags)) {
|
||||
if (array_key_exists('id3v2', $rawTags['tags'])) {
|
||||
$tags = $rawTags['tags']['id3v2'];
|
||||
} elseif (array_key_exists('id3v1', $rawTags['tags'])) {
|
||||
$tags = $rawTags['tags']['id3v1'];
|
||||
} else {
|
||||
$tags = [];
|
||||
}
|
||||
} else {
|
||||
$tags = [];
|
||||
}
|
||||
|
||||
$comment = null;
|
||||
|
||||
if (isset($tags['comment'])) {
|
||||
// The "comment" tag comes in with a badly encoded string index
|
||||
// so its array key has to be used implicitly.
|
||||
$key = array_keys($tags['comment'])[0];
|
||||
|
||||
// The comment may have a null byte at the end. trim() removes it.
|
||||
$comment = trim($tags['comment'][$key]);
|
||||
|
||||
// Replace the malformed comment with the "fixed" one.
|
||||
unset($tags['comment'][$key]);
|
||||
$tags['comment'][0] = $comment;
|
||||
}
|
||||
|
||||
$trackNumber = 1;
|
||||
if (isset($tags['track_number'])) {
|
||||
$trackNumberComponents = explode('/', $tags['track_number'][0]);
|
||||
$trackNumber = $trackNumberComponents[0];
|
||||
}
|
||||
|
||||
return [
|
||||
[
|
||||
'title' => isset($tags['title']) ? $tags['title'][0] : null,
|
||||
'artist' => isset($tags['artist']) ? $tags['artist'][0] : null,
|
||||
'band' => isset($tags['band']) ? $tags['band'][0] : null,
|
||||
'genre' => isset($tags['genre']) ? $tags['genre'][0] : null,
|
||||
'track_number' => $trackNumber,
|
||||
'album' => isset($tags['album']) ? $tags['album'][0] : null,
|
||||
'year' => isset($tags['year']) ? (int) $tags['year'][0] : null,
|
||||
'release_date' => isset($tags['release_date']) ? $this->parseDateString($tags['release_date'][0]) : null,
|
||||
'comments' => $comment,
|
||||
'lyrics' => isset($tags['unsynchronised_lyric']) ? $tags['unsynchronised_lyric'][0] : null,
|
||||
],
|
||||
$tags
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $rawTags
|
||||
* @return array
|
||||
*/
|
||||
protected function getAtomTags($rawTags)
|
||||
{
|
||||
if (array_key_exists('tags', $rawTags) && array_key_exists('quicktime', $rawTags['tags'])) {
|
||||
$tags = $rawTags['tags']['quicktime'];
|
||||
} else {
|
||||
$tags = [];
|
||||
}
|
||||
|
||||
$trackNumber = 1;
|
||||
if (isset($tags['track_number'])) {
|
||||
$trackNumberComponents = explode('/', $tags['track_number'][0]);
|
||||
$trackNumber = $trackNumberComponents[0];
|
||||
}
|
||||
|
||||
if (isset($tags['release_date'])) {
|
||||
$releaseDate = $this->parseDateString($tags['release_date'][0]);
|
||||
} elseif (isset($tags['creation_date'])) {
|
||||
$releaseDate = $this->parseDateString($tags['creation_date'][0]);
|
||||
} else {
|
||||
$releaseDate = null;
|
||||
}
|
||||
|
||||
return [
|
||||
[
|
||||
'title' => isset($tags['title']) ? $tags['title'][0] : null,
|
||||
'artist' => isset($tags['artist']) ? $tags['artist'][0] : null,
|
||||
'band' => isset($tags['band']) ? $tags['band'][0] : null,
|
||||
'album_artist' => isset($tags['album_artist']) ? $tags['album_artist'][0] : null,
|
||||
'genre' => isset($tags['genre']) ? $tags['genre'][0] : null,
|
||||
'track_number' => $trackNumber,
|
||||
'album' => isset($tags['album']) ? $tags['album'][0] : null,
|
||||
'year' => isset($tags['year']) ? (int) $tags['year'][0] : null,
|
||||
'release_date' => $releaseDate,
|
||||
'comments' => isset($tags['comments']) ? $tags['comments'][0] : null,
|
||||
'lyrics' => isset($tags['lyrics']) ? $tags['lyrics'][0] : null,
|
||||
],
|
||||
$tags
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $rawTags
|
||||
* @return array
|
||||
*/
|
||||
protected function getVorbisTags($rawTags)
|
||||
{
|
||||
if (array_key_exists('tags', $rawTags) && array_key_exists('vorbiscomment', $rawTags['tags'])) {
|
||||
$tags = $rawTags['tags']['vorbiscomment'];
|
||||
} else {
|
||||
$tags = [];
|
||||
}
|
||||
|
||||
$trackNumber = 1;
|
||||
if (isset($tags['track_number'])) {
|
||||
$trackNumberComponents = explode('/', $tags['track_number'][0]);
|
||||
$trackNumber = $trackNumberComponents[0];
|
||||
}
|
||||
|
||||
return [
|
||||
[
|
||||
'title' => isset($tags['title']) ? $tags['title'][0] : null,
|
||||
'artist' => isset($tags['artist']) ? $tags['artist'][0] : null,
|
||||
'band' => isset($tags['band']) ? $tags['band'][0] : null,
|
||||
'album_artist' => isset($tags['album_artist']) ? $tags['album_artist'][0] : null,
|
||||
'genre' => isset($tags['genre']) ? $tags['genre'][0] : null,
|
||||
'track_number' => $trackNumber,
|
||||
'album' => isset($tags['album']) ? $tags['album'][0] : null,
|
||||
'year' => isset($tags['year']) ? (int) $tags['year'][0] : null,
|
||||
'release_date' => isset($tags['date']) ? $this->parseDateString($tags['date'][0]) : null,
|
||||
'comments' => isset($tags['comments']) ? $tags['comments'][0] : null,
|
||||
'lyrics' => isset($tags['lyrics']) ? $tags['lyrics'][0] : null,
|
||||
],
|
||||
$tags
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a potentially-partial date string into a proper date object.
|
||||
*
|
||||
* The tagging formats we deal with base their date format on ISO 8601, but
|
||||
* the timestamp may be incomplete.
|
||||
*
|
||||
* @link https://code.google.com/p/mp4v2/wiki/iTunesMetadata
|
||||
* @link https://wiki.xiph.org/VorbisComment#Date_and_time
|
||||
* @link http://id3.org/id3v2.4.0-frames
|
||||
*
|
||||
* @param string $dateString
|
||||
* @return null|Carbon
|
||||
*/
|
||||
protected function parseDateString(string $dateString)
|
||||
{
|
||||
switch (Str::length($dateString)) {
|
||||
// YYYY
|
||||
case 4:
|
||||
try {
|
||||
return Carbon::createFromFormat('Y', $dateString)
|
||||
->month(1)
|
||||
->day(1);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// YYYY-MM
|
||||
case 7:
|
||||
try {
|
||||
return Carbon::createFromFormat('Y m', str_replace("-", " ", $dateString))
|
||||
->day(1);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// YYYY-MM-DD
|
||||
case 10:
|
||||
try {
|
||||
return Carbon::createFromFormat('Y m d', str_replace("-", " ", $dateString));
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// We might have an ISO-8601 string in our hooves.
|
||||
// If not, give up.
|
||||
try {
|
||||
return Carbon::createFromFormat(Carbon::ISO8601, $dateString);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function replaceTrack($toBeUploaded, $targetTrack, $artist, $mime) {
|
||||
Auth::loginUsingId($artist->id);
|
||||
|
||||
$trackFile = new UploadedFile($toBeUploaded->getPathname(), $toBeUploaded->getFilename(), $mime, null, null, true);
|
||||
|
||||
$upload = new UploadTrackCommand(true, false, null, false, $targetTrack->getNextVersion(), $targetTrack);
|
||||
$upload->_file = $trackFile;
|
||||
$result = $upload->execute();
|
||||
|
||||
if ($result->didFail()) {
|
||||
$this->error(json_encode($result->getValidator()->messages()->getMessages(), JSON_PRETTY_PRINT));
|
||||
} else {
|
||||
$track = Track::find($result->getResponse()['id']);
|
||||
$track->license_id = 2;
|
||||
$track->save();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -46,7 +46,8 @@ class Kernel extends ConsoleKernel
|
|||
\Poniverse\Ponyfm\Console\Commands\MergeAccounts::class,
|
||||
\Poniverse\Ponyfm\Console\Commands\SyncPoniverseAccounts::class,
|
||||
\Poniverse\Ponyfm\Console\Commands\FixMLPMAImages::class,
|
||||
\Poniverse\Ponyfm\Console\Commands\VersionFiles::class
|
||||
\Poniverse\Ponyfm\Console\Commands\VersionFiles::class,
|
||||
\Poniverse\Ponyfm\Console\Commands\ImportPonify::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,6 +18,38 @@
|
|||
Version History
|
||||
===============
|
||||
|
||||
1.9.14: [2017-03-27] James Heinrich
|
||||
» Add experimental support for E-AC3
|
||||
* bugfix (G:105): RIFF.WAVE.iXML multiple TIMESTAMP_SAMPLE_RATE
|
||||
* bugfix (G:95): improperly initialized error/warning keys
|
||||
* bugfix (G:94): ID3v2 write support for TXXX
|
||||
* bugfix (G:93): all errors or warnings should pass through class method
|
||||
|
||||
1.9.13: [2016-12-14] James Heinrich
|
||||
* bugfix (G:89): ID3v2.4 custom genres with slashes
|
||||
* bugfix (G:88): large QuickTime files exceed PHP memory limit
|
||||
* bugfix (G:87): ID3v2 write GRID data not working properly
|
||||
* bugfix (G:86): Increase autoloading definitions
|
||||
* bugfix (G:84): ID3v2 available writable frames list
|
||||
* bugfix (G:82): ID3v2 datetime logic
|
||||
* bugfix (G:80): attempt to autodetect ID3v1 encoding
|
||||
* bugfix (G:77): add partial support of DSSv6
|
||||
* bugfix (G:76): add mysqli version of caching extension
|
||||
* bugfix (G:75): mysql cache max key length
|
||||
* bugfix (G:71): custom error handler to catch exif_read_data() errors
|
||||
* bugfix (G:71): add support for mb_convert_encoding
|
||||
* bugfix (G:70): ID3v2 POPM / UFID
|
||||
* bugfix (G:68): workaround broken iTunes ID3v2
|
||||
* bugfix (G:48): Quicktime set MIME to video/mp4 where applicable
|
||||
* bugfix (#1930) fread on pipes
|
||||
* bugfix (#1926) relax ID3v2.IsValidURL check
|
||||
|
||||
1.9.12: [2016-03-02] James Heinrich
|
||||
» Add support for Direct Stream Digital (DSD) /
|
||||
DSD Storage Facility (DSF) file format
|
||||
» Add detection (not parsing) of WebP image format
|
||||
* bugfix (#1910): Quicktime embedded images
|
||||
|
||||
1.9.11: [2015-12-24] James Heinrich
|
||||
* bugfix (G:64): update constructor syntax for PHP 7
|
||||
* bugfix (G:62): infinite loop in large PNG files
|
||||
|
|
|
@ -10,6 +10,6 @@
|
|||
"php": ">=5.3.0"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": ["getid3/getid3.php"]
|
||||
"classmap": ["getid3/"]
|
||||
}
|
||||
}
|
|
@ -43,14 +43,13 @@ require_once('../getid3/getid3.php');
|
|||
* Class for extracting information from audio files with getID3().
|
||||
*/
|
||||
|
||||
class AudioInfo
|
||||
{
|
||||
class AudioInfo {
|
||||
|
||||
/**
|
||||
* Private variables
|
||||
*/
|
||||
var $result = null;
|
||||
var $info = null;
|
||||
var $result = NULL;
|
||||
var $info = NULL;
|
||||
|
||||
|
||||
|
||||
|
@ -59,8 +58,7 @@ class AudioInfo
|
|||
* Constructor
|
||||
*/
|
||||
|
||||
function AudioInfo()
|
||||
{
|
||||
function AudioInfo() {
|
||||
|
||||
// Initialize getID3 engine
|
||||
$this->getID3 = new getID3;
|
||||
|
@ -79,19 +77,18 @@ class AudioInfo
|
|||
* @param string file Audio file to extract info from.
|
||||
*/
|
||||
|
||||
function Info($file)
|
||||
{
|
||||
function Info($file) {
|
||||
|
||||
// Analyze file
|
||||
$this->info = $this->getID3->analyze($file);
|
||||
|
||||
// Exit here on error
|
||||
if (isset($this->info['error'])) {
|
||||
return ['error' => $this->info['error']];
|
||||
return array ('error' => $this->info['error']);
|
||||
}
|
||||
|
||||
// Init wrapper object
|
||||
$this->result = [];
|
||||
$this->result = array();
|
||||
$this->result['format_name'] = (isset($this->info['fileformat']) ? $this->info['fileformat'] : '').'/'.(isset($this->info['audio']['dataformat']) ? $this->info['audio']['dataformat'] : '').(isset($this->info['video']['dataformat']) ? '/'.$this->info['video']['dataformat'] : '');
|
||||
$this->result['encoder_version'] = (isset($this->info['audio']['encoder']) ? $this->info['audio']['encoder'] : '');
|
||||
$this->result['encoder_options'] = (isset($this->info['audio']['encoder_options']) ? $this->info['audio']['encoder_options'] : '');
|
||||
|
@ -124,8 +121,7 @@ class AudioInfo
|
|||
* @access private
|
||||
*/
|
||||
|
||||
function aacInfo()
|
||||
{
|
||||
function aacInfo() {
|
||||
$this->result['format_name'] = 'AAC';
|
||||
}
|
||||
|
||||
|
@ -138,14 +134,19 @@ class AudioInfo
|
|||
* @access private
|
||||
*/
|
||||
|
||||
function riffInfo()
|
||||
{
|
||||
function riffInfo() {
|
||||
if ($this->info['audio']['dataformat'] == 'wav') {
|
||||
|
||||
$this->result['format_name'] = 'Wave';
|
||||
|
||||
} elseif (preg_match('#^mp[1-3]$#', $this->info['audio']['dataformat'])) {
|
||||
|
||||
$this->result['format_name'] = strtoupper($this->info['audio']['dataformat']);
|
||||
|
||||
} else {
|
||||
|
||||
$this->result['format_name'] = 'riff/'.$this->info['audio']['dataformat'];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,8 +159,7 @@ class AudioInfo
|
|||
* @access private
|
||||
*/
|
||||
|
||||
function flacInfo()
|
||||
{
|
||||
function flacInfo() {
|
||||
$this->result['format_name'] = 'FLAC';
|
||||
}
|
||||
|
||||
|
@ -173,8 +173,7 @@ class AudioInfo
|
|||
* @access private
|
||||
*/
|
||||
|
||||
function macInfo()
|
||||
{
|
||||
function macInfo() {
|
||||
$this->result['format_name'] = 'Monkey\'s Audio';
|
||||
}
|
||||
|
||||
|
@ -188,8 +187,7 @@ class AudioInfo
|
|||
* @access private
|
||||
*/
|
||||
|
||||
function laInfo()
|
||||
{
|
||||
function laInfo() {
|
||||
$this->result['format_name'] = 'La';
|
||||
}
|
||||
|
||||
|
@ -203,16 +201,23 @@ class AudioInfo
|
|||
* @access private
|
||||
*/
|
||||
|
||||
function oggInfo()
|
||||
{
|
||||
function oggInfo() {
|
||||
if ($this->info['audio']['dataformat'] == 'vorbis') {
|
||||
|
||||
$this->result['format_name'] = 'Ogg Vorbis';
|
||||
|
||||
} else if ($this->info['audio']['dataformat'] == 'flac') {
|
||||
|
||||
$this->result['format_name'] = 'Ogg FLAC';
|
||||
|
||||
} else if ($this->info['audio']['dataformat'] == 'speex') {
|
||||
|
||||
$this->result['format_name'] = 'Ogg Speex';
|
||||
|
||||
} else {
|
||||
|
||||
$this->result['format_name'] = 'Ogg '.$this->info['audio']['dataformat'];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,8 +230,7 @@ class AudioInfo
|
|||
* @access private
|
||||
*/
|
||||
|
||||
function mpcInfo()
|
||||
{
|
||||
function mpcInfo() {
|
||||
$this->result['format_name'] = 'Musepack';
|
||||
}
|
||||
|
||||
|
@ -239,8 +243,7 @@ class AudioInfo
|
|||
* @access private
|
||||
*/
|
||||
|
||||
function mp3Info()
|
||||
{
|
||||
function mp3Info() {
|
||||
$this->result['format_name'] = 'MP3';
|
||||
}
|
||||
|
||||
|
@ -253,8 +256,7 @@ class AudioInfo
|
|||
* @access private
|
||||
*/
|
||||
|
||||
function mp2Info()
|
||||
{
|
||||
function mp2Info() {
|
||||
$this->result['format_name'] = 'MP2';
|
||||
}
|
||||
|
||||
|
@ -268,8 +270,7 @@ class AudioInfo
|
|||
* @access private
|
||||
*/
|
||||
|
||||
function mp1Info()
|
||||
{
|
||||
function mp1Info() {
|
||||
$this->result['format_name'] = 'MP1';
|
||||
}
|
||||
|
||||
|
@ -282,8 +283,7 @@ class AudioInfo
|
|||
* @access private
|
||||
*/
|
||||
|
||||
function asfInfo()
|
||||
{
|
||||
function asfInfo() {
|
||||
$this->result['format_name'] = strtoupper($this->info['audio']['dataformat']);
|
||||
}
|
||||
|
||||
|
@ -295,8 +295,7 @@ class AudioInfo
|
|||
* @access private
|
||||
*/
|
||||
|
||||
function realInfo()
|
||||
{
|
||||
function realInfo() {
|
||||
$this->result['format_name'] = 'Real';
|
||||
}
|
||||
|
||||
|
@ -310,8 +309,8 @@ class AudioInfo
|
|||
* @access private
|
||||
*/
|
||||
|
||||
function vqfInfo()
|
||||
{
|
||||
function vqfInfo() {
|
||||
$this->result['format_name'] = 'VQF';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
die('Due to a security issue, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in '.$_SERVER['PHP_SELF']);
|
||||
|
||||
|
||||
// include getID3() library (can be in a different directory if full path is specified)
|
||||
require_once('../getid3/getid3.php');
|
||||
|
||||
|
@ -46,7 +45,10 @@ getid3_lib::CopyTagsToComments($ThisFileInfo);
|
|||
//echo $ThisFileInfo['audio']['bitrate']; // audio bitrate
|
||||
//echo $ThisFileInfo['playtime_string']; // playtime in minutes:seconds, formatted string
|
||||
|
||||
/*
|
||||
if you want to see ALL the output, uncomment this line:
|
||||
*/
|
||||
//echo '<pre>'.htmlentities(print_r($ThisFileInfo, true)).'</pre>';
|
||||
/* if you want to see all the tag data (from all tag formats), uncomment this line: */
|
||||
//echo '<pre>'.htmlentities(print_r($ThisFileInfo['comments'], true), ENT_SUBSTITUTE).'</pre>';
|
||||
|
||||
/* if you want to see ALL the output, uncomment this line: */
|
||||
//echo '<pre>'.htmlentities(print_r($ThisFileInfo, true), ENT_SUBSTITUTE).'</pre>';
|
||||
|
||||
|
||||
|
|
|
@ -26,9 +26,6 @@ if (function_exists('get_magic_quotes_runtime') && get_magic_quotes_runtime()) {
|
|||
if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
|
||||
die('magic_quotes_gpc is enabled, getID3 will not run.');
|
||||
}
|
||||
if (!defined('ENT_SUBSTITUTE')) { // defined in PHP v5.4.0
|
||||
define('ENT_SUBSTITUTE', ENT_QUOTES);
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
$PageEncoding = 'UTF-8';
|
||||
|
@ -42,7 +39,7 @@ require_once('../getid3/getid3.php');
|
|||
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$getID3->setOption(['encoding' => $PageEncoding]);
|
||||
$getID3->setOption(array('encoding' => $PageEncoding));
|
||||
|
||||
$getID3checkColor_Head = 'CCCCDD';
|
||||
$getID3checkColor_DirectoryLight = 'FFCCCC';
|
||||
|
@ -83,6 +80,7 @@ if (isset($_REQUEST['deletefile'])) {
|
|||
|
||||
|
||||
if (isset($_REQUEST['filename'])) {
|
||||
|
||||
if (!file_exists($_REQUEST['filename']) || !is_file($_REQUEST['filename'])) {
|
||||
die(getid3_lib::iconv_fallback('ISO-8859-1', $PageEncoding, $_REQUEST['filename'].' does not exist'));
|
||||
}
|
||||
|
@ -122,7 +120,9 @@ if (isset($_REQUEST['filename'])) {
|
|||
echo table_var_dump($ThisFileInfo, false, $PageEncoding);
|
||||
$endtime = microtime(true);
|
||||
echo 'File parsed in '.number_format($endtime - $starttime, 3).' seconds.<br>';
|
||||
|
||||
} else {
|
||||
|
||||
$listdirectory = (isset($_REQUEST['listdirectory']) ? $_REQUEST['listdirectory'] : '.');
|
||||
$listdirectory = realpath($listdirectory); // get rid of /../../ references
|
||||
$currentfulldir = $listdirectory.'/';
|
||||
|
@ -135,6 +135,7 @@ if (isset($_REQUEST['filename'])) {
|
|||
|
||||
ob_start();
|
||||
if ($handle = opendir($listdirectory)) {
|
||||
|
||||
ob_end_clean();
|
||||
echo str_repeat(' ', 300); // IE buffers the first 300 or so chars, making this progressive display useless - fill the buffer with spaces
|
||||
echo 'Processing';
|
||||
|
@ -156,7 +157,6 @@ if (isset($_REQUEST['filename'])) {
|
|||
set_time_limit(30); // allocate another 30 seconds to process this file - should go much quicker than this unless intense processing (like bitrate histogram analysis) is enabled
|
||||
echo ' .'; // progress indicator dot
|
||||
flush(); // make sure the dot is shown, otherwise it's useless
|
||||
|
||||
switch ($file) {
|
||||
case '..':
|
||||
$ParentDir = realpath($file.'/..').'/';
|
||||
|
@ -177,9 +177,12 @@ if (isset($_REQUEST['filename'])) {
|
|||
$TargetObjectType = filetype($TargetObject); // Check file type without examining extension
|
||||
|
||||
if ($TargetObjectType == 'dir') {
|
||||
|
||||
$DirectoryContents[$currentfulldir]['dir'][$file]['filename'] = $file;
|
||||
|
||||
} elseif ($TargetObjectType == 'file') {
|
||||
$getID3->setOption(['option_md5_data' => (isset($_REQUEST['ShowMD5']) && GETID3_DEMO_BROWSE_ALLOW_MD5_LINK)]);
|
||||
|
||||
$getID3->setOption(array('option_md5_data' => (isset($_REQUEST['ShowMD5']) && GETID3_DEMO_BROWSE_ALLOW_MD5_LINK)));
|
||||
$fileinformation = $getID3->analyze($currentfilename);
|
||||
|
||||
getid3_lib::CopyTagsToComments($fileinformation);
|
||||
|
@ -398,8 +401,7 @@ echo '</body></html>';
|
|||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
function RemoveAccents($string)
|
||||
{
|
||||
function RemoveAccents($string) {
|
||||
// Revised version by markstewardרotmail*com
|
||||
// Again revised by James Heinrich (19-June-2006)
|
||||
return strtr(
|
||||
|
@ -408,7 +410,7 @@ function RemoveAccents($string)
|
|||
"\x8A\x8E\x9A\x9E\x9F\xC0\xC1\xC2\xC3\xC4\xC5\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD1\xD2\xD3\xD4\xD5\xD6\xD8\xD9\xDA\xDB\xDC\xDD\xE0\xE1\xE2\xE3\xE4\xE5\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFF",
|
||||
'SZszYAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy'
|
||||
),
|
||||
[
|
||||
array(
|
||||
"\xDE" => 'TH',
|
||||
"\xFE" => 'th',
|
||||
"\xD0" => 'DH',
|
||||
|
@ -419,13 +421,12 @@ function RemoveAccents($string)
|
|||
"\xC6" => 'AE',
|
||||
"\xE6" => 'ae',
|
||||
"\xB5" => 'u'
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function BitrateColor($bitrate, $BitrateMaxScale = 768)
|
||||
{
|
||||
function BitrateColor($bitrate, $BitrateMaxScale=768) {
|
||||
// $BitrateMaxScale is bitrate of maximum-quality color (bright green)
|
||||
// below this is gradient, above is solid green
|
||||
|
||||
|
@ -443,13 +444,11 @@ function BitrateColor($bitrate, $BitrateMaxScale = 768)
|
|||
return str_pad(dechex($Rcomponent), 2, '0', STR_PAD_LEFT).str_pad(dechex($Gcomponent), 2, '0', STR_PAD_LEFT).str_pad(dechex($Bcomponent), 2, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
function BitrateText($bitrate, $decimals = 0, $vbr = false)
|
||||
{
|
||||
function BitrateText($bitrate, $decimals=0, $vbr=false) {
|
||||
return '<span style="color: #'.BitrateColor($bitrate).($vbr ? '; font-weight: bold;' : '').'">'.number_format($bitrate, $decimals).' kbps</span>';
|
||||
}
|
||||
|
||||
function string_var_dump($variable)
|
||||
{
|
||||
function string_var_dump($variable) {
|
||||
if (version_compare(PHP_VERSION, '4.3.0', '>=')) {
|
||||
return print_r($variable, true);
|
||||
}
|
||||
|
@ -460,8 +459,7 @@ function string_var_dump($variable)
|
|||
return $dumpedvariable;
|
||||
}
|
||||
|
||||
function table_var_dump($variable, $wrap_in_td = false, $encoding = 'ISO-8859-1')
|
||||
{
|
||||
function table_var_dump($variable, $wrap_in_td=false, $encoding='ISO-8859-1') {
|
||||
$returnstring = '';
|
||||
switch (gettype($variable)) {
|
||||
case 'array':
|
||||
|
@ -477,7 +475,7 @@ function table_var_dump($variable, $wrap_in_td = false, $encoding = 'ISO-8859-1'
|
|||
}
|
||||
//if (($key == 'data') && isset($variable['image_mime']) && isset($variable['dataoffset'])) {
|
||||
if (($key == 'data') && isset($variable['image_mime'])) {
|
||||
$imageinfo = [];
|
||||
$imageinfo = array();
|
||||
if ($imagechunkcheck = getid3_lib::GetDataImageSize($value, $imageinfo)) {
|
||||
$returnstring .= '</td>'."\n".'<td><img src="data:'.$variable['image_mime'].';base64,'.base64_encode($value).'" width="'.$imagechunkcheck[0].'" height="'.$imagechunkcheck[1].'"></td></tr>'."\n";
|
||||
} else {
|
||||
|
@ -515,7 +513,7 @@ function table_var_dump($variable, $wrap_in_td = false, $encoding = 'ISO-8859-1'
|
|||
break;
|
||||
|
||||
default:
|
||||
$imageinfo = [];
|
||||
$imageinfo = array();
|
||||
if (($imagechunkcheck = getid3_lib::GetDataImageSize($variable, $imageinfo)) && ($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
|
||||
$returnstring .= ($wrap_in_td ? '<td>' : '');
|
||||
$returnstring .= '<table class="dump" cellspacing="0" cellpadding="2">';
|
||||
|
@ -533,8 +531,7 @@ function table_var_dump($variable, $wrap_in_td = false, $encoding = 'ISO-8859-1'
|
|||
}
|
||||
|
||||
|
||||
function NiceDisplayFiletypeFormat(&$fileinfo)
|
||||
{
|
||||
function NiceDisplayFiletypeFormat(&$fileinfo) {
|
||||
|
||||
if (empty($fileinfo['fileformat'])) {
|
||||
return '-';
|
||||
|
@ -568,10 +565,10 @@ function NiceDisplayFiletypeFormat(&$fileinfo)
|
|||
$output .= '.'.$fileinfo['video']['dataformat'];
|
||||
$output .= '.'.$fileinfo['audio']['dataformat']; // asf.wmv.wma
|
||||
return $output;
|
||||
|
||||
}
|
||||
|
||||
function MoreNaturalSort($ar1, $ar2)
|
||||
{
|
||||
function MoreNaturalSort($ar1, $ar2) {
|
||||
if ($ar1 === $ar2) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -589,7 +586,7 @@ function MoreNaturalSort($ar1, $ar2)
|
|||
}
|
||||
$ar1 = RemoveAccents(strtolower(trim($ar1)));
|
||||
$ar2 = RemoveAccents(strtolower(trim($ar2)));
|
||||
$translatearray = ['\''=>'', '"'=>'', '_'=>' ', '('=>'', ')'=>'', '-'=>' ', ' '=>' ', '.'=>'', ','=>''];
|
||||
$translatearray = array('\''=>'', '"'=>'', '_'=>' ', '('=>'', ')'=>'', '-'=>' ', ' '=>' ', '.'=>'', ','=>'');
|
||||
foreach ($translatearray as $key => $val) {
|
||||
$ar1 = str_replace($key, $val, $ar1);
|
||||
$ar2 = str_replace($key, $val, $ar2);
|
||||
|
@ -603,11 +600,10 @@ function MoreNaturalSort($ar1, $ar2)
|
|||
return 0;
|
||||
}
|
||||
|
||||
function PoweredBygetID3($string = '')
|
||||
{
|
||||
function PoweredBygetID3($string='') {
|
||||
global $getID3;
|
||||
if (!$string) {
|
||||
$string = '<div style="border: 1px #CCCCCC solid; padding: 5px; margin: 5px 0px; float: left; background-color: #EEEEEE; font-size: 8pt; font-face: sans-serif;">Powered by <a href="http://getid3.sourceforge.net"><b>getID3() v<!--GETID3VER--></b><br>http://getid3.sourceforge.net</a><br>Running on PHP v'.phpversion().' ('.(ceil(log(PHP_INT_MAX, 2)) + 1).'-bit)</div>';
|
||||
$string = '<div style="border: 1px #CCCCCC solid; padding: 5px; margin: 5px 0px; float: left; background-color: #EEEEEE; font-size: 8pt; font-face: sans-serif;">Powered by <a href="http://www.getid3.org/"><b>getID3() v<!--GETID3VER--></b><br>http://www.getid3.org/</a><br>Running on PHP v'.phpversion().' ('.(ceil(log(PHP_INT_MAX, 2)) + 1).'-bit)</div>';
|
||||
}
|
||||
return str_replace('<!--GETID3VER-->', $getID3->version(), $string);
|
||||
}
|
||||
|
|
|
@ -33,8 +33,7 @@
|
|||
// CombineMultipleMP3sTo('sample.mp3', array(array('input.mp3', 0, 30))); // extract first 30 seconds of audio
|
||||
|
||||
|
||||
function CombineMultipleMP3sTo($FilenameOut, $FilenamesIn)
|
||||
{
|
||||
function CombineMultipleMP3sTo($FilenameOut, $FilenamesIn) {
|
||||
|
||||
foreach ($FilenamesIn as $nextinputfilename) {
|
||||
if (is_array($nextinputfilename)) {
|
||||
|
@ -53,6 +52,7 @@ function CombineMultipleMP3sTo($FilenameOut, $FilenamesIn)
|
|||
require_once(dirname(__FILE__).'/../getid3/getid3.php');
|
||||
ob_start();
|
||||
if ($fp_output = fopen($FilenameOut, 'wb')) {
|
||||
|
||||
ob_end_clean();
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
|
@ -64,8 +64,10 @@ function CombineMultipleMP3sTo($FilenameOut, $FilenamesIn)
|
|||
}
|
||||
$CurrentFileInfo = $getID3->analyze($nextinputfilename);
|
||||
if ($CurrentFileInfo['fileformat'] == 'mp3') {
|
||||
|
||||
ob_start();
|
||||
if ($fp_source = fopen($nextinputfilename, 'rb')) {
|
||||
|
||||
ob_end_clean();
|
||||
$CurrentOutputPosition = ftell($fp_output);
|
||||
|
||||
|
@ -98,24 +100,34 @@ function CombineMultipleMP3sTo($FilenameOut, $FilenamesIn)
|
|||
fwrite($fp_output, fread($fp_source, min(32768, $end_offset_bytes - ftell($fp_source))));
|
||||
}
|
||||
fclose($fp_source);
|
||||
|
||||
} else {
|
||||
|
||||
$errormessage = ob_get_contents();
|
||||
ob_end_clean();
|
||||
echo 'failed to open '.$nextinputfilename.' for reading';
|
||||
fclose($fp_output);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
echo $nextinputfilename.' is not MP3 format';
|
||||
fclose($fp_output);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$errormessage = ob_get_contents();
|
||||
ob_end_clean();
|
||||
echo 'failed to open '.$FilenameOut.' for writing';
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
fclose($fp_output);
|
||||
|
|
|
@ -20,14 +20,17 @@ echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www
|
|||
echo '<html><head><title>getID3 demos - MIME type only</title><style type="text/css">BODY, TD, TH { font-family: sans-serif; font-size: 10pt; }</style></head><body>';
|
||||
|
||||
if (!empty($_REQUEST['filename'])) {
|
||||
|
||||
echo 'The file "'.htmlentities($_REQUEST['filename']).'" has a MIME type of "'.htmlentities(GetMIMEtype($_REQUEST['filename'])).'"';
|
||||
|
||||
} else {
|
||||
|
||||
echo 'Usage: <span style="font-family: monospace;">'.htmlentities($_SERVER['PHP_SELF']).'?filename=<i>filename.ext</i></span>';
|
||||
|
||||
}
|
||||
|
||||
|
||||
function GetMIMEtype($filename)
|
||||
{
|
||||
function GetMIMEtype($filename) {
|
||||
$filename = realpath($filename);
|
||||
if (!file_exists($filename)) {
|
||||
echo 'File does not exist: "'.htmlentities($filename).'"<br>';
|
||||
|
@ -46,6 +49,7 @@ function GetMIMEtype($filename)
|
|||
if ($fp = fopen($filename, 'rb')) {
|
||||
$getID3->openfile($filename);
|
||||
if (empty($getID3->info['error'])) {
|
||||
|
||||
// ID3v2 is the only tag format that might be prepended in front of files, and it's non-trivial to skip, easier just to parse it and know where to skip to
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
|
||||
$getid3_id3v2 = new getid3_id3v2($getID3);
|
||||
|
@ -57,6 +61,7 @@ function GetMIMEtype($filename)
|
|||
|
||||
$DeterminedFormatInfo = $getID3->GetFileFormat($formattest);
|
||||
$DeterminedMIMEtype = $DeterminedFormatInfo['mime_type'];
|
||||
|
||||
} else {
|
||||
echo 'Failed to getID3->openfile "'.htmlentities($filename).'"<br>';
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -12,14 +12,14 @@
|
|||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
//die('Due to a security issue, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in '.$_SERVER['PHP_SELF']);
|
||||
die('Due to a security issue, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in '.$_SERVER['PHP_SELF']);
|
||||
|
||||
$TextEncoding = 'UTF-8';
|
||||
|
||||
require_once('../getid3/getid3.php');
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$getID3->setOption(['encoding'=>$TextEncoding]);
|
||||
$getID3->setOption(array('encoding'=>$TextEncoding));
|
||||
|
||||
require_once('../getid3/write.php');
|
||||
// Initialize getID3 tag-writing module
|
||||
|
@ -28,7 +28,7 @@ $tagwriter = new getid3_writetags;
|
|||
$tagwriter->filename = 'c:/file.mp3';
|
||||
|
||||
//$tagwriter->tagformats = array('id3v1', 'id3v2.3');
|
||||
$tagwriter->tagformats = ['id3v2.3'];
|
||||
$tagwriter->tagformats = array('id3v2.3');
|
||||
|
||||
// set various options (optional)
|
||||
$tagwriter->overwrite_tags = true; // if true will erase existing tag data and write only passed data; if false will merge passed data with existing tag data (experimental)
|
||||
|
@ -37,16 +37,17 @@ $tagwriter->tag_encoding = $TextEncoding;
|
|||
$tagwriter->remove_other_tags = true;
|
||||
|
||||
// populate data array
|
||||
$TagData = [
|
||||
'title' => ['My Song'],
|
||||
'artist' => ['The Artist'],
|
||||
'album' => ['Greatest Hits'],
|
||||
'year' => ['2004'],
|
||||
'genre' => ['Rock'],
|
||||
'comment' => ['excellent!'],
|
||||
'track' => ['04/16'],
|
||||
'popularimeter' => ['email'=>'user@example.net', 'rating'=>128, 'data'=>0],
|
||||
];
|
||||
$TagData = array(
|
||||
'title' => array('My Song'),
|
||||
'artist' => array('The Artist'),
|
||||
'album' => array('Greatest Hits'),
|
||||
'year' => array('2004'),
|
||||
'genre' => array('Rock'),
|
||||
'comment' => array('excellent!'),
|
||||
'track' => array('04/16'),
|
||||
'popularimeter' => array('email'=>'user@example.net', 'rating'=>128, 'data'=>0),
|
||||
'unique_file_identifier' => array('ownerid'=>'user@example.net', 'data'=>md5(time())),
|
||||
);
|
||||
$tagwriter->tag_data = $TagData;
|
||||
|
||||
// write tags
|
||||
|
|
|
@ -25,7 +25,7 @@ echo '<html><head><title>getID3() - Sample tag writer</title></head><style type=
|
|||
require_once('../getid3/getid3.php');
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$getID3->setOption(['encoding'=>$TaggingFormat]);
|
||||
$getID3->setOption(array('encoding'=>$TaggingFormat));
|
||||
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.php', __FILE__, true);
|
||||
|
||||
|
@ -36,7 +36,8 @@ $Filename = (isset($_REQUEST['Filename']) ? $_REQUEST['Filename'] : '');
|
|||
|
||||
|
||||
if (isset($_POST['WriteTags'])) {
|
||||
$TagFormatsToWrite = (isset($_POST['TagFormatsToWrite']) ? $_POST['TagFormatsToWrite'] : []);
|
||||
|
||||
$TagFormatsToWrite = (isset($_POST['TagFormatsToWrite']) ? $_POST['TagFormatsToWrite'] : array());
|
||||
if (!empty($TagFormatsToWrite)) {
|
||||
echo 'starting to write tag(s)<BR>';
|
||||
|
||||
|
@ -49,7 +50,7 @@ if (isset($_POST['WriteTags'])) {
|
|||
$tagwriter->remove_other_tags = true;
|
||||
}
|
||||
|
||||
$commonkeysarray = ['Title', 'Artist', 'Album', 'Year', 'Comment'];
|
||||
$commonkeysarray = array('Title', 'Artist', 'Album', 'Year', 'Comment');
|
||||
foreach ($commonkeysarray as $key) {
|
||||
if (!empty($_POST[$key])) {
|
||||
$TagData[strtolower($key)][] = $_POST[$key];
|
||||
|
@ -75,12 +76,14 @@ if (isset($_POST['WriteTags'])) {
|
|||
fclose ($fd);
|
||||
|
||||
list($APIC_width, $APIC_height, $APIC_imageTypeID) = GetImageSize($_FILES['userfile']['tmp_name']);
|
||||
$imagetypes = [1=>'gif', 2=>'jpeg', 3=>'png'];
|
||||
$imagetypes = array(1=>'gif', 2=>'jpeg', 3=>'png');
|
||||
if (isset($imagetypes[$APIC_imageTypeID])) {
|
||||
|
||||
$TagData['attached_picture'][0]['data'] = $APICdata;
|
||||
$TagData['attached_picture'][0]['picturetypeid'] = $_POST['APICpictureType'];
|
||||
$TagData['attached_picture'][0]['description'] = $_FILES['userfile']['name'];
|
||||
$TagData['attached_picture'][0]['mime'] = 'image/'.$imagetypes[$APIC_imageTypeID];
|
||||
|
||||
} else {
|
||||
echo '<b>invalid image format (only GIF, JPEG, PNG)</b><br>';
|
||||
}
|
||||
|
@ -106,10 +109,14 @@ if (isset($_POST['WriteTags'])) {
|
|||
} else {
|
||||
echo 'Failed to write tags!<BLOCKQUOTE STYLE="background-color:#FF9999; padding: 10px;">'.implode('<br><br>', $tagwriter->errors).'</BLOCKQUOTE>';
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
echo 'WARNING: no tag formats selected for writing - nothing written';
|
||||
|
||||
}
|
||||
echo '<HR>';
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -121,6 +128,7 @@ if (!empty($Filename)) {
|
|||
echo '<table border="3" cellspacing="0" cellpadding="4">';
|
||||
echo '<tr><th align="right">Filename:</th><td><input type="hidden" name="Filename" value="'.htmlentities($Filename, ENT_QUOTES).'"><a href="'.htmlentities($browsescriptfilename.'?filename='.rawurlencode($Filename), ENT_QUOTES).'" target="_blank">'.$Filename.'</a></td></tr>';
|
||||
if (file_exists($Filename)) {
|
||||
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$OldThisFileInfo = $getID3->analyze($Filename);
|
||||
|
@ -130,33 +138,33 @@ if (!empty($Filename)) {
|
|||
case 'mp3':
|
||||
case 'mp2':
|
||||
case 'mp1':
|
||||
$ValidTagTypes = ['id3v1', 'id3v2.3', 'ape'];
|
||||
$ValidTagTypes = array('id3v1', 'id3v2.3', 'ape');
|
||||
break;
|
||||
|
||||
case 'mpc':
|
||||
$ValidTagTypes = ['ape'];
|
||||
$ValidTagTypes = array('ape');
|
||||
break;
|
||||
|
||||
case 'ogg':
|
||||
if (!empty($OldThisFileInfo['audio']['dataformat']) && ($OldThisFileInfo['audio']['dataformat'] == 'flac')) {
|
||||
//$ValidTagTypes = array('metaflac');
|
||||
// metaflac doesn't (yet) work with OggFLAC files
|
||||
$ValidTagTypes = [];
|
||||
$ValidTagTypes = array();
|
||||
} else {
|
||||
$ValidTagTypes = ['vorbiscomment'];
|
||||
$ValidTagTypes = array('vorbiscomment');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'flac':
|
||||
$ValidTagTypes = ['metaflac'];
|
||||
$ValidTagTypes = array('metaflac');
|
||||
break;
|
||||
|
||||
case 'real':
|
||||
$ValidTagTypes = ['real'];
|
||||
$ValidTagTypes = array('real');
|
||||
break;
|
||||
|
||||
default:
|
||||
$ValidTagTypes = [];
|
||||
$ValidTagTypes = array();
|
||||
break;
|
||||
}
|
||||
echo '<tr><td align="right"><b>Title</b></td> <td><input type="text" size="40" name="Title" value="'.htmlentities((!empty($OldThisFileInfo['comments']['title']) ? implode(', ', $OldThisFileInfo['comments']['title'] ) : ''), ENT_QUOTES).'"></td></tr>';
|
||||
|
@ -171,7 +179,7 @@ if (!empty($Filename)) {
|
|||
} elseif (!empty($OldThisFileInfo['comments']['track']) && is_array($OldThisFileInfo['comments']['track'])) {
|
||||
$RawTrackNumberArray = $OldThisFileInfo['comments']['track'];
|
||||
} else {
|
||||
$RawTrackNumberArray = [];
|
||||
$RawTrackNumberArray = array();
|
||||
}
|
||||
foreach ($RawTrackNumberArray as $key => $value) {
|
||||
if (strlen($value) > strlen($TrackNumber)) {
|
||||
|
@ -197,7 +205,7 @@ if (!empty($Filename)) {
|
|||
$ArrayOfGenres['Remix'] = '-Remix-';
|
||||
asort($ArrayOfGenres); // sort into alphabetical order
|
||||
echo '<tr><th align="right">Genre</th><td><select name="Genre">';
|
||||
$AllGenresArray = (!empty($OldThisFileInfo['comments']['genre']) ? $OldThisFileInfo['comments']['genre'] : []);
|
||||
$AllGenresArray = (!empty($OldThisFileInfo['comments']['genre']) ? $OldThisFileInfo['comments']['genre'] : array());
|
||||
foreach ($ArrayOfGenres as $key => $value) {
|
||||
echo '<option value="'.htmlentities($key, ENT_QUOTES).'"';
|
||||
if (in_array($key, $AllGenresArray)) {
|
||||
|
@ -249,11 +257,15 @@ if (!empty($Filename)) {
|
|||
echo '</select></td></tr>';
|
||||
echo '<tr><td align="center" colspan="2"><input type="submit" name="WriteTags" value="Save Changes"> ';
|
||||
echo '<input type="reset" value="Reset"></td></tr>';
|
||||
|
||||
} else {
|
||||
|
||||
echo '<tr><td align="right"><b>Error</b></td><td>'.htmlentities($Filename).' does not exist</td></tr>';
|
||||
|
||||
}
|
||||
echo '</table>';
|
||||
echo '</form>';
|
||||
|
||||
}
|
||||
|
||||
echo '</body></html>';
|
|
@ -13,10 +13,9 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
function UnzipFileContents($filename, &$errors)
|
||||
{
|
||||
$errors = [];
|
||||
$DecompressedFileContents = [];
|
||||
function UnzipFileContents($filename, &$errors) {
|
||||
$errors = array();
|
||||
$DecompressedFileContents = array();
|
||||
if (!class_exists('getID3')) {
|
||||
$errors[] = 'class getID3 not defined, please include getid3.php';
|
||||
} elseif (include_once('module.archive.zip.php')) {
|
||||
|
|
|
@ -48,8 +48,8 @@ $database['hide']=true;
|
|||
|
||||
*/
|
||||
$dir = $_SERVER['PWD'];
|
||||
$media = ['mp4', 'm4v', 'mov', 'mp3', 'm4a', 'jpg', 'png', 'gif'];
|
||||
$database = [];
|
||||
$media = array('mp4', 'm4v', 'mov', 'mp3', 'm4a', 'jpg', 'png', 'gif');
|
||||
$database = array();
|
||||
/**
|
||||
* configure the database bellow
|
||||
*/
|
||||
|
@ -81,8 +81,7 @@ require_once(dirname(__FILE__).'/getid3.php');
|
|||
*
|
||||
*/
|
||||
|
||||
class dirscan
|
||||
{
|
||||
class dirscan {
|
||||
/**
|
||||
* type_brace() * Might not work on Solaris and other non GNU systems *
|
||||
*
|
||||
|
@ -92,9 +91,8 @@ class dirscan
|
|||
* @param mixed cvs list of extentions or an array
|
||||
* @return string or null if checks fail
|
||||
*/
|
||||
private function type_brace($dir, $search = [])
|
||||
{
|
||||
$dir = str_replace(['///', '//'], ['/', '/'], $dir);
|
||||
private function type_brace($dir, $search=array()) {
|
||||
$dir = str_replace(array('///', '//'), array('/', '/'), $dir);
|
||||
if (!is_dir($dir)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -105,7 +103,7 @@ class dirscan
|
|||
} else {
|
||||
$e = $search;
|
||||
}
|
||||
$ext = [];
|
||||
$ext = array();
|
||||
foreach ($e as $new) {
|
||||
$ext[] = strtolower(trim($new));
|
||||
$ext[] = strtoupper(trim($new));
|
||||
|
@ -121,8 +119,7 @@ class dirscan
|
|||
* @return array return an array of dirs under root
|
||||
* @todo figure out how to block tabo directories with ease
|
||||
*/
|
||||
private function getDirs($root)
|
||||
{
|
||||
private function getDirs($root) {
|
||||
switch ($root) { // return null on tabo directories, add as needed -> case {dir to block }: this is not perfect yet
|
||||
case '/':
|
||||
case '/var':
|
||||
|
@ -146,7 +143,7 @@ class dirscan
|
|||
break;
|
||||
}
|
||||
if (count($dirs) < 1) {
|
||||
$dirs = [$root];
|
||||
$dirs = array($root);
|
||||
}
|
||||
return $dirs;
|
||||
}
|
||||
|
@ -157,12 +154,11 @@ class dirscan
|
|||
* @param string $search
|
||||
* @return mixed
|
||||
*/
|
||||
private function file_check($search)
|
||||
{
|
||||
$t = [];
|
||||
private function file_check($search) {
|
||||
$t = array();
|
||||
$s = glob($search, GLOB_BRACE);
|
||||
foreach ($s as $file) {
|
||||
$t[] = str_replace(['///', '//'], ['/', '/'], $file);
|
||||
$t[] = str_replace(array('///', '//'), array('/', '/'), $file);
|
||||
}
|
||||
if (count($t) > 0) {
|
||||
return $t;
|
||||
|
@ -170,8 +166,7 @@ class dirscan
|
|||
return null;
|
||||
}
|
||||
|
||||
function getTime()
|
||||
{
|
||||
function getTime() {
|
||||
return microtime(true);
|
||||
// old method for PHP < 5
|
||||
//$a = explode(' ', microtime());
|
||||
|
@ -186,8 +181,7 @@ class dirscan
|
|||
* @param type $cache caching extention, select one of sqlite3, mysql, dbm
|
||||
* @param array $opt database options,
|
||||
*/
|
||||
function scan_files($dir, $match, $cache = 'sqlite3', $opt = ['table'=>'getid3_cache', 'hide'=>true])
|
||||
{
|
||||
function scan_files($dir, $match, $cache='sqlite3', $opt=array('table'=>'getid3_cache', 'hide'=>true)) {
|
||||
$Start = self::getTime();
|
||||
switch ($cache) { // load the caching module
|
||||
case 'sqlite3':
|
||||
|
@ -213,7 +207,7 @@ class dirscan
|
|||
die(' You have selected an Invalid cache type, only "sqlite3" and "mysql" are valid'."\n");
|
||||
break;
|
||||
}
|
||||
$count = ['dir'=>0, 'file'=>0];
|
||||
$count = array('dir'=>0, 'file'=>0);
|
||||
$dirs = self::getDirs($dir);
|
||||
if ($dirs !== null) {
|
||||
foreach ($dirs as $d) {
|
||||
|
|
|
@ -74,8 +74,7 @@ class getID3_cached_dbm extends getID3
|
|||
{
|
||||
|
||||
// public: constructor - see top of this file for cache type and cache_options
|
||||
public function __construct($cache_type, $dbm_filename, $lock_filename)
|
||||
{
|
||||
public function __construct($cache_type, $dbm_filename, $lock_filename) {
|
||||
|
||||
// Check for dba extension
|
||||
if (!extension_loaded('dba')) {
|
||||
|
@ -113,6 +112,7 @@ class getID3_cached_dbm extends getID3
|
|||
// 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);
|
||||
|
||||
|
@ -129,7 +129,7 @@ class getID3_cached_dbm extends getID3
|
|||
$this->dbm_filename = $dbm_filename;
|
||||
|
||||
// Register destructor
|
||||
register_shutdown_function([$this, '__destruct']);
|
||||
register_shutdown_function(array($this, '__destruct'));
|
||||
|
||||
// Check version number and clear cache if changed
|
||||
if (dba_fetch(getID3::VERSION, $this->dba) != getID3::VERSION) {
|
||||
|
@ -142,8 +142,7 @@ class getID3_cached_dbm extends getID3
|
|||
|
||||
|
||||
// public: destructor
|
||||
public function __destruct()
|
||||
{
|
||||
public function __destruct() {
|
||||
|
||||
// Close dbm file
|
||||
dba_close($this->dba);
|
||||
|
@ -158,8 +157,7 @@ class getID3_cached_dbm extends getID3
|
|||
|
||||
|
||||
// public: clear cache
|
||||
public function clear_cache()
|
||||
{
|
||||
public function clear_cache() {
|
||||
|
||||
// Close dbm file
|
||||
dba_close($this->dba);
|
||||
|
@ -175,16 +173,16 @@ class getID3_cached_dbm extends getID3
|
|||
dba_insert(getID3::VERSION, getID3::VERSION, $this->dba);
|
||||
|
||||
// Re-register shutdown function
|
||||
register_shutdown_function([$this, '__destruct']);
|
||||
register_shutdown_function(array($this, '__destruct'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// public: analyze file
|
||||
public function analyze($filename)
|
||||
{
|
||||
public function analyze($filename) {
|
||||
|
||||
if (file_exists($filename)) {
|
||||
|
||||
// Calc key filename::mod_time::size - should be unique
|
||||
$key = $filename.'::'.filemtime($filename).'::'.filesize($filename);
|
||||
|
||||
|
@ -207,4 +205,5 @@ class getID3_cached_dbm extends getID3
|
|||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -80,8 +80,7 @@ class getID3_cached_mysql extends getID3
|
|||
|
||||
|
||||
// public: constructor - see top of this file for cache type and cache_options
|
||||
public function __construct($host, $database, $username, $password, $table = 'getid3_cache')
|
||||
{
|
||||
public function __construct($host, $database, $username, $password, $table='getid3_cache') {
|
||||
|
||||
// Check for mysql support
|
||||
if (!function_exists('mysql_pconnect')) {
|
||||
|
@ -126,8 +125,7 @@ class getID3_cached_mysql extends getID3
|
|||
|
||||
|
||||
// public: clear cache
|
||||
public function clear_cache()
|
||||
{
|
||||
public function clear_cache() {
|
||||
|
||||
$this->cursor = mysql_query('DELETE FROM `'.mysql_real_escape_string($this->table).'`', $this->connection);
|
||||
$this->cursor = mysql_query('INSERT INTO `'.mysql_real_escape_string($this->table).'` VALUES (\''.getID3::VERSION.'\', -1, -1, -1, \''.getID3::VERSION.'\')', $this->connection);
|
||||
|
@ -136,10 +134,10 @@ class getID3_cached_mysql extends getID3
|
|||
|
||||
|
||||
// public: analyze file
|
||||
public function analyze($filename, $filesize = null, $original_filename = '')
|
||||
{
|
||||
public function analyze($filename, $filesize=null, $original_filename='') {
|
||||
|
||||
if (file_exists($filename)) {
|
||||
|
||||
// Short-hands
|
||||
$filetime = filemtime($filename);
|
||||
$filesize = filesize($filename);
|
||||
|
@ -177,16 +175,15 @@ class getID3_cached_mysql extends getID3
|
|||
|
||||
|
||||
// private: (re)create sql table
|
||||
private function create_table($drop = false)
|
||||
{
|
||||
private function create_table($drop=false) {
|
||||
|
||||
$SQLquery = 'CREATE TABLE IF NOT EXISTS `'.mysql_real_escape_string($this->table).'` (';
|
||||
$SQLquery .= '`filename` VARCHAR(500) NOT NULL DEFAULT \'\'';
|
||||
$SQLquery .= '`filename` VARCHAR(990) NOT NULL DEFAULT \'\'';
|
||||
$SQLquery .= ', `filesize` INT(11) NOT NULL DEFAULT \'0\'';
|
||||
$SQLquery .= ', `filetime` INT(11) NOT NULL DEFAULT \'0\'';
|
||||
$SQLquery .= ', `analyzetime` INT(11) NOT NULL DEFAULT \'0\'';
|
||||
$SQLquery .= ', `value` LONGTEXT NOT NULL';
|
||||
$SQLquery .= ', PRIMARY KEY (`filename`, `filesize`, `filetime`)) ENGINE=MyISAM';
|
||||
$SQLquery .= ', PRIMARY KEY (`filename`, `filesize`, `filetime`)) ENGINE=MyISAM CHARACTER SET=latin1 COLLATE=latin1_general_ci';
|
||||
$this->cursor = mysql_query($SQLquery, $this->connection);
|
||||
echo mysql_error($this->connection);
|
||||
}
|
||||
|
|
183
app/Library/getid3/getid3/extension.cache.mysqli.php
Normal file
183
app/Library/getid3/getid3/extension.cache.mysqli.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 //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// extension.cache.mysqli.php - part of getID3() //
|
||||
// Please see readme.txt for more information //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// This extension written by Allan Hansen <ahØartemis*dk> //
|
||||
// Table name mod by Carlo Capocasa <calroØcarlocapocasa*com> //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* This is a caching extension for getID3(). It works the exact same
|
||||
* way as the getID3 class, but return cached information very fast
|
||||
*
|
||||
* Example: (see also demo.cache.mysql.php in /demo/)
|
||||
*
|
||||
* Normal getID3 usage (example):
|
||||
*
|
||||
* require_once 'getid3/getid3.php';
|
||||
* $getID3 = new getID3;
|
||||
* $getID3->encoding = 'UTF-8';
|
||||
* $info1 = $getID3->analyze('file1.flac');
|
||||
* $info2 = $getID3->analyze('file2.wv');
|
||||
*
|
||||
* getID3_cached usage:
|
||||
*
|
||||
* require_once 'getid3/getid3.php';
|
||||
* require_once 'getid3/getid3/extension.cache.mysqli.php';
|
||||
* // 5th parameter (tablename) is optional, default is 'getid3_cache'
|
||||
* $getID3 = new getID3_cached_mysqli('localhost', 'database', 'username', 'password', 'tablename');
|
||||
* $getID3->encoding = 'UTF-8';
|
||||
* $info1 = $getID3->analyze('file1.flac');
|
||||
* $info2 = $getID3->analyze('file2.wv');
|
||||
*
|
||||
*
|
||||
* Supported Cache Types (this extension)
|
||||
*
|
||||
* SQL Databases:
|
||||
*
|
||||
* cache_type cache_options
|
||||
* -------------------------------------------------------------------
|
||||
* mysqli host, database, username, password
|
||||
*
|
||||
*
|
||||
* DBM-Style Databases: (use extension.cache.dbm)
|
||||
*
|
||||
* cache_type cache_options
|
||||
* -------------------------------------------------------------------
|
||||
* gdbm dbm_filename, lock_filename
|
||||
* ndbm dbm_filename, lock_filename
|
||||
* db2 dbm_filename, lock_filename
|
||||
* db3 dbm_filename, lock_filename
|
||||
* db4 dbm_filename, lock_filename (PHP5 required)
|
||||
*
|
||||
* PHP must have write access to both dbm_filename and lock_filename.
|
||||
*
|
||||
*
|
||||
* Recommended Cache Types
|
||||
*
|
||||
* Infrequent updates, many reads any DBM
|
||||
* Frequent updates mysqli
|
||||
*/
|
||||
|
||||
class getID3_cached_mysqli extends getID3
|
||||
{
|
||||
// private vars
|
||||
private $mysqli;
|
||||
private $cursor;
|
||||
|
||||
|
||||
// public: constructor - see top of this file for cache type and cache_options
|
||||
public function __construct($host, $database, $username, $password, $table='getid3_cache') {
|
||||
|
||||
// Check for mysqli support
|
||||
if (!function_exists('mysqli_connect')) {
|
||||
throw new Exception('PHP not compiled with mysqli support.');
|
||||
}
|
||||
|
||||
// Connect to database
|
||||
$this->mysqli = new mysqli($host, $username, $password);
|
||||
if (!$this->mysqli) {
|
||||
throw new Exception('mysqli_connect() failed - check permissions and spelling.');
|
||||
}
|
||||
|
||||
// Select database
|
||||
if (!$this->mysqli->select_db($database)) {
|
||||
throw new Exception('Cannot use database '.$database);
|
||||
}
|
||||
|
||||
// Set table
|
||||
$this->table = $table;
|
||||
|
||||
// Create cache table if not exists
|
||||
$this->create_table();
|
||||
|
||||
// Check version number and clear cache if changed
|
||||
$version = '';
|
||||
$SQLquery = 'SELECT `value`';
|
||||
$SQLquery .= ' FROM `'.$this->mysqli->real_escape_string($this->table).'`';
|
||||
$SQLquery .= ' WHERE (`filename` = \''.$this->mysqli->real_escape_string(getID3::VERSION).'\')';
|
||||
$SQLquery .= ' AND (`filesize` = -1)';
|
||||
$SQLquery .= ' AND (`filetime` = -1)';
|
||||
$SQLquery .= ' AND (`analyzetime` = -1)';
|
||||
if ($this->cursor = $this->mysqli->query($SQLquery)) {
|
||||
list($version) = $this->cursor->fetch_array();
|
||||
}
|
||||
if ($version != getID3::VERSION) {
|
||||
$this->clear_cache();
|
||||
}
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
||||
// public: clear cache
|
||||
public function clear_cache() {
|
||||
$this->mysqli->query('DELETE FROM `'.$this->mysqli->real_escape_string($this->table).'`');
|
||||
$this->mysqli->query('INSERT INTO `'.$this->mysqli->real_escape_string($this->table).'` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (\''.getID3::VERSION.'\', -1, -1, -1, \''.getID3::VERSION.'\')');
|
||||
}
|
||||
|
||||
|
||||
// public: analyze file
|
||||
public function analyze($filename, $filesize=null, $original_filename='') {
|
||||
|
||||
if (file_exists($filename)) {
|
||||
|
||||
// Short-hands
|
||||
$filetime = filemtime($filename);
|
||||
$filesize = filesize($filename);
|
||||
|
||||
// Lookup file
|
||||
$SQLquery = 'SELECT `value`';
|
||||
$SQLquery .= ' FROM `'.$this->mysqli->real_escape_string($this->table).'`';
|
||||
$SQLquery .= ' WHERE (`filename` = \''.$this->mysqli->real_escape_string($filename).'\')';
|
||||
$SQLquery .= ' AND (`filesize` = \''.$this->mysqli->real_escape_string($filesize).'\')';
|
||||
$SQLquery .= ' AND (`filetime` = \''.$this->mysqli->real_escape_string($filetime).'\')';
|
||||
$this->cursor = $this->mysqli->query($SQLquery);
|
||||
if ($this->cursor->num_rows > 0) {
|
||||
// Hit
|
||||
list($result) = $this->cursor->fetch_array();
|
||||
return unserialize(base64_decode($result));
|
||||
}
|
||||
}
|
||||
|
||||
// Miss
|
||||
$analysis = parent::analyze($filename, $filesize, $original_filename);
|
||||
|
||||
// Save result
|
||||
if (file_exists($filename)) {
|
||||
$SQLquery = 'INSERT INTO `'.$this->mysqli->real_escape_string($this->table).'` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (';
|
||||
$SQLquery .= '\''.$this->mysqli->real_escape_string($filename).'\'';
|
||||
$SQLquery .= ', \''.$this->mysqli->real_escape_string($filesize).'\'';
|
||||
$SQLquery .= ', \''.$this->mysqli->real_escape_string($filetime).'\'';
|
||||
$SQLquery .= ', \''.$this->mysqli->real_escape_string(time() ).'\'';
|
||||
$SQLquery .= ', \''.$this->mysqli->real_escape_string(base64_encode(serialize($analysis))).'\')';
|
||||
$this->cursor = $this->mysqli->query($SQLquery);
|
||||
}
|
||||
return $analysis;
|
||||
}
|
||||
|
||||
|
||||
// private: (re)create mysqli table
|
||||
private function create_table($drop=false) {
|
||||
$SQLquery = 'CREATE TABLE IF NOT EXISTS `'.$this->mysqli->real_escape_string($this->table).'` (';
|
||||
$SQLquery .= '`filename` VARCHAR(990) NOT NULL DEFAULT \'\'';
|
||||
$SQLquery .= ', `filesize` INT(11) NOT NULL DEFAULT \'0\'';
|
||||
$SQLquery .= ', `filetime` INT(11) NOT NULL DEFAULT \'0\'';
|
||||
$SQLquery .= ', `analyzetime` INT(11) NOT NULL DEFAULT \'0\'';
|
||||
$SQLquery .= ', `value` LONGTEXT NOT NULL';
|
||||
$SQLquery .= ', PRIMARY KEY (`filename`, `filesize`, `filetime`)) ENGINE=MyISAM CHARACTER SET=latin1 COLLATE=latin1_general_ci';
|
||||
$this->cursor = $this->mysqli->query($SQLquery);
|
||||
echo $this->mysqli->error;
|
||||
}
|
||||
}
|
|
@ -89,16 +89,14 @@
|
|||
*
|
||||
*
|
||||
*/
|
||||
class getID3_cached_sqlite3 extends getID3
|
||||
{
|
||||
class getID3_cached_sqlite3 extends getID3 {
|
||||
|
||||
/**
|
||||
* __construct()
|
||||
* @param string $table holds name of sqlite table
|
||||
* @return type
|
||||
*/
|
||||
public function __construct($table = 'getid3_cache', $hide = false)
|
||||
{
|
||||
public function __construct($table='getid3_cache', $hide=false) {
|
||||
$this->table = $table; // Set table
|
||||
$file = dirname(__FILE__).'/'.basename(__FILE__, 'php').'sqlite';
|
||||
if ($hide) {
|
||||
|
@ -122,8 +120,7 @@ class getID3_cached_sqlite3 extends getID3
|
|||
/**
|
||||
* close the database connection
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
public function __destruct() {
|
||||
$db=$this->db;
|
||||
$db->close();
|
||||
}
|
||||
|
@ -145,8 +142,7 @@ class getID3_cached_sqlite3 extends getID3
|
|||
* @access private
|
||||
* @return type
|
||||
*/
|
||||
private function clear_cache()
|
||||
{
|
||||
private function clear_cache() {
|
||||
$db = $this->db;
|
||||
$sql = $this->delete_cache;
|
||||
$db->exec($sql);
|
||||
|
@ -163,8 +159,7 @@ class getID3_cached_sqlite3 extends getID3
|
|||
* @param type $filename
|
||||
* @return boolean
|
||||
*/
|
||||
public function analyze($filename, $filesize = null, $original_filename = '')
|
||||
{
|
||||
public function analyze($filename, $filesize=null, $original_filename='') {
|
||||
if (!file_exists($filename)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -206,8 +201,7 @@ class getID3_cached_sqlite3 extends getID3
|
|||
* this is almost the same as MySQL, with the exception of the dirname being added
|
||||
* @return type
|
||||
*/
|
||||
private function create_table()
|
||||
{
|
||||
private function create_table() {
|
||||
$db = $this->db;
|
||||
$sql = $this->make_table;
|
||||
return $db->exec($sql);
|
||||
|
@ -223,10 +217,9 @@ class getID3_cached_sqlite3 extends getID3
|
|||
* @param string $dir directory to search the cache database for
|
||||
* @return array return an array of matching id3 data
|
||||
*/
|
||||
public function get_cached_dir($dir)
|
||||
{
|
||||
public function get_cached_dir($dir) {
|
||||
$db = $this->db;
|
||||
$rows = [];
|
||||
$rows = array();
|
||||
$sql = $this->get_cached_dir;
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->bindValue(':dirname', $dir, SQLITE3_TEXT);
|
||||
|
@ -242,8 +235,7 @@ class getID3_cached_sqlite3 extends getID3
|
|||
*
|
||||
* access as easy as $this->{case name}, returns NULL if query is not found
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
public function __get($name) {
|
||||
switch($name) {
|
||||
case 'version_check':
|
||||
return "SELECT val FROM $this->table WHERE filename = :filename AND filesize = '-1' AND filetime = '-1' AND analyzetime = '-1'";
|
||||
|
@ -270,4 +262,5 @@ class getID3_cached_sqlite3 extends getID3
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
class getid3_lib
|
||||
{
|
||||
|
||||
public static function PrintHexBytes($string, $hex = true, $spaces = true, $htmlencoding = 'UTF-8')
|
||||
{
|
||||
public static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') {
|
||||
$returnstring = '';
|
||||
for ($i = 0; $i < strlen($string); $i++) {
|
||||
if ($hex) {
|
||||
|
@ -37,8 +36,7 @@ class getid3_lib
|
|||
return $returnstring;
|
||||
}
|
||||
|
||||
public static function trunc($floatnumber)
|
||||
{
|
||||
public static function trunc($floatnumber) {
|
||||
// truncates a floating-point number at the decimal point
|
||||
// returns int (if possible, otherwise float)
|
||||
if ($floatnumber >= 1) {
|
||||
|
@ -55,8 +53,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function safe_inc(&$variable, $increment = 1)
|
||||
{
|
||||
public static function safe_inc(&$variable, $increment=1) {
|
||||
if (isset($variable)) {
|
||||
$variable += $increment;
|
||||
} else {
|
||||
|
@ -65,8 +62,7 @@ class getid3_lib
|
|||
return true;
|
||||
}
|
||||
|
||||
public static function CastAsInt($floatnum)
|
||||
{
|
||||
public static function CastAsInt($floatnum) {
|
||||
// convert to float if not already
|
||||
$floatnum = (float) $floatnum;
|
||||
|
||||
|
@ -81,8 +77,7 @@ class getid3_lib
|
|||
return $floatnum;
|
||||
}
|
||||
|
||||
public static function intValueSupported($num)
|
||||
{
|
||||
public static function intValueSupported($num) {
|
||||
// check if integers are 64-bit
|
||||
static $hasINT64 = null;
|
||||
if ($hasINT64 === null) { // 10x faster than is_null()
|
||||
|
@ -98,23 +93,20 @@ class getid3_lib
|
|||
return false;
|
||||
}
|
||||
|
||||
public static function DecimalizeFraction($fraction)
|
||||
{
|
||||
public static function DecimalizeFraction($fraction) {
|
||||
list($numerator, $denominator) = explode('/', $fraction);
|
||||
return $numerator / ($denominator ? $denominator : 1);
|
||||
}
|
||||
|
||||
|
||||
public static function DecimalBinary2Float($binarynumerator)
|
||||
{
|
||||
public static function DecimalBinary2Float($binarynumerator) {
|
||||
$numerator = self::Bin2Dec($binarynumerator);
|
||||
$denominator = self::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator)));
|
||||
return ($numerator / $denominator);
|
||||
}
|
||||
|
||||
|
||||
public static function NormalizeBinaryPoint($binarypointnumber, $maxbits = 52)
|
||||
{
|
||||
public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) {
|
||||
// http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
|
||||
if (strpos($binarypointnumber, '.') === false) {
|
||||
$binarypointnumber = '0.'.$binarypointnumber;
|
||||
|
@ -134,12 +126,11 @@ class getid3_lib
|
|||
}
|
||||
}
|
||||
$binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT);
|
||||
return ['normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent];
|
||||
return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent);
|
||||
}
|
||||
|
||||
|
||||
public static function Float2BinaryDecimal($floatvalue)
|
||||
{
|
||||
public static function Float2BinaryDecimal($floatvalue) {
|
||||
// http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
|
||||
$maxbits = 128; // to how many bits of precision should the calculations be taken?
|
||||
$intpart = self::trunc($floatvalue);
|
||||
|
@ -155,8 +146,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function Float2String($floatvalue, $bits)
|
||||
{
|
||||
public static function Float2String($floatvalue, $bits) {
|
||||
// http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
|
||||
switch ($bits) {
|
||||
case 32:
|
||||
|
@ -187,14 +177,12 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function LittleEndian2Float($byteword)
|
||||
{
|
||||
public static function LittleEndian2Float($byteword) {
|
||||
return self::BigEndian2Float(strrev($byteword));
|
||||
}
|
||||
|
||||
|
||||
public static function BigEndian2Float($byteword)
|
||||
{
|
||||
public static function BigEndian2Float($byteword) {
|
||||
// ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
|
||||
// http://www.psc.edu/general/software/packages/ieee/ieee.html
|
||||
// http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
|
||||
|
@ -272,8 +260,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function BigEndian2Int($byteword, $synchsafe = false, $signed = false)
|
||||
{
|
||||
public static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) {
|
||||
$intvalue = 0;
|
||||
$bytewordlen = strlen($byteword);
|
||||
if ($bytewordlen == 0) {
|
||||
|
@ -302,14 +289,12 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function LittleEndian2Int($byteword, $signed = false)
|
||||
{
|
||||
public static function LittleEndian2Int($byteword, $signed=false) {
|
||||
return self::BigEndian2Int(strrev($byteword), false, $signed);
|
||||
}
|
||||
|
||||
|
||||
public static function BigEndian2Bin($byteword)
|
||||
{
|
||||
public static function BigEndian2Bin($byteword) {
|
||||
$binvalue = '';
|
||||
$bytewordlen = strlen($byteword);
|
||||
for ($i = 0; $i < $bytewordlen; $i++) {
|
||||
|
@ -319,8 +304,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function BigEndian2String($number, $minbytes = 1, $synchsafe = false, $signed = false)
|
||||
{
|
||||
public static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) {
|
||||
if ($number < 0) {
|
||||
throw new Exception('ERROR: self::BigEndian2String() does not support negative numbers');
|
||||
}
|
||||
|
@ -341,8 +325,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function Dec2Bin($number)
|
||||
{
|
||||
public static function Dec2Bin($number) {
|
||||
while ($number >= 256) {
|
||||
$bytes[] = (($number / 256) - (floor($number / 256))) * 256;
|
||||
$number = floor($number / 256);
|
||||
|
@ -356,8 +339,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function Bin2Dec($binstring, $signed = false)
|
||||
{
|
||||
public static function Bin2Dec($binstring, $signed=false) {
|
||||
$signmult = 1;
|
||||
if ($signed) {
|
||||
if ($binstring{0} == '1') {
|
||||
|
@ -373,8 +355,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function Bin2String($binstring)
|
||||
{
|
||||
public static function Bin2String($binstring) {
|
||||
// return 'hi' for input of '0110100001101001'
|
||||
$string = '';
|
||||
$binstringreversed = strrev($binstring);
|
||||
|
@ -385,8 +366,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function LittleEndian2String($number, $minbytes = 1, $synchsafe = false)
|
||||
{
|
||||
public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
|
||||
$intstring = '';
|
||||
while ($number > 0) {
|
||||
if ($synchsafe) {
|
||||
|
@ -401,8 +381,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function array_merge_clobber($array1, $array2)
|
||||
{
|
||||
public static function array_merge_clobber($array1, $array2) {
|
||||
// written by kcØhireability*com
|
||||
// taken from http://www.php.net/manual/en/function.array-merge-recursive.php
|
||||
if (!is_array($array1) || !is_array($array2)) {
|
||||
|
@ -420,8 +399,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function array_merge_noclobber($array1, $array2)
|
||||
{
|
||||
public static function array_merge_noclobber($array1, $array2) {
|
||||
if (!is_array($array1) || !is_array($array2)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -436,8 +414,7 @@ class getid3_lib
|
|||
return $newarray;
|
||||
}
|
||||
|
||||
public static function flipped_array_merge_noclobber($array1, $array2)
|
||||
{
|
||||
public static function flipped_array_merge_noclobber($array1, $array2) {
|
||||
if (!is_array($array1) || !is_array($array2)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -452,8 +429,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function ksort_recursive(&$theArray)
|
||||
{
|
||||
public static function ksort_recursive(&$theArray) {
|
||||
ksort($theArray);
|
||||
foreach ($theArray as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
|
@ -463,8 +439,7 @@ class getid3_lib
|
|||
return true;
|
||||
}
|
||||
|
||||
public static function fileextension($filename, $numextensions = 1)
|
||||
{
|
||||
public static function fileextension($filename, $numextensions=1) {
|
||||
if (strstr($filename, '.')) {
|
||||
$reversedfilename = strrev($filename);
|
||||
$offset = 0;
|
||||
|
@ -480,8 +455,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function PlaytimeString($seconds)
|
||||
{
|
||||
public static function PlaytimeString($seconds) {
|
||||
$sign = (($seconds < 0) ? '-' : '');
|
||||
$seconds = round(abs($seconds));
|
||||
$H = (int) floor( $seconds / 3600);
|
||||
|
@ -491,35 +465,30 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function DateMac2Unix($macdate)
|
||||
{
|
||||
public static function DateMac2Unix($macdate) {
|
||||
// Macintosh timestamp: seconds since 00:00h January 1, 1904
|
||||
// UNIX timestamp: seconds since 00:00h January 1, 1970
|
||||
return self::CastAsInt($macdate - 2082844800);
|
||||
}
|
||||
|
||||
|
||||
public static function FixedPoint8_8($rawdata)
|
||||
{
|
||||
public static function FixedPoint8_8($rawdata) {
|
||||
return self::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (self::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8));
|
||||
}
|
||||
|
||||
|
||||
public static function FixedPoint16_16($rawdata)
|
||||
{
|
||||
public static function FixedPoint16_16($rawdata) {
|
||||
return self::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (self::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16));
|
||||
}
|
||||
|
||||
|
||||
public static function FixedPoint2_30($rawdata)
|
||||
{
|
||||
public static function FixedPoint2_30($rawdata) {
|
||||
$binarystring = self::BigEndian2Bin($rawdata);
|
||||
return self::Bin2Dec(substr($binarystring, 0, 2)) + (float) (self::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30));
|
||||
}
|
||||
|
||||
|
||||
public static function CreateDeepArray($ArrayPath, $Separator, $Value)
|
||||
{
|
||||
public static function CreateDeepArray($ArrayPath, $Separator, $Value) {
|
||||
// assigns $Value to a nested array path:
|
||||
// $foo = self::CreateDeepArray('/path/to/my', '/', 'file.txt')
|
||||
// is the same as:
|
||||
|
@ -535,8 +504,7 @@ class getid3_lib
|
|||
return $ReturnedArray;
|
||||
}
|
||||
|
||||
public static function array_max($arraydata, $returnkey = false)
|
||||
{
|
||||
public static function array_max($arraydata, $returnkey=false) {
|
||||
$maxvalue = false;
|
||||
$maxkey = false;
|
||||
foreach ($arraydata as $key => $value) {
|
||||
|
@ -550,8 +518,7 @@ class getid3_lib
|
|||
return ($returnkey ? $maxkey : $maxvalue);
|
||||
}
|
||||
|
||||
public static function array_min($arraydata, $returnkey = false)
|
||||
{
|
||||
public static function array_min($arraydata, $returnkey=false) {
|
||||
$minvalue = false;
|
||||
$minkey = false;
|
||||
foreach ($arraydata as $key => $value) {
|
||||
|
@ -565,8 +532,7 @@ class getid3_lib
|
|||
return ($returnkey ? $minkey : $minvalue);
|
||||
}
|
||||
|
||||
public static function XML2array($XMLstring)
|
||||
{
|
||||
public static function XML2array($XMLstring) {
|
||||
if (function_exists('simplexml_load_string') && function_exists('libxml_disable_entity_loader')) {
|
||||
// http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html
|
||||
// https://core.trac.wordpress.org/changeset/29378
|
||||
|
@ -579,8 +545,7 @@ class getid3_lib
|
|||
return false;
|
||||
}
|
||||
|
||||
public static function SimpleXMLelement2array($XMLobject)
|
||||
{
|
||||
public static function SimpleXMLelement2array($XMLobject) {
|
||||
if (!is_object($XMLobject) && !is_array($XMLobject)) {
|
||||
return $XMLobject;
|
||||
}
|
||||
|
@ -594,8 +559,7 @@ class getid3_lib
|
|||
|
||||
// Allan Hansen <ahØartemis*dk>
|
||||
// self::md5_data() - returns md5sum for a file from startuing position to absolute end position
|
||||
public static function hash_data($file, $offset, $end, $algorithm)
|
||||
{
|
||||
public static function hash_data($file, $offset, $end, $algorithm) {
|
||||
static $tempdir = '';
|
||||
if (!self::intValueSupported($end)) {
|
||||
return false;
|
||||
|
@ -622,13 +586,14 @@ class getid3_lib
|
|||
$size = $end - $offset;
|
||||
while (true) {
|
||||
if (GETID3_OS_ISWINDOWS) {
|
||||
|
||||
// It seems that sha1sum.exe for Windows only works on physical files, does not accept piped data
|
||||
// Fall back to create-temp-file method:
|
||||
if ($algorithm == 'sha1') {
|
||||
break;
|
||||
}
|
||||
|
||||
$RequiredFiles = ['cygwin1.dll', 'head.exe', 'tail.exe', $windows_call];
|
||||
$RequiredFiles = array('cygwin1.dll', 'head.exe', 'tail.exe', $windows_call);
|
||||
foreach ($RequiredFiles as $required_file) {
|
||||
if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) {
|
||||
// helper apps not available - fall back to old method
|
||||
|
@ -638,10 +603,13 @@ class getid3_lib
|
|||
$commandline = GETID3_HELPERAPPSDIR.'head.exe -c '.$end.' '.escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $file)).' | ';
|
||||
$commandline .= GETID3_HELPERAPPSDIR.'tail.exe -c '.$size.' | ';
|
||||
$commandline .= GETID3_HELPERAPPSDIR.$windows_call;
|
||||
|
||||
} else {
|
||||
|
||||
$commandline = 'head -c'.$end.' '.escapeshellarg($file).' | ';
|
||||
$commandline .= 'tail -c'.$size.' | ';
|
||||
$commandline .= $unix_call;
|
||||
|
||||
}
|
||||
if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
|
||||
//throw new Exception('PHP running in Safe Mode - backtick operator not available, using slower non-system-call '.$algorithm.' algorithm');
|
||||
|
@ -677,8 +645,7 @@ class getid3_lib
|
|||
return $result;
|
||||
}
|
||||
|
||||
public static function CopyFileParts($filename_source, $filename_dest, $offset, $length)
|
||||
{
|
||||
public static function CopyFileParts($filename_source, $filename_dest, $offset, $length) {
|
||||
if (!self::intValueSupported($offset + $length)) {
|
||||
throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit');
|
||||
}
|
||||
|
@ -705,8 +672,7 @@ class getid3_lib
|
|||
return false;
|
||||
}
|
||||
|
||||
public static function iconv_fallback_int_utf8($charval)
|
||||
{
|
||||
public static function iconv_fallback_int_utf8($charval) {
|
||||
if ($charval < 128) {
|
||||
// 0bbbbbbb
|
||||
$newcharstring = chr($charval);
|
||||
|
@ -730,8 +696,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
// ISO-8859-1 => UTF-8
|
||||
public static function iconv_fallback_iso88591_utf8($string, $bom = false)
|
||||
{
|
||||
public static function iconv_fallback_iso88591_utf8($string, $bom=false) {
|
||||
if (function_exists('utf8_encode')) {
|
||||
return utf8_encode($string);
|
||||
}
|
||||
|
@ -748,8 +713,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
// ISO-8859-1 => UTF-16BE
|
||||
public static function iconv_fallback_iso88591_utf16be($string, $bom = false)
|
||||
{
|
||||
public static function iconv_fallback_iso88591_utf16be($string, $bom=false) {
|
||||
$newcharstring = '';
|
||||
if ($bom) {
|
||||
$newcharstring .= "\xFE\xFF";
|
||||
|
@ -761,8 +725,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
// ISO-8859-1 => UTF-16LE
|
||||
public static function iconv_fallback_iso88591_utf16le($string, $bom = false)
|
||||
{
|
||||
public static function iconv_fallback_iso88591_utf16le($string, $bom=false) {
|
||||
$newcharstring = '';
|
||||
if ($bom) {
|
||||
$newcharstring .= "\xFF\xFE";
|
||||
|
@ -774,14 +737,12 @@ class getid3_lib
|
|||
}
|
||||
|
||||
// ISO-8859-1 => UTF-16LE (BOM)
|
||||
public static function iconv_fallback_iso88591_utf16($string)
|
||||
{
|
||||
public static function iconv_fallback_iso88591_utf16($string) {
|
||||
return self::iconv_fallback_iso88591_utf16le($string, true);
|
||||
}
|
||||
|
||||
// UTF-8 => ISO-8859-1
|
||||
public static function iconv_fallback_utf8_iso88591($string)
|
||||
{
|
||||
public static function iconv_fallback_utf8_iso88591($string) {
|
||||
if (function_exists('utf8_decode')) {
|
||||
return utf8_decode($string);
|
||||
}
|
||||
|
@ -825,8 +786,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
// UTF-8 => UTF-16BE
|
||||
public static function iconv_fallback_utf8_utf16be($string, $bom = false)
|
||||
{
|
||||
public static function iconv_fallback_utf8_utf16be($string, $bom=false) {
|
||||
$newcharstring = '';
|
||||
if ($bom) {
|
||||
$newcharstring .= "\xFE\xFF";
|
||||
|
@ -869,8 +829,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
// UTF-8 => UTF-16LE
|
||||
public static function iconv_fallback_utf8_utf16le($string, $bom = false)
|
||||
{
|
||||
public static function iconv_fallback_utf8_utf16le($string, $bom=false) {
|
||||
$newcharstring = '';
|
||||
if ($bom) {
|
||||
$newcharstring .= "\xFF\xFE";
|
||||
|
@ -913,14 +872,12 @@ class getid3_lib
|
|||
}
|
||||
|
||||
// UTF-8 => UTF-16LE (BOM)
|
||||
public static function iconv_fallback_utf8_utf16($string)
|
||||
{
|
||||
public static function iconv_fallback_utf8_utf16($string) {
|
||||
return self::iconv_fallback_utf8_utf16le($string, true);
|
||||
}
|
||||
|
||||
// UTF-16BE => UTF-8
|
||||
public static function iconv_fallback_utf16be_utf8($string)
|
||||
{
|
||||
public static function iconv_fallback_utf16be_utf8($string) {
|
||||
if (substr($string, 0, 2) == "\xFE\xFF") {
|
||||
// strip BOM
|
||||
$string = substr($string, 2);
|
||||
|
@ -934,8 +891,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
// UTF-16LE => UTF-8
|
||||
public static function iconv_fallback_utf16le_utf8($string)
|
||||
{
|
||||
public static function iconv_fallback_utf16le_utf8($string) {
|
||||
if (substr($string, 0, 2) == "\xFF\xFE") {
|
||||
// strip BOM
|
||||
$string = substr($string, 2);
|
||||
|
@ -949,8 +905,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
// UTF-16BE => ISO-8859-1
|
||||
public static function iconv_fallback_utf16be_iso88591($string)
|
||||
{
|
||||
public static function iconv_fallback_utf16be_iso88591($string) {
|
||||
if (substr($string, 0, 2) == "\xFE\xFF") {
|
||||
// strip BOM
|
||||
$string = substr($string, 2);
|
||||
|
@ -964,8 +919,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
// UTF-16LE => ISO-8859-1
|
||||
public static function iconv_fallback_utf16le_iso88591($string)
|
||||
{
|
||||
public static function iconv_fallback_utf16le_iso88591($string) {
|
||||
if (substr($string, 0, 2) == "\xFF\xFE") {
|
||||
// strip BOM
|
||||
$string = substr($string, 2);
|
||||
|
@ -979,8 +933,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
// UTF-16 (BOM) => ISO-8859-1
|
||||
public static function iconv_fallback_utf16_iso88591($string)
|
||||
{
|
||||
public static function iconv_fallback_utf16_iso88591($string) {
|
||||
$bom = substr($string, 0, 2);
|
||||
if ($bom == "\xFE\xFF") {
|
||||
return self::iconv_fallback_utf16be_iso88591(substr($string, 2));
|
||||
|
@ -991,8 +944,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
// UTF-16 (BOM) => UTF-8
|
||||
public static function iconv_fallback_utf16_utf8($string)
|
||||
{
|
||||
public static function iconv_fallback_utf16_utf8($string) {
|
||||
$bom = substr($string, 0, 2);
|
||||
if ($bom == "\xFE\xFF") {
|
||||
return self::iconv_fallback_utf16be_utf8(substr($string, 2));
|
||||
|
@ -1002,15 +954,26 @@ class getid3_lib
|
|||
return $string;
|
||||
}
|
||||
|
||||
public static function iconv_fallback($in_charset, $out_charset, $string)
|
||||
{
|
||||
public static function iconv_fallback($in_charset, $out_charset, $string) {
|
||||
|
||||
if ($in_charset == $out_charset) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
// mb_convert_encoding() availble
|
||||
if (function_exists('mb_convert_encoding')) {
|
||||
if ($converted_string = @mb_convert_encoding($string, $out_charset, $in_charset)) {
|
||||
switch ($out_charset) {
|
||||
case 'ISO-8859-1':
|
||||
$converted_string = rtrim($converted_string, "\x00");
|
||||
break;
|
||||
}
|
||||
return $converted_string;
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
// iconv() availble
|
||||
if (function_exists('iconv')) {
|
||||
else if (function_exists('iconv')) {
|
||||
if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) {
|
||||
switch ($out_charset) {
|
||||
case 'ISO-8859-1':
|
||||
|
@ -1026,8 +989,8 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
// iconv() not available
|
||||
static $ConversionFunctionList = [];
|
||||
// neither mb_convert_encoding or iconv() is available
|
||||
static $ConversionFunctionList = array();
|
||||
if (empty($ConversionFunctionList)) {
|
||||
$ConversionFunctionList['ISO-8859-1']['UTF-8'] = 'iconv_fallback_iso88591_utf8';
|
||||
$ConversionFunctionList['ISO-8859-1']['UTF-16'] = 'iconv_fallback_iso88591_utf16';
|
||||
|
@ -1048,15 +1011,14 @@ class getid3_lib
|
|||
$ConversionFunction = $ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)];
|
||||
return self::$ConversionFunction($string);
|
||||
}
|
||||
throw new Exception('PHP does not have iconv() support - cannot convert from '.$in_charset.' to '.$out_charset);
|
||||
throw new Exception('PHP does not has mb_convert_encoding() or iconv() support - cannot convert from '.$in_charset.' to '.$out_charset);
|
||||
}
|
||||
|
||||
public static function recursiveMultiByteCharString2HTML($data, $charset = 'ISO-8859-1')
|
||||
{
|
||||
public static function recursiveMultiByteCharString2HTML($data, $charset='ISO-8859-1') {
|
||||
if (is_string($data)) {
|
||||
return self::MultiByteCharString2HTML($data, $charset);
|
||||
} elseif (is_array($data)) {
|
||||
$return_data = [];
|
||||
$return_data = array();
|
||||
foreach ($data as $key => $value) {
|
||||
$return_data[$key] = self::recursiveMultiByteCharString2HTML($value, $charset);
|
||||
}
|
||||
|
@ -1066,43 +1028,42 @@ class getid3_lib
|
|||
return $data;
|
||||
}
|
||||
|
||||
public static function MultiByteCharString2HTML($string, $charset = 'ISO-8859-1')
|
||||
{
|
||||
public static function MultiByteCharString2HTML($string, $charset='ISO-8859-1') {
|
||||
$string = (string) $string; // in case trying to pass a numeric (float, int) string, would otherwise return an empty string
|
||||
$HTMLstring = '';
|
||||
|
||||
switch ($charset) {
|
||||
switch (strtolower($charset)) {
|
||||
case '1251':
|
||||
case '1252':
|
||||
case '866':
|
||||
case '932':
|
||||
case '936':
|
||||
case '950':
|
||||
case 'BIG5':
|
||||
case 'BIG5-HKSCS':
|
||||
case 'big5':
|
||||
case 'big5-hkscs':
|
||||
case 'cp1251':
|
||||
case 'cp1252':
|
||||
case 'cp866':
|
||||
case 'EUC-JP':
|
||||
case 'EUCJP':
|
||||
case 'GB2312':
|
||||
case 'euc-jp':
|
||||
case 'eucjp':
|
||||
case 'gb2312':
|
||||
case 'ibm866':
|
||||
case 'ISO-8859-1':
|
||||
case 'ISO-8859-15':
|
||||
case 'ISO8859-1':
|
||||
case 'ISO8859-15':
|
||||
case 'KOI8-R':
|
||||
case 'iso-8859-1':
|
||||
case 'iso-8859-15':
|
||||
case 'iso8859-1':
|
||||
case 'iso8859-15':
|
||||
case 'koi8-r':
|
||||
case 'koi8-ru':
|
||||
case 'koi8r':
|
||||
case 'Shift_JIS':
|
||||
case 'SJIS':
|
||||
case 'shift_jis':
|
||||
case 'sjis':
|
||||
case 'win-1251':
|
||||
case 'Windows-1251':
|
||||
case 'Windows-1252':
|
||||
case 'windows-1251':
|
||||
case 'windows-1252':
|
||||
$HTMLstring = htmlentities($string, ENT_COMPAT, $charset);
|
||||
break;
|
||||
|
||||
case 'UTF-8':
|
||||
case 'utf-8':
|
||||
$strlen = strlen($string);
|
||||
for ($i = 0; $i < $strlen; $i++) {
|
||||
$char_ord_val = ord($string{$i});
|
||||
|
@ -1130,7 +1091,7 @@ class getid3_lib
|
|||
}
|
||||
break;
|
||||
|
||||
case 'UTF-16LE':
|
||||
case 'utf-16le':
|
||||
for ($i = 0; $i < strlen($string); $i += 2) {
|
||||
$charval = self::LittleEndian2Int(substr($string, $i, 2));
|
||||
if (($charval >= 32) && ($charval <= 127)) {
|
||||
|
@ -1141,7 +1102,7 @@ class getid3_lib
|
|||
}
|
||||
break;
|
||||
|
||||
case 'UTF-16BE':
|
||||
case 'utf-16be':
|
||||
for ($i = 0; $i < strlen($string); $i += 2) {
|
||||
$charval = self::BigEndian2Int(substr($string, $i, 2));
|
||||
if (($charval >= 32) && ($charval <= 127)) {
|
||||
|
@ -1161,9 +1122,8 @@ class getid3_lib
|
|||
|
||||
|
||||
|
||||
public static function RGADnameLookup($namecode)
|
||||
{
|
||||
static $RGADname = [];
|
||||
public static function RGADnameLookup($namecode) {
|
||||
static $RGADname = array();
|
||||
if (empty($RGADname)) {
|
||||
$RGADname[0] = 'not set';
|
||||
$RGADname[1] = 'Track Gain Adjustment';
|
||||
|
@ -1174,9 +1134,8 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function RGADoriginatorLookup($originatorcode)
|
||||
{
|
||||
static $RGADoriginator = [];
|
||||
public static function RGADoriginatorLookup($originatorcode) {
|
||||
static $RGADoriginator = array();
|
||||
if (empty($RGADoriginator)) {
|
||||
$RGADoriginator[0] = 'unspecified';
|
||||
$RGADoriginator[1] = 'pre-set by artist/producer/mastering engineer';
|
||||
|
@ -1188,8 +1147,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function RGADadjustmentLookup($rawadjustment, $signbit)
|
||||
{
|
||||
public static function RGADadjustmentLookup($rawadjustment, $signbit) {
|
||||
$adjustment = $rawadjustment / 10;
|
||||
if ($signbit == 1) {
|
||||
$adjustment *= -1;
|
||||
|
@ -1198,8 +1156,7 @@ class getid3_lib
|
|||
}
|
||||
|
||||
|
||||
public static function RGADgainString($namecode, $originatorcode, $replaygain)
|
||||
{
|
||||
public static function RGADgainString($namecode, $originatorcode, $replaygain) {
|
||||
if ($replaygain < 0) {
|
||||
$signbit = '1';
|
||||
} else {
|
||||
|
@ -1214,14 +1171,12 @@ class getid3_lib
|
|||
return $gainstring;
|
||||
}
|
||||
|
||||
public static function RGADamplitude2dB($amplitude)
|
||||
{
|
||||
public static function RGADamplitude2dB($amplitude) {
|
||||
return 20 * log10($amplitude);
|
||||
}
|
||||
|
||||
|
||||
public static function GetDataImageSize($imgData, &$imageinfo = [])
|
||||
{
|
||||
public static function GetDataImageSize($imgData, &$imageinfo=array()) {
|
||||
static $tempdir = '';
|
||||
if (empty($tempdir)) {
|
||||
if (function_exists('sys_get_temp_dir')) {
|
||||
|
@ -1255,15 +1210,13 @@ class getid3_lib
|
|||
return $GetDataImageSize;
|
||||
}
|
||||
|
||||
public static function ImageExtFromMime($mime_type)
|
||||
{
|
||||
public static function ImageExtFromMime($mime_type) {
|
||||
// temporary way, works OK for now, but should be reworked in the future
|
||||
return str_replace(['image/', 'x-', 'jpeg'], ['', '', 'jpg'], $mime_type);
|
||||
return str_replace(array('image/', 'x-', 'jpeg'), array('', '', 'jpg'), $mime_type);
|
||||
}
|
||||
|
||||
public static function ImageTypesLookup($imagetypeid)
|
||||
{
|
||||
static $ImageTypesLookup = [];
|
||||
public static function ImageTypesLookup($imagetypeid) {
|
||||
static $ImageTypesLookup = array();
|
||||
if (empty($ImageTypesLookup)) {
|
||||
$ImageTypesLookup[1] = 'gif';
|
||||
$ImageTypesLookup[2] = 'jpeg';
|
||||
|
@ -1283,8 +1236,7 @@ class getid3_lib
|
|||
return (isset($ImageTypesLookup[$imagetypeid]) ? $ImageTypesLookup[$imagetypeid] : '');
|
||||
}
|
||||
|
||||
public static function CopyTagsToComments(&$ThisFileInfo)
|
||||
{
|
||||
public static function CopyTagsToComments(&$ThisFileInfo) {
|
||||
|
||||
// Copy all entries from ['tags'] into common ['comments']
|
||||
if (!empty($ThisFileInfo['tags'])) {
|
||||
|
@ -1293,8 +1245,11 @@ class getid3_lib
|
|||
foreach ($tagdata as $key => $value) {
|
||||
if (!empty($value)) {
|
||||
if (empty($ThisFileInfo['comments'][$tagname])) {
|
||||
|
||||
// fall through and append value
|
||||
|
||||
} elseif ($tagtype == 'id3v1') {
|
||||
|
||||
$newvaluelength = strlen(trim($value));
|
||||
foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) {
|
||||
$oldvaluelength = strlen(trim($existingvalue));
|
||||
|
@ -1303,7 +1258,9 @@ class getid3_lib
|
|||
break 2;
|
||||
}
|
||||
}
|
||||
|
||||
} elseif (!is_array($value)) {
|
||||
|
||||
$newvaluelength = strlen(trim($value));
|
||||
foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) {
|
||||
$oldvaluelength = strlen(trim($existingvalue));
|
||||
|
@ -1313,11 +1270,15 @@ class getid3_lib
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) {
|
||||
$value = (is_string($value) ? trim($value) : $value);
|
||||
if (!is_numeric($key)) {
|
||||
if (!is_int($key) && !ctype_digit($key)) {
|
||||
$ThisFileInfo['comments'][$tagname][$key] = $value;
|
||||
} else {
|
||||
if (isset($ThisFileInfo['comments'][$tagname])) {
|
||||
$ThisFileInfo['comments'][$tagname] = array($value);
|
||||
} else {
|
||||
$ThisFileInfo['comments'][$tagname][] = $value;
|
||||
}
|
||||
|
@ -1326,6 +1287,19 @@ class getid3_lib
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// attempt to standardize spelling of returned keys
|
||||
$StandardizeFieldNames = array(
|
||||
'tracknumber' => 'track_number',
|
||||
'track' => 'track_number',
|
||||
);
|
||||
foreach ($StandardizeFieldNames as $badkey => $goodkey) {
|
||||
if (array_key_exists($badkey, $ThisFileInfo['comments']) && !array_key_exists($goodkey, $ThisFileInfo['comments'])) {
|
||||
$ThisFileInfo['comments'][$goodkey] = $ThisFileInfo['comments'][$badkey];
|
||||
unset($ThisFileInfo['comments'][$badkey]);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy to ['comments_html']
|
||||
if (!empty($ThisFileInfo['comments'])) {
|
||||
|
@ -1344,13 +1318,13 @@ class getid3_lib
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static function EmbeddedLookup($key, $begin, $end, $file, $name)
|
||||
{
|
||||
public static function EmbeddedLookup($key, $begin, $end, $file, $name) {
|
||||
|
||||
// Cached
|
||||
static $cache;
|
||||
|
@ -1372,6 +1346,7 @@ class getid3_lib
|
|||
|
||||
// Loop thru line
|
||||
while (0 < $line_count--) {
|
||||
|
||||
// Read line
|
||||
$line = ltrim(fgets($fp, 1024), "\t ");
|
||||
|
||||
|
@ -1395,8 +1370,7 @@ class getid3_lib
|
|||
return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : '');
|
||||
}
|
||||
|
||||
public static function IncludeDependency($filename, $sourcefile, $DieOnFailure = false)
|
||||
{
|
||||
public static function IncludeDependency($filename, $sourcefile, $DieOnFailure=false) {
|
||||
global $GETID3_ERRORARRAY;
|
||||
|
||||
if (file_exists($filename)) {
|
||||
|
@ -1416,13 +1390,11 @@ class getid3_lib
|
|||
return false;
|
||||
}
|
||||
|
||||
public static function trimNullByte($string)
|
||||
{
|
||||
public static function trimNullByte($string) {
|
||||
return trim($string, "\x00");
|
||||
}
|
||||
|
||||
public static function getFileSizeSyscall($path)
|
||||
{
|
||||
public static function getFileSizeSyscall($path) {
|
||||
$filesize = false;
|
||||
|
||||
if (GETID3_OS_ISWINDOWS) {
|
||||
|
@ -1453,9 +1425,9 @@ class getid3_lib
|
|||
* @param string $suffix If the name component ends in suffix this will also be cut off.
|
||||
* @return string
|
||||
*/
|
||||
public static function mb_basename($path, $suffix = null)
|
||||
{
|
||||
public static function mb_basename($path, $suffix = null) {
|
||||
$splited = preg_split('#/#', rtrim($path, '/ '));
|
||||
return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -20,14 +20,12 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class getid3_gzip extends getid3_handler
|
||||
{
|
||||
class getid3_gzip extends getid3_handler {
|
||||
|
||||
// public: Optional file list - disable for speed.
|
||||
public $option_gzip_parse_contents = false; // decode gzipped files, if possible, and parse recursively (.tar.gz for example)
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'gzip';
|
||||
|
@ -39,7 +37,7 @@ class getid3_gzip extends getid3_handler
|
|||
//+---+---+---+---+---+---+---+---+---+---+
|
||||
|
||||
if ($info['php_memory_limit'] && ($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)';
|
||||
$this->error('File is too large ('.number_format($info['filesize']).' bytes) to read into memory (limit: '.number_format($info['php_memory_limit'] / 1048576).'MB)');
|
||||
return false;
|
||||
}
|
||||
$this->fseek(0);
|
||||
|
@ -69,7 +67,7 @@ class getid3_gzip extends getid3_handler
|
|||
}
|
||||
}
|
||||
|
||||
$info['gzip']['files'] = [];
|
||||
$info['gzip']['files'] = array();
|
||||
|
||||
$fpointer = 0;
|
||||
$idx = 0;
|
||||
|
@ -99,12 +97,12 @@ class getid3_gzip extends getid3_handler
|
|||
|
||||
$thisInfo['os'] = $this->get_os_type($thisInfo['raw']['os']);
|
||||
if (!$thisInfo['os']) {
|
||||
$info['error'][] = 'Read error on gzip file';
|
||||
$this->error('Read error on gzip file');
|
||||
return false;
|
||||
}
|
||||
|
||||
$fpointer = 10;
|
||||
$arr_xsubfield = [];
|
||||
$arr_xsubfield = array();
|
||||
// bit 2 - FLG.FEXTRA
|
||||
//+---+---+=================================+
|
||||
//| XLEN |...XLEN bytes of "extra field"...|
|
||||
|
@ -217,7 +215,7 @@ class getid3_gzip extends getid3_handler
|
|||
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';
|
||||
$this->error('Unable to create temp file to parse TAR inside GZIP file');
|
||||
break;
|
||||
}
|
||||
if ($fp_temp_tar = fopen($temp_tar_filename, 'w+b')) {
|
||||
|
@ -231,7 +229,7 @@ class getid3_gzip extends getid3_handler
|
|||
unset($getid3_temp, $getid3_tar);
|
||||
unlink($temp_tar_filename);
|
||||
} else {
|
||||
$info['error'][] = 'Unable to fopen() temp file to parse TAR inside GZIP file';
|
||||
$this->error('Unable to fopen() temp file to parse TAR inside GZIP file');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -249,9 +247,8 @@ class getid3_gzip extends getid3_handler
|
|||
}
|
||||
|
||||
// Converts the OS type
|
||||
public function get_os_type($key)
|
||||
{
|
||||
static $os_type = [
|
||||
public function get_os_type($key) {
|
||||
static $os_type = array(
|
||||
'0' => 'FAT filesystem (MS-DOS, OS/2, NT/Win32)',
|
||||
'1' => 'Amiga',
|
||||
'2' => 'VMS (or OpenVMS)',
|
||||
|
@ -267,18 +264,18 @@ class getid3_gzip extends getid3_handler
|
|||
'12' => 'QDOS',
|
||||
'13' => 'Acorn RISCOS',
|
||||
'255' => 'unknown'
|
||||
];
|
||||
);
|
||||
return (isset($os_type[$key]) ? $os_type[$key] : '');
|
||||
}
|
||||
|
||||
// Converts the eXtra FLags
|
||||
public function get_xflag_type($key)
|
||||
{
|
||||
static $xflag_type = [
|
||||
public 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] : '');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,7 @@ class getid3_rar extends getid3_handler
|
|||
|
||||
public $option_use_rar_extension = false;
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'rar';
|
||||
|
@ -29,7 +28,7 @@ class getid3_rar extends getid3_handler
|
|||
if ($this->option_use_rar_extension === true) {
|
||||
if (function_exists('rar_open')) {
|
||||
if ($rp = rar_open($info['filenamepath'])) {
|
||||
$info['rar']['files'] = [];
|
||||
$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()));
|
||||
|
@ -37,14 +36,16 @@ class getid3_rar extends getid3_handler
|
|||
rar_close($rp);
|
||||
return true;
|
||||
} else {
|
||||
$info['error'][] = 'failed to rar_open('.$info['filename'].')';
|
||||
$this->error('failed to rar_open('.$info['filename'].')');
|
||||
}
|
||||
} else {
|
||||
$info['error'][] = 'RAR support does not appear to be available in this PHP installation';
|
||||
$this->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)';
|
||||
$this->error('PHP-RAR processing has been disabled (set $getid3_rar->option_use_rar_extension=true to enable)');
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,20 +18,19 @@
|
|||
class getid3_szip extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$SZIPHeader = $this->fread(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)).'"';
|
||||
$this->error('Expecting "53 5A 0A 04" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($SZIPHeader, 0, 4)).'"');
|
||||
return false;
|
||||
}
|
||||
$info['fileformat'] = 'szip';
|
||||
$info['szip']['major_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 4, 1));
|
||||
$info['szip']['minor_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 5, 1));
|
||||
$info['error'][] = 'SZIP parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
|
||||
$this->error('SZIP parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
|
||||
return false;
|
||||
|
||||
while (!$this->feof()) {
|
||||
|
@ -92,5 +91,7 @@ class getid3_szip extends getid3_handler
|
|||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,12 +23,11 @@
|
|||
class getid3_tar extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'tar';
|
||||
$info['tar']['files'] = [];
|
||||
$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
|
||||
|
@ -95,7 +94,7 @@ class getid3_tar extends getid3_handler
|
|||
if ($name == '') {
|
||||
break;
|
||||
}
|
||||
$info['tar']['file_details'][$name] = [
|
||||
$info['tar']['file_details'][$name] = array (
|
||||
'name' => $name,
|
||||
'mode_raw' => $mode,
|
||||
'mode' => self::display_perms($mode),
|
||||
|
@ -112,33 +111,23 @@ class getid3_tar extends getid3_handler
|
|||
'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
|
||||
public function display_perms($mode)
|
||||
{
|
||||
public 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
|
||||
}
|
||||
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' : '-');
|
||||
|
@ -152,15 +141,9 @@ class getid3_tar extends getid3_handler
|
|||
$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';
|
||||
}
|
||||
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']);
|
||||
|
@ -170,9 +153,8 @@ class getid3_tar extends getid3_handler
|
|||
}
|
||||
|
||||
// Converts the file type
|
||||
public function get_flag_type($typflag)
|
||||
{
|
||||
static $flag_types = [
|
||||
public function get_flag_type($typflag) {
|
||||
static $flag_types = array(
|
||||
'0' => 'LF_NORMAL',
|
||||
'1' => 'LF_LINK',
|
||||
'2' => 'LF_SYNLINK',
|
||||
|
@ -188,7 +170,8 @@ class getid3_tar extends getid3_handler
|
|||
'N' => 'LF_NAMES',
|
||||
'S' => 'LF_SPARSE',
|
||||
'V' => 'LF_VOLHDR'
|
||||
];
|
||||
);
|
||||
return (isset($flag_types[$typflag]) ? $flag_types[$typflag] : '');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,29 +18,30 @@
|
|||
class getid3_zip extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'zip';
|
||||
$info['zip']['encoding'] = 'ISO-8859-1';
|
||||
$info['zip']['files'] = [];
|
||||
$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';
|
||||
$this->error('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB, not supported by PHP');
|
||||
return false;
|
||||
} else {
|
||||
$EOCDsearchData = '';
|
||||
$EOCDsearchCounter = 0;
|
||||
while ($EOCDsearchCounter++ < 512) {
|
||||
|
||||
$this->fseek(-128 * $EOCDsearchCounter, SEEK_END);
|
||||
$EOCDsearchData = $this->fread(128).$EOCDsearchData;
|
||||
|
||||
if (strstr($EOCDsearchData, 'PK'."\x05\x06")) {
|
||||
|
||||
$EOCDposition = strpos($EOCDsearchData, 'PK'."\x05\x06");
|
||||
$this->fseek((-128 * $EOCDsearchCounter) + $EOCDposition, SEEK_END);
|
||||
$info['zip']['end_central_directory'] = $this->ZIPparseEndOfCentralDirectory();
|
||||
|
@ -60,7 +61,7 @@ class getid3_zip extends getid3_handler
|
|||
}
|
||||
|
||||
if ($info['zip']['entries_count'] == 0) {
|
||||
$info['error'][] = 'No Central Directory entries found (truncated file?)';
|
||||
$this->error('No Central Directory entries found (truncated file?)');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -85,7 +86,7 @@ class getid3_zip extends getid3_handler
|
|||
if ($fileentry = $this->ZIPparseLocalFileHeader()) {
|
||||
$info['zip']['entries'][] = $fileentry;
|
||||
} else {
|
||||
$info['warning'][] = 'Error parsing Local File Header at offset '.$central_directory_entry['entry_offset'];
|
||||
$this->warning('Error parsing Local File Header at offset '.$central_directory_entry['entry_offset']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,16 +113,16 @@ class getid3_zip extends getid3_handler
|
|||
if (!$this->getZIPentriesFilepointer()) {
|
||||
unset($info['zip']);
|
||||
$info['fileformat'] = '';
|
||||
$info['error'][] = 'Cannot find End Of Central Directory (truncated file?)';
|
||||
$this->error('Cannot find End Of Central Directory (truncated file?)');
|
||||
return false;
|
||||
}
|
||||
|
||||
// central directory couldn't be found and/or parsed
|
||||
// scan through actual file data entries, recover as much as possible from probable trucated file
|
||||
if ($info['zip']['compressed_size'] > ($info['filesize'] - 46 - 22)) {
|
||||
$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)';
|
||||
$this->error('Warning: Truncated file! - Total compressed file sizes ('.$info['zip']['compressed_size'].' bytes) is greater than filesize minus Central Directory and End Of Central Directory structures ('.($info['filesize'] - 46 - 22).' bytes)');
|
||||
}
|
||||
$info['error'][] = 'Cannot find End Of Central Directory - returned list of files in [zip][entries] array may not be complete';
|
||||
$this->error('Cannot find End Of Central Directory - returned list of files in [zip][entries] array may not be complete');
|
||||
foreach ($info['zip']['entries'] as $key => $valuearray) {
|
||||
$info['zip']['files'][$valuearray['filename']] = $valuearray['uncompressed_size'];
|
||||
}
|
||||
|
@ -129,8 +130,7 @@ class getid3_zip extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function getZIPHeaderFilepointerTopDown()
|
||||
{
|
||||
public function getZIPHeaderFilepointerTopDown() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'zip';
|
||||
|
@ -145,7 +145,7 @@ class getid3_zip extends getid3_handler
|
|||
$info['zip']['entries_count']++;
|
||||
}
|
||||
if ($info['zip']['entries_count'] == 0) {
|
||||
$info['error'][] = 'No Local File Header entries found';
|
||||
$this->error('No Local File Header entries found');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -157,14 +157,14 @@ class getid3_zip extends getid3_handler
|
|||
$info['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size'];
|
||||
}
|
||||
if ($info['zip']['entries_count'] == 0) {
|
||||
$info['error'][] = 'No Central Directory entries found (truncated file?)';
|
||||
$this->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?)';
|
||||
$this->error('No End Of Central Directory entry found (truncated file?)');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -176,8 +176,7 @@ class getid3_zip extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function getZIPentriesFilepointer()
|
||||
{
|
||||
public function getZIPentriesFilepointer() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['zip']['compressed_size'] = 0;
|
||||
|
@ -192,7 +191,7 @@ class getid3_zip extends getid3_handler
|
|||
$info['zip']['uncompressed_size'] += $fileentry['uncompressed_size'];
|
||||
}
|
||||
if ($info['zip']['entries_count'] == 0) {
|
||||
$info['error'][] = 'No Local File Header entries found';
|
||||
$this->error('No Local File Header entries found');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -200,8 +199,7 @@ class getid3_zip extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function ZIPparseLocalFileHeader()
|
||||
{
|
||||
public function ZIPparseLocalFileHeader() {
|
||||
$LocalFileHeader['offset'] = $this->ftell();
|
||||
|
||||
$ZIPlocalFileHeader = $this->fread(30);
|
||||
|
@ -258,6 +256,7 @@ class getid3_zip extends getid3_handler
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
$LocalFileHeader['data_offset'] = $this->ftell();
|
||||
$this->fseek($LocalFileHeader['compressed_size'], SEEK_CUR); // this should (but may not) match value in $LocalFileHeader['raw']['compressed_size'] -- $LocalFileHeader['compressed_size'] could have been overwritten above with value from Central Directory
|
||||
|
@ -279,13 +278,13 @@ class getid3_zip extends getid3_handler
|
|||
if ($LocalFileHeader['data_descriptor']['compressed_size'] == $central_directory_entry['compressed_size']) {
|
||||
// $LocalFileHeader['compressed_size'] already set from Central Directory
|
||||
} else {
|
||||
$this->getid3->info['warning'][] = 'conflicting compressed_size from data_descriptor ('.$LocalFileHeader['data_descriptor']['compressed_size'].') vs Central Directory ('.$central_directory_entry['compressed_size'].') for file at offset '.$LocalFileHeader['offset'];
|
||||
$this->warning('conflicting compressed_size from data_descriptor ('.$LocalFileHeader['data_descriptor']['compressed_size'].') vs Central Directory ('.$central_directory_entry['compressed_size'].') for file at offset '.$LocalFileHeader['offset']);
|
||||
}
|
||||
|
||||
if ($LocalFileHeader['data_descriptor']['uncompressed_size'] == $central_directory_entry['uncompressed_size']) {
|
||||
$LocalFileHeader['uncompressed_size'] = $LocalFileHeader['data_descriptor']['uncompressed_size'];
|
||||
} else {
|
||||
$this->getid3->info['warning'][] = 'conflicting uncompressed_size from data_descriptor ('.$LocalFileHeader['data_descriptor']['uncompressed_size'].') vs Central Directory ('.$central_directory_entry['uncompressed_size'].') for file at offset '.$LocalFileHeader['offset'];
|
||||
$this->warning('conflicting uncompressed_size from data_descriptor ('.$LocalFileHeader['data_descriptor']['uncompressed_size'].') vs Central Directory ('.$central_directory_entry['uncompressed_size'].') for file at offset '.$LocalFileHeader['offset']);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -296,8 +295,7 @@ class getid3_zip extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function ZIPparseCentralDirectory()
|
||||
{
|
||||
public function ZIPparseCentralDirectory() {
|
||||
$CentralDirectory['offset'] = $this->ftell();
|
||||
|
||||
$ZIPcentralDirectory = $this->fread(46);
|
||||
|
@ -353,8 +351,7 @@ class getid3_zip extends getid3_handler
|
|||
return $CentralDirectory;
|
||||
}
|
||||
|
||||
public function ZIPparseEndOfCentralDirectory()
|
||||
{
|
||||
public function ZIPparseEndOfCentralDirectory() {
|
||||
$EndOfCentralDirectory['offset'] = $this->ftell();
|
||||
|
||||
$ZIPendOfCentralDirectory = $this->fread(22);
|
||||
|
@ -381,8 +378,7 @@ class getid3_zip extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public static function ZIPparseGeneralPurposeFlags($flagbytes, $compressionmethod)
|
||||
{
|
||||
public static function ZIPparseGeneralPurposeFlags($flagbytes, $compressionmethod) {
|
||||
// https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip-printable.html
|
||||
$ParsedFlags['encrypted'] = (bool) ($flagbytes & 0x0001);
|
||||
// 0x0002 -- see below
|
||||
|
@ -430,9 +426,8 @@ class getid3_zip extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public static function ZIPversionOSLookup($index)
|
||||
{
|
||||
static $ZIPversionOSLookup = [
|
||||
public static function ZIPversionOSLookup($index) {
|
||||
static $ZIPversionOSLookup = array(
|
||||
0 => 'MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)',
|
||||
1 => 'Amiga',
|
||||
2 => 'OpenVMS',
|
||||
|
@ -453,15 +448,14 @@ class getid3_zip extends getid3_handler
|
|||
17 => 'Tandem',
|
||||
18 => 'OS/400',
|
||||
19 => 'OS/X (Darwin)',
|
||||
];
|
||||
);
|
||||
|
||||
return (isset($ZIPversionOSLookup[$index]) ? $ZIPversionOSLookup[$index] : '[unknown]');
|
||||
}
|
||||
|
||||
public static function ZIPcompressionMethodLookup($index)
|
||||
{
|
||||
public static function ZIPcompressionMethodLookup($index) {
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/ZIP.html
|
||||
static $ZIPcompressionMethodLookup = [
|
||||
static $ZIPcompressionMethodLookup = array(
|
||||
0 => 'store',
|
||||
1 => 'shrink',
|
||||
2 => 'reduce-1',
|
||||
|
@ -485,13 +479,12 @@ class getid3_zip extends getid3_handler
|
|||
96 => 'JPEG recompressed',
|
||||
97 => 'WavPack compressed',
|
||||
98 => 'PPMd version I, Rev 1',
|
||||
];
|
||||
);
|
||||
|
||||
return (isset($ZIPcompressionMethodLookup[$index]) ? $ZIPcompressionMethodLookup[$index] : '[unknown]');
|
||||
}
|
||||
|
||||
public static function DOStime2UNIXtime($DOSdate, $DOStime)
|
||||
{
|
||||
public static function DOStime2UNIXtime($DOSdate, $DOStime) {
|
||||
// wFatDate
|
||||
// Specifies the MS-DOS date. The date is a packed 16-bit value with the following format:
|
||||
// Bits Contents
|
||||
|
@ -516,4 +509,5 @@ class getid3_zip extends getid3_handler
|
|||
|
||||
return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,11 +16,9 @@
|
|||
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
|
||||
|
||||
class getid3_asf extends getid3_handler
|
||||
{
|
||||
class getid3_asf extends getid3_handler {
|
||||
|
||||
public function __construct(getID3 $getid3)
|
||||
{
|
||||
public function __construct(getID3 $getid3) {
|
||||
parent::__construct($getid3); // extends getid3_handler::__construct()
|
||||
|
||||
// initialize all GUID constants
|
||||
|
@ -32,18 +30,17 @@ class getid3_asf extends getid3_handler
|
|||
}
|
||||
}
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// Shortcuts
|
||||
$thisfile_audio = &$info['audio'];
|
||||
$thisfile_video = &$info['video'];
|
||||
$info['asf'] = [];
|
||||
$info['asf'] = array();
|
||||
$thisfile_asf = &$info['asf'];
|
||||
$thisfile_asf['comments'] = [];
|
||||
$thisfile_asf['comments'] = array();
|
||||
$thisfile_asf_comments = &$thisfile_asf['comments'];
|
||||
$thisfile_asf['header_object'] = [];
|
||||
$thisfile_asf['header_object'] = array();
|
||||
$thisfile_asf_headerobject = &$thisfile_asf['header_object'];
|
||||
|
||||
|
||||
|
@ -94,6 +91,7 @@ class getid3_asf extends getid3_handler
|
|||
$NextObjectSize = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
|
||||
$offset += 8;
|
||||
switch ($NextObjectGUID) {
|
||||
|
||||
case GETID3_ASF_File_Properties_Object:
|
||||
// File Properties Object: (mandatory, one only)
|
||||
// Field Name Field Type Size (bits)
|
||||
|
@ -115,7 +113,7 @@ class getid3_asf extends getid3_handler
|
|||
// Maximum Bitrate DWORD 32 // maximum instantaneous bitrate in bits per second for entire file, including all data streams and ASF overhead
|
||||
|
||||
// shortcut
|
||||
$thisfile_asf['file_properties_object'] = [];
|
||||
$thisfile_asf['file_properties_object'] = array();
|
||||
$thisfile_asf_filepropertiesobject = &$thisfile_asf['file_properties_object'];
|
||||
|
||||
$thisfile_asf_filepropertiesobject['offset'] = $NextObjectOffset + $offset;
|
||||
|
@ -151,6 +149,7 @@ class getid3_asf extends getid3_handler
|
|||
$offset += 4;
|
||||
|
||||
if ($thisfile_asf_filepropertiesobject['flags']['broadcast']) {
|
||||
|
||||
// broadcast flag is set, some values invalid
|
||||
unset($thisfile_asf_filepropertiesobject['filesize']);
|
||||
unset($thisfile_asf_filepropertiesobject['data_packets']);
|
||||
|
@ -158,7 +157,9 @@ class getid3_asf extends getid3_handler
|
|||
unset($thisfile_asf_filepropertiesobject['send_duration']);
|
||||
unset($thisfile_asf_filepropertiesobject['min_packet_size']);
|
||||
unset($thisfile_asf_filepropertiesobject['max_packet_size']);
|
||||
|
||||
} else {
|
||||
|
||||
// broadcast flag NOT set, perform calculations
|
||||
$info['playtime_seconds'] = ($thisfile_asf_filepropertiesobject['play_duration'] / 10000000) - ($thisfile_asf_filepropertiesobject['preroll'] / 1000);
|
||||
|
||||
|
@ -217,6 +218,7 @@ class getid3_asf extends getid3_handler
|
|||
$offset += $StreamPropertiesObjectData['error_data_length'];
|
||||
|
||||
switch ($StreamPropertiesObjectData['stream_type']) {
|
||||
|
||||
case GETID3_ASF_Audio_Media:
|
||||
$thisfile_audio['dataformat'] = (!empty($thisfile_audio['dataformat']) ? $thisfile_audio['dataformat'] : 'asf');
|
||||
$thisfile_audio['bitrate_mode'] = (!empty($thisfile_audio['bitrate_mode']) ? $thisfile_audio['bitrate_mode'] : 'cbr');
|
||||
|
@ -235,6 +237,7 @@ class getid3_asf extends getid3_handler
|
|||
default:
|
||||
// do nothing
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
$thisfile_asf['stream_properties_object'][$StreamPropertiesObjectStreamNumber] = $StreamPropertiesObjectData;
|
||||
|
@ -252,7 +255,7 @@ class getid3_asf extends getid3_handler
|
|||
// Header Extension Data BYTESTREAM variable // array of zero or more extended header objects
|
||||
|
||||
// shortcut
|
||||
$thisfile_asf['header_extension_object'] = [];
|
||||
$thisfile_asf['header_extension_object'] = array();
|
||||
$thisfile_asf_headerextensionobject = &$thisfile_asf['header_extension_object'];
|
||||
|
||||
$thisfile_asf_headerextensionobject['offset'] = $NextObjectOffset + $offset;
|
||||
|
@ -263,14 +266,14 @@ class getid3_asf extends getid3_handler
|
|||
$offset += 16;
|
||||
$thisfile_asf_headerextensionobject['reserved_1_guid'] = $this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']);
|
||||
if ($thisfile_asf_headerextensionobject['reserved_1'] != GETID3_ASF_Reserved_1) {
|
||||
$info['warning'][] = 'header_extension_object.reserved_1 GUID ('.$this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']).') does not match expected "GETID3_ASF_Reserved_1" GUID ('.$this->BytestringToGUID(GETID3_ASF_Reserved_1).')';
|
||||
$this->warning('header_extension_object.reserved_1 GUID ('.$this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']).') does not match expected "GETID3_ASF_Reserved_1" GUID ('.$this->BytestringToGUID(GETID3_ASF_Reserved_1).')');
|
||||
//return false;
|
||||
break;
|
||||
}
|
||||
$thisfile_asf_headerextensionobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
|
||||
$offset += 2;
|
||||
if ($thisfile_asf_headerextensionobject['reserved_2'] != 6) {
|
||||
$info['warning'][] = 'header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"';
|
||||
$this->warning('header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"');
|
||||
//return false;
|
||||
break;
|
||||
}
|
||||
|
@ -302,7 +305,7 @@ class getid3_asf extends getid3_handler
|
|||
// * Codec Information BYTESTREAM variable // opaque array of information bytes about the codec used to create the content
|
||||
|
||||
// shortcut
|
||||
$thisfile_asf['codec_list_object'] = [];
|
||||
$thisfile_asf['codec_list_object'] = array();
|
||||
$thisfile_asf_codeclistobject = &$thisfile_asf['codec_list_object'];
|
||||
|
||||
$thisfile_asf_codeclistobject['offset'] = $NextObjectOffset + $offset;
|
||||
|
@ -313,7 +316,7 @@ class getid3_asf extends getid3_handler
|
|||
$offset += 16;
|
||||
$thisfile_asf_codeclistobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']);
|
||||
if ($thisfile_asf_codeclistobject['reserved'] != $this->GUIDtoBytestring('86D15241-311D-11D0-A3A4-00A0C90348F6')) {
|
||||
$info['warning'][] = 'codec_list_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {86D15241-311D-11D0-A3A4-00A0C90348F6}';
|
||||
$this->warning('codec_list_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {86D15241-311D-11D0-A3A4-00A0C90348F6}');
|
||||
//return false;
|
||||
break;
|
||||
}
|
||||
|
@ -321,7 +324,7 @@ class getid3_asf extends getid3_handler
|
|||
$offset += 4;
|
||||
for ($CodecEntryCounter = 0; $CodecEntryCounter < $thisfile_asf_codeclistobject['codec_entries_count']; $CodecEntryCounter++) {
|
||||
// shortcut
|
||||
$thisfile_asf_codeclistobject['codec_entries'][$CodecEntryCounter] = [];
|
||||
$thisfile_asf_codeclistobject['codec_entries'][$CodecEntryCounter] = array();
|
||||
$thisfile_asf_codeclistobject_codecentries_current = &$thisfile_asf_codeclistobject['codec_entries'][$CodecEntryCounter];
|
||||
|
||||
$thisfile_asf_codeclistobject_codecentries_current['type_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
|
||||
|
@ -346,8 +349,9 @@ class getid3_asf extends getid3_handler
|
|||
if ($thisfile_asf_codeclistobject_codecentries_current['type_raw'] == 2) { // audio codec
|
||||
|
||||
if (strpos($thisfile_asf_codeclistobject_codecentries_current['description'], ',') === false) {
|
||||
$info['warning'][] = '[asf][codec_list_object][codec_entries]['.$CodecEntryCounter.'][description] expected to contain comma-seperated list of parameters: "'.$thisfile_asf_codeclistobject_codecentries_current['description'].'"';
|
||||
$this->warning('[asf][codec_list_object][codec_entries]['.$CodecEntryCounter.'][description] expected to contain comma-separated list of parameters: "'.$thisfile_asf_codeclistobject_codecentries_current['description'].'"');
|
||||
} else {
|
||||
|
||||
list($AudioCodecBitrate, $AudioCodecFrequency, $AudioCodecChannels) = explode(',', $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']));
|
||||
$thisfile_audio['codec'] = $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['name']);
|
||||
|
||||
|
@ -408,7 +412,7 @@ class getid3_asf extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'unknown frequency: "'.$AudioCodecFrequency.'" ('.$this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']).')';
|
||||
$this->warning('unknown frequency: "'.$AudioCodecFrequency.'" ('.$this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']).')');
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -419,6 +423,7 @@ class getid3_asf extends getid3_handler
|
|||
$thisfile_audio['channels'] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -442,7 +447,7 @@ class getid3_asf extends getid3_handler
|
|||
// * Command Name WCHAR variable // array of Unicode characters - name of this command
|
||||
|
||||
// shortcut
|
||||
$thisfile_asf['script_command_object'] = [];
|
||||
$thisfile_asf['script_command_object'] = array();
|
||||
$thisfile_asf_scriptcommandobject = &$thisfile_asf['script_command_object'];
|
||||
|
||||
$thisfile_asf_scriptcommandobject['offset'] = $NextObjectOffset + $offset;
|
||||
|
@ -453,7 +458,7 @@ class getid3_asf extends getid3_handler
|
|||
$offset += 16;
|
||||
$thisfile_asf_scriptcommandobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']);
|
||||
if ($thisfile_asf_scriptcommandobject['reserved'] != $this->GUIDtoBytestring('4B1ACBE3-100B-11D0-A39B-00A0C90348F6')) {
|
||||
$info['warning'][] = 'script_command_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4B1ACBE3-100B-11D0-A39B-00A0C90348F6}';
|
||||
$this->warning('script_command_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4B1ACBE3-100B-11D0-A39B-00A0C90348F6}');
|
||||
//return false;
|
||||
break;
|
||||
}
|
||||
|
@ -501,7 +506,7 @@ class getid3_asf extends getid3_handler
|
|||
// * Padding BYTESTREAM variable // optional padding bytes
|
||||
|
||||
// shortcut
|
||||
$thisfile_asf['marker_object'] = [];
|
||||
$thisfile_asf['marker_object'] = array();
|
||||
$thisfile_asf_markerobject = &$thisfile_asf['marker_object'];
|
||||
|
||||
$thisfile_asf_markerobject['offset'] = $NextObjectOffset + $offset;
|
||||
|
@ -512,7 +517,7 @@ class getid3_asf extends getid3_handler
|
|||
$offset += 16;
|
||||
$thisfile_asf_markerobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_markerobject['reserved']);
|
||||
if ($thisfile_asf_markerobject['reserved'] != $this->GUIDtoBytestring('4CFEDB20-75F6-11CF-9C0F-00A0C90349CB')) {
|
||||
$info['warning'][] = 'marker_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_markerobject['reserved_1']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4CFEDB20-75F6-11CF-9C0F-00A0C90349CB}';
|
||||
$this->warning('marker_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_markerobject['reserved_1']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4CFEDB20-75F6-11CF-9C0F-00A0C90349CB}');
|
||||
break;
|
||||
}
|
||||
$thisfile_asf_markerobject['markers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
|
||||
|
@ -520,7 +525,7 @@ class getid3_asf extends getid3_handler
|
|||
$thisfile_asf_markerobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
|
||||
$offset += 2;
|
||||
if ($thisfile_asf_markerobject['reserved_2'] != 0) {
|
||||
$info['warning'][] = 'marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"';
|
||||
$this->warning('marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"');
|
||||
break;
|
||||
}
|
||||
$thisfile_asf_markerobject['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
|
||||
|
@ -560,7 +565,7 @@ class getid3_asf extends getid3_handler
|
|||
// Stream Numbers WORD variable // array of mutually exclusive video stream numbers. 1 <= valid <= 127
|
||||
|
||||
// shortcut
|
||||
$thisfile_asf['bitrate_mutual_exclusion_object'] = [];
|
||||
$thisfile_asf['bitrate_mutual_exclusion_object'] = array();
|
||||
$thisfile_asf_bitratemutualexclusionobject = &$thisfile_asf['bitrate_mutual_exclusion_object'];
|
||||
|
||||
$thisfile_asf_bitratemutualexclusionobject['offset'] = $NextObjectOffset + $offset;
|
||||
|
@ -571,7 +576,7 @@ class getid3_asf extends getid3_handler
|
|||
$thisfile_asf_bitratemutualexclusionobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']);
|
||||
$offset += 16;
|
||||
if (($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Bitrate) && ($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Unknown)) {
|
||||
$info['warning'][] = 'bitrate_mutual_exclusion_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']).'} does not match expected "GETID3_ASF_Mutex_Bitrate" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Bitrate).'} or "GETID3_ASF_Mutex_Unknown" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Unknown).'}';
|
||||
$this->warning('bitrate_mutual_exclusion_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']).'} does not match expected "GETID3_ASF_Mutex_Bitrate" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Bitrate).'} or "GETID3_ASF_Mutex_Unknown" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Unknown).'}');
|
||||
//return false;
|
||||
break;
|
||||
}
|
||||
|
@ -593,7 +598,7 @@ class getid3_asf extends getid3_handler
|
|||
// Error Correction Data BYTESTREAM variable // structure depends on value of Error Correction Type field
|
||||
|
||||
// shortcut
|
||||
$thisfile_asf['error_correction_object'] = [];
|
||||
$thisfile_asf['error_correction_object'] = array();
|
||||
$thisfile_asf_errorcorrectionobject = &$thisfile_asf['error_correction_object'];
|
||||
|
||||
$thisfile_asf_errorcorrectionobject['offset'] = $NextObjectOffset + $offset;
|
||||
|
@ -632,7 +637,7 @@ class getid3_asf extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'error_correction_object.error_correction_type GUID {'.$this->BytestringToGUID($thisfile_asf_errorcorrectionobject['reserved']).'} does not match expected "GETID3_ASF_No_Error_Correction" GUID {'.$this->BytestringToGUID(GETID3_ASF_No_Error_Correction).'} or "GETID3_ASF_Audio_Spread" GUID {'.$this->BytestringToGUID(GETID3_ASF_Audio_Spread).'}';
|
||||
$this->warning('error_correction_object.error_correction_type GUID {'.$this->BytestringToGUID($thisfile_asf_errorcorrectionobject['reserved']).'} does not match expected "GETID3_ASF_No_Error_Correction" GUID {'.$this->BytestringToGUID(GETID3_ASF_No_Error_Correction).'} or "GETID3_ASF_Audio_Spread" GUID {'.$this->BytestringToGUID(GETID3_ASF_Audio_Spread).'}');
|
||||
//return false;
|
||||
break;
|
||||
}
|
||||
|
@ -656,7 +661,7 @@ class getid3_asf extends getid3_handler
|
|||
// Rating WCHAR 16 // array of Unicode characters - Rating
|
||||
|
||||
// shortcut
|
||||
$thisfile_asf['content_description_object'] = [];
|
||||
$thisfile_asf['content_description_object'] = array();
|
||||
$thisfile_asf_contentdescriptionobject = &$thisfile_asf['content_description_object'];
|
||||
|
||||
$thisfile_asf_contentdescriptionobject['offset'] = $NextObjectOffset + $offset;
|
||||
|
@ -684,7 +689,7 @@ class getid3_asf extends getid3_handler
|
|||
$thisfile_asf_contentdescriptionobject['rating'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['rating_length']);
|
||||
$offset += $thisfile_asf_contentdescriptionobject['rating_length'];
|
||||
|
||||
$ASFcommentKeysToCopy = ['title'=>'title', 'author'=>'artist', 'copyright'=>'copyright', 'description'=>'comment', 'rating'=>'rating'];
|
||||
$ASFcommentKeysToCopy = array('title'=>'title', 'author'=>'artist', 'copyright'=>'copyright', 'description'=>'comment', 'rating'=>'rating');
|
||||
foreach ($ASFcommentKeysToCopy as $keytocopyfrom => $keytocopyto) {
|
||||
if (!empty($thisfile_asf_contentdescriptionobject[$keytocopyfrom])) {
|
||||
$thisfile_asf_comments[$keytocopyto][] = $this->TrimTerm($thisfile_asf_contentdescriptionobject[$keytocopyfrom]);
|
||||
|
@ -712,7 +717,7 @@ class getid3_asf extends getid3_handler
|
|||
// * Descriptor Value variable variable // value for Content Descriptor
|
||||
|
||||
// shortcut
|
||||
$thisfile_asf['extended_content_description_object'] = [];
|
||||
$thisfile_asf['extended_content_description_object'] = array();
|
||||
$thisfile_asf_extendedcontentdescriptionobject = &$thisfile_asf['extended_content_description_object'];
|
||||
|
||||
$thisfile_asf_extendedcontentdescriptionobject['offset'] = $NextObjectOffset + $offset;
|
||||
|
@ -723,7 +728,7 @@ class getid3_asf extends getid3_handler
|
|||
$offset += 2;
|
||||
for ($ExtendedContentDescriptorsCounter = 0; $ExtendedContentDescriptorsCounter < $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count']; $ExtendedContentDescriptorsCounter++) {
|
||||
// shortcut
|
||||
$thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter] = [];
|
||||
$thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter] = array();
|
||||
$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current = &$thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter];
|
||||
|
||||
$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['base_offset'] = $offset + 30;
|
||||
|
@ -756,35 +761,36 @@ class getid3_asf extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'extended_content_description.content_descriptors.'.$ExtendedContentDescriptorsCounter.'.value_type is invalid ('.$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'].')';
|
||||
$this->warning('extended_content_description.content_descriptors.'.$ExtendedContentDescriptorsCounter.'.value_type is invalid ('.$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'].')');
|
||||
//return false;
|
||||
break;
|
||||
}
|
||||
switch ($this->TrimConvert(strtolower($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name']))) {
|
||||
|
||||
case 'wm/albumartist':
|
||||
case 'artist':
|
||||
// Note: not 'artist', that comes from 'author' tag
|
||||
$thisfile_asf_comments['albumartist'] = [$this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])];
|
||||
$thisfile_asf_comments['albumartist'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
|
||||
break;
|
||||
|
||||
case 'wm/albumtitle':
|
||||
case 'album':
|
||||
$thisfile_asf_comments['album'] = [$this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])];
|
||||
$thisfile_asf_comments['album'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
|
||||
break;
|
||||
|
||||
case 'wm/genre':
|
||||
case 'genre':
|
||||
$thisfile_asf_comments['genre'] = [$this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])];
|
||||
$thisfile_asf_comments['genre'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
|
||||
break;
|
||||
|
||||
case 'wm/partofset':
|
||||
$thisfile_asf_comments['partofset'] = [$this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])];
|
||||
$thisfile_asf_comments['partofset'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
|
||||
break;
|
||||
|
||||
case 'wm/tracknumber':
|
||||
case 'tracknumber':
|
||||
// be careful casting to int: casting unicode strings to int gives unexpected results (stops parsing at first non-numeric character)
|
||||
$thisfile_asf_comments['track'] = [$this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])];
|
||||
$thisfile_asf_comments['track'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
|
||||
foreach ($thisfile_asf_comments['track'] as $key => $value) {
|
||||
if (preg_match('/^[0-9\x00]+$/', $value)) {
|
||||
$thisfile_asf_comments['track'][$key] = intval(str_replace("\x00", '', $value));
|
||||
|
@ -794,19 +800,19 @@ class getid3_asf extends getid3_handler
|
|||
|
||||
case 'wm/track':
|
||||
if (empty($thisfile_asf_comments['track'])) {
|
||||
$thisfile_asf_comments['track'] = [1 + $this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])];
|
||||
$thisfile_asf_comments['track'] = array(1 + $this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'wm/year':
|
||||
case 'year':
|
||||
case 'date':
|
||||
$thisfile_asf_comments['year'] = [ $this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])];
|
||||
$thisfile_asf_comments['year'] = array( $this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
|
||||
break;
|
||||
|
||||
case 'wm/lyrics':
|
||||
case 'lyrics':
|
||||
$thisfile_asf_comments['lyrics'] = [$this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])];
|
||||
$thisfile_asf_comments['lyrics'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
|
||||
break;
|
||||
|
||||
case 'isvbr':
|
||||
|
@ -830,7 +836,7 @@ class getid3_asf extends getid3_handler
|
|||
|
||||
case 'wm/encodingtime':
|
||||
$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['encoding_time_unix'] = $this->FILETIMEtoUNIXtime($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
|
||||
$thisfile_asf_comments['encoding_time_unix'] = [$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['encoding_time_unix']];
|
||||
$thisfile_asf_comments['encoding_time_unix'] = array($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['encoding_time_unix']);
|
||||
break;
|
||||
|
||||
case 'wm/picture':
|
||||
|
@ -883,7 +889,7 @@ class getid3_asf extends getid3_handler
|
|||
switch ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type']) {
|
||||
case 0: // Unicode string
|
||||
if (substr($this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name']), 0, 3) == 'WM/') {
|
||||
$thisfile_asf_comments[str_replace('wm/', '', strtolower($this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name'])))] = [$this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])];
|
||||
$thisfile_asf_comments[str_replace('wm/', '', strtolower($this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name'])))] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -892,6 +898,7 @@ class getid3_asf extends getid3_handler
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -908,7 +915,7 @@ class getid3_asf extends getid3_handler
|
|||
// * Average Bitrate DWORD 32 // in bits per second
|
||||
|
||||
// shortcut
|
||||
$thisfile_asf['stream_bitrate_properties_object'] = [];
|
||||
$thisfile_asf['stream_bitrate_properties_object'] = array();
|
||||
$thisfile_asf_streambitratepropertiesobject = &$thisfile_asf['stream_bitrate_properties_object'];
|
||||
|
||||
$thisfile_asf_streambitratepropertiesobject['offset'] = $NextObjectOffset + $offset;
|
||||
|
@ -934,7 +941,7 @@ class getid3_asf extends getid3_handler
|
|||
// Padding Data BYTESTREAM variable // ignore
|
||||
|
||||
// shortcut
|
||||
$thisfile_asf['padding_object'] = [];
|
||||
$thisfile_asf['padding_object'] = array();
|
||||
$thisfile_asf_paddingobject = &$thisfile_asf['padding_object'];
|
||||
|
||||
$thisfile_asf_paddingobject['offset'] = $NextObjectOffset + $offset;
|
||||
|
@ -955,9 +962,9 @@ class getid3_asf extends getid3_handler
|
|||
default:
|
||||
// Implementations shall ignore any standard or non-standard object that they do not know how to handle.
|
||||
if ($this->GUIDname($NextObjectGUIDtext)) {
|
||||
$info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8);
|
||||
$this->warning('unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8));
|
||||
} else {
|
||||
$info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8);
|
||||
$this->warning('unknown GUID {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8));
|
||||
}
|
||||
$offset += ($NextObjectSize - 16 - 8);
|
||||
break;
|
||||
|
@ -991,10 +998,12 @@ class getid3_asf extends getid3_handler
|
|||
}
|
||||
}
|
||||
if (isset($thisfile_asf['stream_properties_object']) && is_array($thisfile_asf['stream_properties_object'])) {
|
||||
|
||||
$thisfile_audio['bitrate'] = 0;
|
||||
$thisfile_video['bitrate'] = 0;
|
||||
|
||||
foreach ($thisfile_asf['stream_properties_object'] as $streamnumber => $streamdata) {
|
||||
|
||||
switch ($streamdata['stream_type']) {
|
||||
case GETID3_ASF_Audio_Media:
|
||||
// Field Name Field Type Size (bits)
|
||||
|
@ -1008,7 +1017,7 @@ class getid3_asf extends getid3_handler
|
|||
// Codec Specific Data BYTESTREAM variable // array of codec-specific data bytes
|
||||
|
||||
// shortcut
|
||||
$thisfile_asf['audio_media'][$streamnumber] = [];
|
||||
$thisfile_asf['audio_media'][$streamnumber] = array();
|
||||
$thisfile_asf_audiomedia_currentstream = &$thisfile_asf['audio_media'][$streamnumber];
|
||||
|
||||
$audiomediaoffset = 0;
|
||||
|
@ -1074,7 +1083,7 @@ class getid3_asf extends getid3_handler
|
|||
// * Codec Specific Data BYTESTREAM variable // array of codec-specific data bytes
|
||||
|
||||
// shortcut
|
||||
$thisfile_asf['video_media'][$streamnumber] = [];
|
||||
$thisfile_asf['video_media'][$streamnumber] = array();
|
||||
$thisfile_asf_videomedia_currentstream = &$thisfile_asf['video_media'][$streamnumber];
|
||||
|
||||
$videomediaoffset = 0;
|
||||
|
@ -1156,7 +1165,7 @@ class getid3_asf extends getid3_handler
|
|||
// Reserved WORD 16 // hardcoded: 0x0101
|
||||
|
||||
// shortcut
|
||||
$thisfile_asf['data_object'] = [];
|
||||
$thisfile_asf['data_object'] = array();
|
||||
$thisfile_asf_dataobject = &$thisfile_asf['data_object'];
|
||||
|
||||
$DataObjectData = $NextObjectDataHeader.$this->fread(50 - 24);
|
||||
|
@ -1174,7 +1183,7 @@ class getid3_asf extends getid3_handler
|
|||
$thisfile_asf_dataobject['reserved'] = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 2));
|
||||
$offset += 2;
|
||||
if ($thisfile_asf_dataobject['reserved'] != 0x0101) {
|
||||
$info['warning'][] = 'data_object.reserved ('.getid3_lib::PrintHexBytes($thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"';
|
||||
$this->warning('data_object.reserved ('.getid3_lib::PrintHexBytes($thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"');
|
||||
//return false;
|
||||
break;
|
||||
}
|
||||
|
@ -1206,7 +1215,7 @@ class getid3_asf extends getid3_handler
|
|||
// * Packet Count WORD 16 // number of Data Packets to sent at this index entry
|
||||
|
||||
// shortcut
|
||||
$thisfile_asf['simple_index_object'] = [];
|
||||
$thisfile_asf['simple_index_object'] = array();
|
||||
$thisfile_asf_simpleindexobject = &$thisfile_asf['simple_index_object'];
|
||||
|
||||
$SimpleIndexObjectData = $NextObjectDataHeader.$this->fread(56 - 24);
|
||||
|
@ -1260,7 +1269,7 @@ class getid3_asf extends getid3_handler
|
|||
// * * Offsets DWORD varies // An offset value of 0xffffffff indicates an invalid offset value
|
||||
|
||||
// shortcut
|
||||
$thisfile_asf['asf_index_object'] = [];
|
||||
$thisfile_asf['asf_index_object'] = array();
|
||||
$thisfile_asf_asfindexobject = &$thisfile_asf['asf_index_object'];
|
||||
|
||||
$ASFIndexObjectData = $NextObjectDataHeader.$this->fread(34 - 24);
|
||||
|
@ -1310,9 +1319,9 @@ class getid3_asf extends getid3_handler
|
|||
default:
|
||||
// Implementations shall ignore any standard or non-standard object that they do not know how to handle.
|
||||
if ($this->GUIDname($NextObjectGUIDtext)) {
|
||||
$info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF body at offset '.($offset - 16 - 8);
|
||||
$this->warning('unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF body at offset '.($offset - 16 - 8));
|
||||
} else {
|
||||
$info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF body at offset '.($this->ftell() - 16 - 8);
|
||||
$this->warning('unknown GUID {'.$NextObjectGUIDtext.'} in ASF body at offset '.($this->ftell() - 16 - 8));
|
||||
}
|
||||
$this->fseek(($NextObjectSize - 16 - 8), SEEK_CUR);
|
||||
break;
|
||||
|
@ -1362,6 +1371,7 @@ class getid3_asf extends getid3_handler
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1380,6 +1390,7 @@ class getid3_asf extends getid3_handler
|
|||
if (isset($thisfile_asf_codeclistobject['codec_entries'])) {
|
||||
foreach ($thisfile_asf_codeclistobject['codec_entries'] as $streamnumber => $streamdata) {
|
||||
switch ($streamdata['type_raw']) {
|
||||
|
||||
case 1: // video
|
||||
$thisfile_video['encoder'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][$streamnumber]['name']);
|
||||
break;
|
||||
|
@ -1394,8 +1405,9 @@ class getid3_asf extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unknown streamtype: [codec_list_object][codec_entries]['.$streamnumber.'][type_raw] == '.$streamdata['type_raw'];
|
||||
$this->warning('Unknown streamtype: [codec_list_object][codec_entries]['.$streamnumber.'][type_raw] == '.$streamdata['type_raw']);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1428,20 +1440,18 @@ class getid3_asf extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public static function codecListObjectTypeLookup($CodecListType)
|
||||
{
|
||||
static $lookup = [
|
||||
public static function codecListObjectTypeLookup($CodecListType) {
|
||||
static $lookup = array(
|
||||
0x0001 => 'Video Codec',
|
||||
0x0002 => 'Audio Codec',
|
||||
0xFFFF => 'Unknown Codec'
|
||||
];
|
||||
);
|
||||
|
||||
return (isset($lookup[$CodecListType]) ? $lookup[$CodecListType] : 'Invalid Codec Type');
|
||||
}
|
||||
|
||||
public static function KnownGUIDs()
|
||||
{
|
||||
static $GUIDarray = [
|
||||
public static function KnownGUIDs() {
|
||||
static $GUIDarray = array(
|
||||
'GETID3_ASF_Extended_Stream_Properties_Object' => '14E6A5CB-C672-4332-8399-A96952065B5A',
|
||||
'GETID3_ASF_Padding_Object' => '1806D474-CADF-4509-A4BA-9AABCB96AAE8',
|
||||
'GETID3_ASF_Payload_Ext_Syst_Pixel_Aspect_Ratio' => '1B1EE554-F9EA-4BC8-821A-376B74E4C4B8',
|
||||
|
@ -1550,22 +1560,20 @@ class getid3_asf extends getid3_handler
|
|||
'GETID3_ASF_Alt_Extended_Content_Encryption_Obj' => 'FF889EF1-ADEE-40DA-9E71-98704BB928CE',
|
||||
'GETID3_ASF_Index_Placeholder_Object' => 'D9AADE20-7C17-4F9C-BC28-8555DD98E2A2', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html
|
||||
'GETID3_ASF_Compatibility_Object' => '26F18B5D-4584-47EC-9F5F-0E651F0452C9', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html
|
||||
];
|
||||
);
|
||||
return $GUIDarray;
|
||||
}
|
||||
|
||||
public static function GUIDname($GUIDstring)
|
||||
{
|
||||
static $GUIDarray = [];
|
||||
public static function GUIDname($GUIDstring) {
|
||||
static $GUIDarray = array();
|
||||
if (empty($GUIDarray)) {
|
||||
$GUIDarray = self::KnownGUIDs();
|
||||
}
|
||||
return array_search($GUIDstring, $GUIDarray);
|
||||
}
|
||||
|
||||
public static function ASFIndexObjectIndexTypeLookup($id)
|
||||
{
|
||||
static $ASFIndexObjectIndexTypeLookup = [];
|
||||
public static function ASFIndexObjectIndexTypeLookup($id) {
|
||||
static $ASFIndexObjectIndexTypeLookup = array();
|
||||
if (empty($ASFIndexObjectIndexTypeLookup)) {
|
||||
$ASFIndexObjectIndexTypeLookup[1] = 'Nearest Past Data Packet';
|
||||
$ASFIndexObjectIndexTypeLookup[2] = 'Nearest Past Media Object';
|
||||
|
@ -1574,8 +1582,7 @@ class getid3_asf extends getid3_handler
|
|||
return (isset($ASFIndexObjectIndexTypeLookup[$id]) ? $ASFIndexObjectIndexTypeLookup[$id] : 'invalid');
|
||||
}
|
||||
|
||||
public static function GUIDtoBytestring($GUIDstring)
|
||||
{
|
||||
public static function GUIDtoBytestring($GUIDstring) {
|
||||
// Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way:
|
||||
// first 4 bytes are in little-endian order
|
||||
// next 2 bytes are appended in little-endian order
|
||||
|
@ -1610,8 +1617,7 @@ class getid3_asf extends getid3_handler
|
|||
return $hexbytecharstring;
|
||||
}
|
||||
|
||||
public static function BytestringToGUID($Bytestring)
|
||||
{
|
||||
public static function BytestringToGUID($Bytestring) {
|
||||
$GUIDstring = str_pad(dechex(ord($Bytestring{3})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{2})), 2, '0', STR_PAD_LEFT);
|
||||
$GUIDstring .= str_pad(dechex(ord($Bytestring{1})), 2, '0', STR_PAD_LEFT);
|
||||
|
@ -1636,8 +1642,7 @@ class getid3_asf extends getid3_handler
|
|||
return strtoupper($GUIDstring);
|
||||
}
|
||||
|
||||
public static function FILETIMEtoUNIXtime($FILETIME, $round = true)
|
||||
{
|
||||
public static function FILETIMEtoUNIXtime($FILETIME, $round=true) {
|
||||
// FILETIME is a 64-bit unsigned integer representing
|
||||
// the number of 100-nanosecond intervals since January 1, 1601
|
||||
// UNIX timestamp is number of seconds since January 1, 1970
|
||||
|
@ -1648,11 +1653,10 @@ class getid3_asf extends getid3_handler
|
|||
return ($FILETIME - 116444736000000000) / 10000000;
|
||||
}
|
||||
|
||||
public static function WMpictureTypeLookup($WMpictureType)
|
||||
{
|
||||
public static function WMpictureTypeLookup($WMpictureType) {
|
||||
static $lookup = null;
|
||||
if ($lookup === null) {
|
||||
$lookup = [
|
||||
$lookup = array(
|
||||
0x03 => 'Front Cover',
|
||||
0x04 => 'Back Cover',
|
||||
0x00 => 'User Defined',
|
||||
|
@ -1671,7 +1675,7 @@ class getid3_asf extends getid3_handler
|
|||
0x12 => 'Illustration',
|
||||
0x13 => 'Band Logotype',
|
||||
0x14 => 'Publisher Logotype'
|
||||
];
|
||||
);
|
||||
$lookup = array_map(function($str) {
|
||||
return getid3_lib::iconv_fallback('UTF-8', 'UTF-16LE', $str);
|
||||
}, $lookup);
|
||||
|
@ -1680,16 +1684,15 @@ class getid3_asf extends getid3_handler
|
|||
return (isset($lookup[$WMpictureType]) ? $lookup[$WMpictureType] : '');
|
||||
}
|
||||
|
||||
public function HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections)
|
||||
{
|
||||
public function HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) {
|
||||
// http://msdn.microsoft.com/en-us/library/bb643323.aspx
|
||||
|
||||
$offset = 0;
|
||||
$objectOffset = 0;
|
||||
$HeaderExtensionObjectParsed = [];
|
||||
$HeaderExtensionObjectParsed = array();
|
||||
while ($objectOffset < strlen($asf_header_extension_object_data)) {
|
||||
$offset = $objectOffset;
|
||||
$thisObject = [];
|
||||
$thisObject = array();
|
||||
|
||||
$thisObject['guid'] = substr($asf_header_extension_object_data, $offset, 16);
|
||||
$offset += 16;
|
||||
|
@ -1756,7 +1759,7 @@ class getid3_asf extends getid3_handler
|
|||
$offset += 2;
|
||||
|
||||
for ($i = 0; $i < $thisObject['stream_name_count']; $i++) {
|
||||
$streamName = [];
|
||||
$streamName = array();
|
||||
|
||||
$streamName['language_id_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
|
||||
$offset += 2;
|
||||
|
@ -1771,7 +1774,7 @@ class getid3_asf extends getid3_handler
|
|||
}
|
||||
|
||||
for ($i = 0; $i < $thisObject['payload_extension_system_count']; $i++) {
|
||||
$payloadExtensionSystem = [];
|
||||
$payloadExtensionSystem = array();
|
||||
|
||||
$payloadExtensionSystem['extension_system_id'] = substr($asf_header_extension_object_data, $offset, 16);
|
||||
$offset += 16;
|
||||
|
@ -1803,7 +1806,7 @@ class getid3_asf extends getid3_handler
|
|||
$offset += 2;
|
||||
|
||||
for ($i = 0; $i < $thisObject['description_record_counts']; $i++) {
|
||||
$descriptionRecord = [];
|
||||
$descriptionRecord = array();
|
||||
|
||||
$descriptionRecord['reserved_1'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); // must be zero
|
||||
$offset += 2;
|
||||
|
@ -1858,7 +1861,7 @@ class getid3_asf extends getid3_handler
|
|||
$offset += 2;
|
||||
|
||||
for ($i = 0; $i < $thisObject['language_id_record_counts']; $i++) {
|
||||
$languageIDrecord = [];
|
||||
$languageIDrecord = array();
|
||||
|
||||
$languageIDrecord['language_id_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 1));
|
||||
$offset += 1;
|
||||
|
@ -1875,7 +1878,7 @@ class getid3_asf extends getid3_handler
|
|||
$offset += 2;
|
||||
|
||||
for ($i = 0; $i < $thisObject['description_records_count']; $i++) {
|
||||
$descriptionRecord = [];
|
||||
$descriptionRecord = array();
|
||||
|
||||
$descriptionRecord['language_list_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
|
||||
$offset += 2;
|
||||
|
@ -1914,9 +1917,9 @@ class getid3_asf extends getid3_handler
|
|||
default:
|
||||
$unhandled_sections++;
|
||||
if ($this->GUIDname($thisObject['guid_text'])) {
|
||||
$this->getid3->info['warning'][] = 'unhandled Header Extension Object GUID "'.$this->GUIDname($thisObject['guid_text']).'" {'.$thisObject['guid_text'].'} at offset '.($offset - 16 - 8);
|
||||
$this->warning('unhandled Header Extension Object GUID "'.$this->GUIDname($thisObject['guid_text']).'" {'.$thisObject['guid_text'].'} at offset '.($offset - 16 - 8));
|
||||
} else {
|
||||
$this->getid3->info['warning'][] = 'unknown Header Extension Object GUID {'.$thisObject['guid_text'].'} in at offset '.($offset - 16 - 8);
|
||||
$this->warning('unknown Header Extension Object GUID {'.$thisObject['guid_text'].'} in at offset '.($offset - 16 - 8));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1928,9 +1931,8 @@ class getid3_asf extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public static function metadataLibraryObjectDataTypeLookup($id)
|
||||
{
|
||||
static $lookup = [
|
||||
public static function metadataLibraryObjectDataTypeLookup($id) {
|
||||
static $lookup = array(
|
||||
0x0000 => 'Unicode string', // The data consists of a sequence of Unicode characters
|
||||
0x0001 => 'BYTE array', // The type of the data is implementation-specific
|
||||
0x0002 => 'BOOL', // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer. Only 0x0000 or 0x0001 are permitted values
|
||||
|
@ -1938,12 +1940,11 @@ class getid3_asf extends getid3_handler
|
|||
0x0004 => 'QWORD', // The data is 8 bytes long and should be interpreted as a 64-bit unsigned integer
|
||||
0x0005 => 'WORD', // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer
|
||||
0x0006 => 'GUID', // The data is 16 bytes long and should be interpreted as a 128-bit GUID
|
||||
];
|
||||
);
|
||||
return (isset($lookup[$id]) ? $lookup[$id] : 'invalid');
|
||||
}
|
||||
|
||||
public function ASF_WMpicture(&$data)
|
||||
{
|
||||
public function ASF_WMpicture(&$data) {
|
||||
//typedef struct _WMPicture{
|
||||
// LPWSTR pwszMIMEType;
|
||||
// BYTE bPictureType;
|
||||
|
@ -1952,7 +1953,7 @@ class getid3_asf extends getid3_handler
|
|||
// BYTE* pbData;
|
||||
//} WM_PICTURE;
|
||||
|
||||
$WMpicture = [];
|
||||
$WMpicture = array();
|
||||
|
||||
$offset = 0;
|
||||
$WMpicture['image_type_id'] = getid3_lib::LittleEndian2Int(substr($data, $offset, 1));
|
||||
|
@ -1978,7 +1979,7 @@ class getid3_asf extends getid3_handler
|
|||
$WMpicture['dataoffset'] = $offset;
|
||||
$WMpicture['data'] = substr($data, $offset);
|
||||
|
||||
$imageinfo = [];
|
||||
$imageinfo = array();
|
||||
$WMpicture['image_mime'] = '';
|
||||
$imagechunkcheck = getid3_lib::GetDataImageSize($WMpicture['data'], $imageinfo);
|
||||
unset($imageinfo);
|
||||
|
@ -1986,28 +1987,27 @@ class getid3_asf extends getid3_handler
|
|||
$WMpicture['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
|
||||
}
|
||||
if (!isset($this->getid3->info['asf']['comments']['picture'])) {
|
||||
$this->getid3->info['asf']['comments']['picture'] = [];
|
||||
$this->getid3->info['asf']['comments']['picture'] = array();
|
||||
}
|
||||
$this->getid3->info['asf']['comments']['picture'][] = ['data'=>$WMpicture['data'], 'image_mime'=>$WMpicture['image_mime']];
|
||||
$this->getid3->info['asf']['comments']['picture'][] = array('data'=>$WMpicture['data'], 'image_mime'=>$WMpicture['image_mime']);
|
||||
|
||||
return $WMpicture;
|
||||
}
|
||||
|
||||
|
||||
// Remove terminator 00 00 and convert UTF-16LE to Latin-1
|
||||
public static function TrimConvert($string)
|
||||
{
|
||||
public static function TrimConvert($string) {
|
||||
return trim(getid3_lib::iconv_fallback('UTF-16LE', 'ISO-8859-1', self::TrimTerm($string)), ' ');
|
||||
}
|
||||
|
||||
|
||||
// Remove terminator 00 00
|
||||
public static function TrimTerm($string)
|
||||
{
|
||||
public static function TrimTerm($string) {
|
||||
// remove terminator, only if present (it should be, but...)
|
||||
if (substr($string, -2) === "\x00\x00") {
|
||||
$string = substr($string, 0, -2);
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,11 +18,10 @@
|
|||
class getid3_bink extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['error'][] = 'Bink / Smacker files not properly processed by this version of getID3() ['.$this->getid3->version().']';
|
||||
$this->error('Bink / Smacker files not properly processed by this version of getID3() ['.$this->getid3->version().']');
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$fileTypeID = $this->fread(3);
|
||||
|
@ -36,16 +35,16 @@ class getid3_bink extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Expecting "BIK" or "SMK" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($fileTypeID).'"';
|
||||
$this->error('Expecting "BIK" or "SMK" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($fileTypeID).'"');
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function ParseBink()
|
||||
{
|
||||
public function ParseBink() {
|
||||
$info = &$this->getid3->info;
|
||||
$info['fileformat'] = 'bink';
|
||||
$info['video']['dataformat'] = 'bink';
|
||||
|
@ -56,18 +55,18 @@ class getid3_bink extends getid3_handler
|
|||
$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']);
|
||||
$this->error('Probably truncated file: expecting '.$info['bink']['data_size'].' bytes, found '.($info['avdataend'] - $info['avdataoffset']));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function ParseSmacker()
|
||||
{
|
||||
public function ParseSmacker() {
|
||||
$info = &$this->getid3->info;
|
||||
$info['fileformat'] = 'smacker';
|
||||
$info['video']['dataformat'] = 'smacker';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -73,15 +73,13 @@ define('H264_PROFILE_HIGH422', 122);
|
|||
define('H264_PROFILE_HIGH444', 144);
|
||||
define('H264_PROFILE_HIGH444_PREDICTIVE', 244);
|
||||
|
||||
class getid3_flv extends getid3_handler
|
||||
{
|
||||
class getid3_flv extends getid3_handler {
|
||||
|
||||
const magic = 'FLV';
|
||||
|
||||
public $max_frames = 100000; // break out of the loop if too many frames have been scanned; only scan this many if meta frame does not contain useful duration
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
@ -95,7 +93,7 @@ class getid3_flv extends getid3_handler
|
|||
$TypeFlags = getid3_lib::BigEndian2Int(substr($FLVheader, 4, 1));
|
||||
|
||||
if ($info['flv']['header']['signature'] != self::magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(self::magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['flv']['header']['signature']).'"';
|
||||
$this->error('Expecting "'.getid3_lib::PrintHexBytes(self::magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['flv']['header']['signature']).'"');
|
||||
unset($info['flv'], $info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
|
@ -114,7 +112,7 @@ class getid3_flv extends getid3_handler
|
|||
$found_meta = false;
|
||||
$found_valid_meta_playtime = false;
|
||||
$tagParseCount = 0;
|
||||
$info['flv']['framecount'] = ['total'=>0, 'audio'=>0, 'video'=>0];
|
||||
$info['flv']['framecount'] = array('total'=>0, 'audio'=>0, 'video'=>0);
|
||||
$flv_framecount = &$info['flv']['framecount'];
|
||||
while ((($this->ftell() + 16) < $info['avdataend']) && (($tagParseCount++ <= $this->max_frames) || !$found_valid_meta_playtime)) {
|
||||
$ThisTagHeader = $this->fread(16);
|
||||
|
@ -178,7 +176,9 @@ class getid3_flv extends getid3_handler
|
|||
}
|
||||
}
|
||||
// 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;
|
||||
|
@ -233,8 +233,11 @@ class getid3_flv extends getid3_handler
|
|||
$info['video']['resolution_x'] = 0;
|
||||
$info['video']['resolution_y'] = 0;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
} elseif ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_VP6FLV_ALPHA) {
|
||||
|
||||
/* contributed by schouwerwouØgmail*com */
|
||||
if (!isset($info['video']['resolution_x'])) { // only when meta data isn't set
|
||||
$PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 2));
|
||||
|
@ -243,6 +246,7 @@ class getid3_flv extends getid3_handler
|
|||
$info['video']['resolution_y'] = ($PictureSizeEnc['y'] & 0xFF) << 3;
|
||||
}
|
||||
/* end schouwerwouØgmail*com */
|
||||
|
||||
}
|
||||
if (!empty($info['video']['resolution_x']) && !empty($info['video']['resolution_y'])) {
|
||||
$info['video']['pixel_aspect_ratio'] = $info['video']['resolution_x'] / $info['video']['resolution_y'];
|
||||
|
@ -262,7 +266,7 @@ class getid3_flv extends getid3_handler
|
|||
$info['flv']['meta'][$eventName] = $reader->readData();
|
||||
unset($reader);
|
||||
|
||||
$copykeys = ['framerate'=>'frame_rate', 'width'=>'resolution_x', 'height'=>'resolution_y', 'audiodatarate'=>'bitrate', 'videodatarate'=>'bitrate'];
|
||||
$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) {
|
||||
|
@ -329,9 +333,8 @@ class getid3_flv extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public static function audioFormatLookup($id)
|
||||
{
|
||||
static $lookup = [
|
||||
public static function audioFormatLookup($id) {
|
||||
static $lookup = array(
|
||||
0 => 'Linear PCM, platform endian',
|
||||
1 => 'ADPCM',
|
||||
2 => 'mp3',
|
||||
|
@ -348,136 +351,118 @@ class getid3_flv extends getid3_handler
|
|||
13 => false, // unknown?
|
||||
14 => 'mp3 8kHz',
|
||||
15 => 'Device-specific sound',
|
||||
];
|
||||
);
|
||||
return (isset($lookup[$id]) ? $lookup[$id] : false);
|
||||
}
|
||||
|
||||
public static function audioRateLookup($id)
|
||||
{
|
||||
static $lookup = [
|
||||
public static function audioRateLookup($id) {
|
||||
static $lookup = array(
|
||||
0 => 5500,
|
||||
1 => 11025,
|
||||
2 => 22050,
|
||||
3 => 44100,
|
||||
];
|
||||
);
|
||||
return (isset($lookup[$id]) ? $lookup[$id] : false);
|
||||
}
|
||||
|
||||
public static function audioBitDepthLookup($id)
|
||||
{
|
||||
static $lookup = [
|
||||
public static function audioBitDepthLookup($id) {
|
||||
static $lookup = array(
|
||||
0 => 8,
|
||||
1 => 16,
|
||||
];
|
||||
);
|
||||
return (isset($lookup[$id]) ? $lookup[$id] : false);
|
||||
}
|
||||
|
||||
public static function videoCodecLookup($id)
|
||||
{
|
||||
static $lookup = [
|
||||
public static function videoCodecLookup($id) {
|
||||
static $lookup = array(
|
||||
GETID3_FLV_VIDEO_H263 => 'Sorenson H.263',
|
||||
GETID3_FLV_VIDEO_SCREEN => 'Screen video',
|
||||
GETID3_FLV_VIDEO_VP6FLV => 'On2 VP6',
|
||||
GETID3_FLV_VIDEO_VP6FLV_ALPHA => 'On2 VP6 with alpha channel',
|
||||
GETID3_FLV_VIDEO_SCREENV2 => 'Screen video v2',
|
||||
GETID3_FLV_VIDEO_H264 => 'Sorenson H.264',
|
||||
];
|
||||
);
|
||||
return (isset($lookup[$id]) ? $lookup[$id] : false);
|
||||
}
|
||||
}
|
||||
|
||||
class AMFStream
|
||||
{
|
||||
class AMFStream {
|
||||
public $bytes;
|
||||
public $pos;
|
||||
|
||||
public function __construct(&$bytes)
|
||||
{
|
||||
public function __construct(&$bytes) {
|
||||
$this->bytes =& $bytes;
|
||||
$this->pos = 0;
|
||||
}
|
||||
|
||||
public function readByte()
|
||||
{
|
||||
public function readByte() {
|
||||
return getid3_lib::BigEndian2Int(substr($this->bytes, $this->pos++, 1));
|
||||
}
|
||||
|
||||
public function readInt()
|
||||
{
|
||||
public function readInt() {
|
||||
return ($this->readByte() << 8) + $this->readByte();
|
||||
}
|
||||
|
||||
public function readLong()
|
||||
{
|
||||
public function readLong() {
|
||||
return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte();
|
||||
}
|
||||
|
||||
public function readDouble()
|
||||
{
|
||||
public function readDouble() {
|
||||
return getid3_lib::BigEndian2Float($this->read(8));
|
||||
}
|
||||
|
||||
public function readUTF()
|
||||
{
|
||||
public function readUTF() {
|
||||
$length = $this->readInt();
|
||||
return $this->read($length);
|
||||
}
|
||||
|
||||
public function readLongUTF()
|
||||
{
|
||||
public function readLongUTF() {
|
||||
$length = $this->readLong();
|
||||
return $this->read($length);
|
||||
}
|
||||
|
||||
public function read($length)
|
||||
{
|
||||
public function read($length) {
|
||||
$val = substr($this->bytes, $this->pos, $length);
|
||||
$this->pos += $length;
|
||||
return $val;
|
||||
}
|
||||
|
||||
public function peekByte()
|
||||
{
|
||||
public function peekByte() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readByte();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
|
||||
public function peekInt()
|
||||
{
|
||||
public function peekInt() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readInt();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
|
||||
public function peekLong()
|
||||
{
|
||||
public function peekLong() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readLong();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
|
||||
public function peekDouble()
|
||||
{
|
||||
public function peekDouble() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readDouble();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
|
||||
public function peekUTF()
|
||||
{
|
||||
public function peekUTF() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readUTF();
|
||||
$this->pos = $pos;
|
||||
return $val;
|
||||
}
|
||||
|
||||
public function peekLongUTF()
|
||||
{
|
||||
public function peekLongUTF() {
|
||||
$pos = $this->pos;
|
||||
$val = $this->readLongUTF();
|
||||
$this->pos = $pos;
|
||||
|
@ -485,21 +470,19 @@ class AMFStream
|
|||
}
|
||||
}
|
||||
|
||||
class AMFReader
|
||||
{
|
||||
class AMFReader {
|
||||
public $stream;
|
||||
|
||||
public function __construct(&$stream)
|
||||
{
|
||||
public function __construct(&$stream) {
|
||||
$this->stream =& $stream;
|
||||
}
|
||||
|
||||
public function readData()
|
||||
{
|
||||
public function readData() {
|
||||
$value = null;
|
||||
|
||||
$type = $this->stream->readByte();
|
||||
switch ($type) {
|
||||
|
||||
// Double
|
||||
case 0:
|
||||
$value = $this->readDouble();
|
||||
|
@ -564,27 +547,23 @@ class AMFReader
|
|||
return $value;
|
||||
}
|
||||
|
||||
public function readDouble()
|
||||
{
|
||||
public function readDouble() {
|
||||
return $this->stream->readDouble();
|
||||
}
|
||||
|
||||
public function readBoolean()
|
||||
{
|
||||
public function readBoolean() {
|
||||
return $this->stream->readByte() == 1;
|
||||
}
|
||||
|
||||
public function readString()
|
||||
{
|
||||
public function readString() {
|
||||
return $this->stream->readUTF();
|
||||
}
|
||||
|
||||
public function readObject()
|
||||
{
|
||||
public function readObject() {
|
||||
// Get highest numerical index - ignored
|
||||
// $highestIndex = $this->stream->readLong();
|
||||
|
||||
$data = [];
|
||||
$data = array();
|
||||
|
||||
while ($key = $this->stream->readUTF()) {
|
||||
$data[$key] = $this->readData();
|
||||
|
@ -597,12 +576,11 @@ class AMFReader
|
|||
return $data;
|
||||
}
|
||||
|
||||
public function readMixedArray()
|
||||
{
|
||||
public function readMixedArray() {
|
||||
// Get highest numerical index - ignored
|
||||
$highestIndex = $this->stream->readLong();
|
||||
|
||||
$data = [];
|
||||
$data = array();
|
||||
|
||||
while ($key = $this->stream->readUTF()) {
|
||||
if (is_numeric($key)) {
|
||||
|
@ -619,10 +597,9 @@ class AMFReader
|
|||
return $data;
|
||||
}
|
||||
|
||||
public function readArray()
|
||||
{
|
||||
public function readArray() {
|
||||
$length = $this->stream->readLong();
|
||||
$data = [];
|
||||
$data = array();
|
||||
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$data[] = $this->readData();
|
||||
|
@ -630,32 +607,27 @@ class AMFReader
|
|||
return $data;
|
||||
}
|
||||
|
||||
public function readDate()
|
||||
{
|
||||
public function readDate() {
|
||||
$timestamp = $this->stream->readDouble();
|
||||
$timezone = $this->stream->readInt();
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
public function readLongString()
|
||||
{
|
||||
public function readLongString() {
|
||||
return $this->stream->readLongUTF();
|
||||
}
|
||||
|
||||
public function readXML()
|
||||
{
|
||||
public function readXML() {
|
||||
return $this->stream->readLongUTF();
|
||||
}
|
||||
|
||||
public function readTypedObject()
|
||||
{
|
||||
public function readTypedObject() {
|
||||
$className = $this->stream->readUTF();
|
||||
return $this->readObject();
|
||||
}
|
||||
}
|
||||
|
||||
class AVCSequenceParameterSetReader
|
||||
{
|
||||
class AVCSequenceParameterSetReader {
|
||||
public $sps;
|
||||
public $start = 0;
|
||||
public $currentBytes = 0;
|
||||
|
@ -663,13 +635,11 @@ class AVCSequenceParameterSetReader
|
|||
public $width;
|
||||
public $height;
|
||||
|
||||
public function __construct($sps)
|
||||
{
|
||||
public function __construct($sps) {
|
||||
$this->sps = $sps;
|
||||
}
|
||||
|
||||
public function readData()
|
||||
{
|
||||
public function readData() {
|
||||
$this->skipBits(8);
|
||||
$this->skipBits(8);
|
||||
$profile = $this->getBits(8); // read profile
|
||||
|
@ -721,22 +691,19 @@ class AVCSequenceParameterSetReader
|
|||
}
|
||||
}
|
||||
|
||||
public function skipBits($bits)
|
||||
{
|
||||
public function skipBits($bits) {
|
||||
$newBits = $this->currentBits + $bits;
|
||||
$this->currentBytes += (int)floor($newBits / 8);
|
||||
$this->currentBits = $newBits % 8;
|
||||
}
|
||||
|
||||
public function getBit()
|
||||
{
|
||||
public function getBit() {
|
||||
$result = (getid3_lib::BigEndian2Int(substr($this->sps, $this->currentBytes, 1)) >> (7 - $this->currentBits)) & 0x01;
|
||||
$this->skipBits(1);
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getBits($bits)
|
||||
{
|
||||
public function getBits($bits) {
|
||||
$result = 0;
|
||||
for ($i = 0; $i < $bits; $i++) {
|
||||
$result = ($result << 1) + $this->getBit();
|
||||
|
@ -744,8 +711,7 @@ class AVCSequenceParameterSetReader
|
|||
return $result;
|
||||
}
|
||||
|
||||
public function expGolombUe()
|
||||
{
|
||||
public function expGolombUe() {
|
||||
$significantBits = 0;
|
||||
$bit = $this->getBit();
|
||||
while ($bit == 0) {
|
||||
|
@ -760,8 +726,7 @@ class AVCSequenceParameterSetReader
|
|||
return (1 << $significantBits) + $this->getBits($significantBits) - 1;
|
||||
}
|
||||
|
||||
public function expGolombSe()
|
||||
{
|
||||
public function expGolombSe() {
|
||||
$result = $this->expGolombUe();
|
||||
if (($result & 0x01) == 0) {
|
||||
return -($result >> 1);
|
||||
|
@ -770,13 +735,11 @@ class AVCSequenceParameterSetReader
|
|||
}
|
||||
}
|
||||
|
||||
public function getWidth()
|
||||
{
|
||||
public function getWidth() {
|
||||
return $this->width;
|
||||
}
|
||||
|
||||
public function getHeight()
|
||||
{
|
||||
public function getHeight() {
|
||||
return $this->height;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -224,7 +224,7 @@ class getid3_matroska extends getid3_handler
|
|||
private $EBMLbuffer_offset = 0;
|
||||
private $EBMLbuffer_length = 0;
|
||||
private $current_offset = 0;
|
||||
private $unuseful_elements = [EBML_ID_CRC32, EBML_ID_VOID];
|
||||
private $unuseful_elements = array(EBML_ID_CRC32, EBML_ID_VOID);
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
|
@ -234,7 +234,7 @@ class getid3_matroska extends getid3_handler
|
|||
try {
|
||||
$this->parseEBML($info);
|
||||
} catch (Exception $e) {
|
||||
$info['error'][] = 'EBML parser: '.$e->getMessage();
|
||||
$this->error('EBML parser: '.$e->getMessage());
|
||||
}
|
||||
|
||||
// calculate playtime
|
||||
|
@ -258,14 +258,14 @@ class getid3_matroska extends getid3_handler
|
|||
// process tracks
|
||||
if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
|
||||
foreach ($info['matroska']['tracks']['tracks'] as $key => $trackarray) {
|
||||
$track_info = [];
|
||||
|
||||
$track_info = array();
|
||||
$track_info['dataformat'] = self::CodecIDtoCommonName($trackarray['CodecID']);
|
||||
$track_info['default'] = (isset($trackarray['FlagDefault']) ? $trackarray['FlagDefault'] : true);
|
||||
if (isset($trackarray['Name'])) {
|
||||
$track_info['name'] = $trackarray['Name'];
|
||||
}
|
||||
if (isset($trackarray['Name'])) { $track_info['name'] = $trackarray['Name']; }
|
||||
|
||||
switch ($trackarray['TrackType']) {
|
||||
|
||||
case 1: // Video
|
||||
$track_info['resolution_x'] = $trackarray['PixelWidth'];
|
||||
$track_info['resolution_y'] = $trackarray['PixelHeight'];
|
||||
|
@ -273,24 +273,12 @@ class getid3_matroska extends getid3_handler
|
|||
$track_info['display_x'] = (isset($trackarray['DisplayWidth']) ? $trackarray['DisplayWidth'] : $trackarray['PixelWidth']);
|
||||
$track_info['display_y'] = (isset($trackarray['DisplayHeight']) ? $trackarray['DisplayHeight'] : $trackarray['PixelHeight']);
|
||||
|
||||
if (isset($trackarray['PixelCropBottom'])) {
|
||||
$track_info['crop_bottom'] = $trackarray['PixelCropBottom'];
|
||||
}
|
||||
if (isset($trackarray['PixelCropTop'])) {
|
||||
$track_info['crop_top'] = $trackarray['PixelCropTop'];
|
||||
}
|
||||
if (isset($trackarray['PixelCropLeft'])) {
|
||||
$track_info['crop_left'] = $trackarray['PixelCropLeft'];
|
||||
}
|
||||
if (isset($trackarray['PixelCropRight'])) {
|
||||
$track_info['crop_right'] = $trackarray['PixelCropRight'];
|
||||
}
|
||||
if (isset($trackarray['DefaultDuration'])) {
|
||||
$track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3);
|
||||
}
|
||||
if (isset($trackarray['CodecName'])) {
|
||||
$track_info['codec'] = $trackarray['CodecName'];
|
||||
}
|
||||
if (isset($trackarray['PixelCropBottom'])) { $track_info['crop_bottom'] = $trackarray['PixelCropBottom']; }
|
||||
if (isset($trackarray['PixelCropTop'])) { $track_info['crop_top'] = $trackarray['PixelCropTop']; }
|
||||
if (isset($trackarray['PixelCropLeft'])) { $track_info['crop_left'] = $trackarray['PixelCropLeft']; }
|
||||
if (isset($trackarray['PixelCropRight'])) { $track_info['crop_right'] = $trackarray['PixelCropRight']; }
|
||||
if (isset($trackarray['DefaultDuration'])) { $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3); }
|
||||
if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; }
|
||||
|
||||
switch ($trackarray['CodecID']) {
|
||||
case 'V_MS/VFW/FOURCC':
|
||||
|
@ -332,12 +320,8 @@ class getid3_matroska extends getid3_handler
|
|||
$track_info['sample_rate'] = (isset($trackarray['SamplingFrequency']) ? $trackarray['SamplingFrequency'] : 8000.0);
|
||||
$track_info['channels'] = (isset($trackarray['Channels']) ? $trackarray['Channels'] : 1);
|
||||
$track_info['language'] = (isset($trackarray['Language']) ? $trackarray['Language'] : 'eng');
|
||||
if (isset($trackarray['BitDepth'])) {
|
||||
$track_info['bits_per_sample'] = $trackarray['BitDepth'];
|
||||
}
|
||||
if (isset($trackarray['CodecName'])) {
|
||||
$track_info['codec'] = $trackarray['CodecName'];
|
||||
}
|
||||
if (isset($trackarray['BitDepth'])) { $track_info['bits_per_sample'] = $trackarray['BitDepth']; }
|
||||
if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; }
|
||||
|
||||
switch ($trackarray['CodecID']) {
|
||||
case 'A_PCM/INT/LIT':
|
||||
|
@ -346,11 +330,13 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case 'A_AC3':
|
||||
case 'A_EAC3':
|
||||
case 'A_DTS':
|
||||
case 'A_MPEG/L3':
|
||||
case 'A_MPEG/L2':
|
||||
case 'A_FLAC':
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.'.($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']).'.php', __FILE__, true);
|
||||
$module_dataformat = ($track_info['dataformat'] == 'mp2' ? 'mp3' : ($track_info['dataformat'] == 'eac3' ? 'ac3' : $track_info['dataformat']));
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.'.$module_dataformat.'.php', __FILE__, true);
|
||||
|
||||
if (!isset($info['matroska']['track_data_offsets'][$trackarray['TrackNumber']])) {
|
||||
$this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because $info[matroska][track_data_offsets]['.$trackarray['TrackNumber'].'] not set');
|
||||
|
@ -368,12 +354,13 @@ class getid3_matroska extends getid3_handler
|
|||
}
|
||||
|
||||
// analyze
|
||||
$class = 'getid3_'.($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']);
|
||||
$class = 'getid3_'.$module_dataformat;
|
||||
$header_data_key = $track_info['dataformat'][0] == 'm' ? 'mpeg' : $track_info['dataformat'];
|
||||
$getid3_audio = new $class($getid3_temp, __CLASS__);
|
||||
if ($track_info['dataformat'] == 'flac') {
|
||||
$getid3_audio->AnalyzeString($trackarray['CodecPrivate']);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$getid3_audio->Analyze();
|
||||
}
|
||||
if (!empty($getid3_temp->info[$header_data_key])) {
|
||||
|
@ -383,7 +370,8 @@ class getid3_matroska extends getid3_handler
|
|||
$track_info[$key] = $value;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because '.$class.'::Analyze() failed at offset '.$getid3_temp->info['avdataoffset']);
|
||||
}
|
||||
|
||||
|
@ -491,7 +479,7 @@ class getid3_matroska extends getid3_handler
|
|||
if (isset($info['matroska']['attachments']) && $this->getid3->option_save_attachments !== getID3::ATTACHMENTS_NONE) {
|
||||
foreach ($info['matroska']['attachments'] as $i => $entry) {
|
||||
if (strpos($entry['FileMimeType'], 'image/') === 0 && !empty($entry['FileData'])) {
|
||||
$info['matroska']['comments']['picture'][] = ['data' => $entry['FileData'], 'image_mime' => $entry['FileMimeType'], 'filename' => $entry['FileName']];
|
||||
$info['matroska']['comments']['picture'][] = array('data' => $entry['FileData'], 'image_mime' => $entry['FileMimeType'], 'filename' => $entry['FileName']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -508,19 +496,20 @@ class getid3_matroska extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
private function parseEBML(&$info)
|
||||
{
|
||||
private function parseEBML(&$info) {
|
||||
// http://www.matroska.org/technical/specs/index.html#EBMLBasics
|
||||
$this->current_offset = $info['avdataoffset'];
|
||||
|
||||
while ($this->getEBMLelement($top_element, $info['avdataend'])) {
|
||||
switch ($top_element['id']) {
|
||||
|
||||
case EBML_ID_EBML:
|
||||
$info['matroska']['header']['offset'] = $top_element['offset'];
|
||||
$info['matroska']['header']['length'] = $top_element['length'];
|
||||
|
||||
while ($this->getEBMLelement($element_data, $top_element['end'], true)) {
|
||||
switch ($element_data['id']) {
|
||||
|
||||
case EBML_ID_EBMLVERSION:
|
||||
case EBML_ID_EBMLREADVERSION:
|
||||
case EBML_ID_EBMLMAXIDLENGTH:
|
||||
|
@ -555,12 +544,17 @@ class getid3_matroska extends getid3_handler
|
|||
$info['matroska']['segments'][] = $element_data;
|
||||
}
|
||||
switch ($element_data['id']) {
|
||||
case EBML_ID_SEEKHEAD:
|
||||
|
||||
case EBML_ID_SEEKHEAD: // Contains the position of other level 1 elements.
|
||||
|
||||
while ($this->getEBMLelement($seek_entry, $element_data['end'])) {
|
||||
switch ($seek_entry['id']) {
|
||||
|
||||
case EBML_ID_SEEK: // Contains a single seek entry to an EBML element
|
||||
while ($this->getEBMLelement($sub_seek_entry, $seek_entry['end'], true)) {
|
||||
|
||||
switch ($sub_seek_entry['id']) {
|
||||
|
||||
case EBML_ID_SEEKID:
|
||||
$seek_entry['target_id'] = self::EBML2Int($sub_seek_entry['data']);
|
||||
$seek_entry['target_name'] = self::EBMLidName($seek_entry['target_id']);
|
||||
|
@ -571,12 +565,14 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$this->unhandledElement('seekhead.seek', __LINE__, $sub_seek_entry);
|
||||
}
|
||||
$this->unhandledElement('seekhead.seek', __LINE__, $sub_seek_entry); }
|
||||
break;
|
||||
}
|
||||
|
||||
if ($seek_entry['target_id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required
|
||||
if (!isset($seek_entry['target_id'])) {
|
||||
$this->warning('seek_entry[target_id] unexpectedly not set at '.$seek_entry['offset']);
|
||||
break;
|
||||
}
|
||||
if (($seek_entry['target_id'] != EBML_ID_CLUSTER) || !self::$hide_clusters) { // collect clusters only if required
|
||||
$info['matroska']['seek'][] = $seek_entry;
|
||||
}
|
||||
break;
|
||||
|
@ -593,9 +589,12 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
while ($this->getEBMLelement($track_entry, $element_data['end'])) {
|
||||
switch ($track_entry['id']) {
|
||||
case EBML_ID_TRACKENTRY:
|
||||
while ($this->getEBMLelement($subelement, $track_entry['end'], [EBML_ID_VIDEO, EBML_ID_AUDIO, EBML_ID_CONTENTENCODINGS, EBML_ID_CODECPRIVATE])) {
|
||||
|
||||
case EBML_ID_TRACKENTRY: //subelements: Describes a track with all elements.
|
||||
|
||||
while ($this->getEBMLelement($subelement, $track_entry['end'], array(EBML_ID_VIDEO, EBML_ID_AUDIO, EBML_ID_CONTENTENCODINGS, EBML_ID_CODECPRIVATE))) {
|
||||
switch ($subelement['id']) {
|
||||
|
||||
case EBML_ID_TRACKNUMBER:
|
||||
case EBML_ID_TRACKUID:
|
||||
case EBML_ID_TRACKTYPE:
|
||||
|
@ -630,8 +629,10 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case EBML_ID_VIDEO:
|
||||
|
||||
while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
|
||||
switch ($sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_PIXELWIDTH:
|
||||
case EBML_ID_PIXELHEIGHT:
|
||||
case EBML_ID_PIXELCROPBOTTOM:
|
||||
|
@ -667,8 +668,10 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case EBML_ID_AUDIO:
|
||||
|
||||
while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
|
||||
switch ($sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_CHANNELS:
|
||||
case EBML_ID_BITDEPTH:
|
||||
$track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
|
||||
|
@ -691,11 +694,15 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case EBML_ID_CONTENTENCODINGS:
|
||||
|
||||
while ($this->getEBMLelement($sub_subelement, $subelement['end'])) {
|
||||
switch ($sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_CONTENTENCODING:
|
||||
while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], [EBML_ID_CONTENTCOMPRESSION, EBML_ID_CONTENTENCRYPTION])) {
|
||||
|
||||
while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], array(EBML_ID_CONTENTCOMPRESSION, EBML_ID_CONTENTENCRYPTION))) {
|
||||
switch ($sub_sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_CONTENTENCODINGORDER:
|
||||
case EBML_ID_CONTENTENCODINGSCOPE:
|
||||
case EBML_ID_CONTENTENCODINGTYPE:
|
||||
|
@ -703,8 +710,10 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case EBML_ID_CONTENTCOMPRESSION:
|
||||
|
||||
while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
|
||||
switch ($sub_sub_sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_CONTENTCOMPALGO:
|
||||
$track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
|
||||
break;
|
||||
|
@ -721,8 +730,10 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case EBML_ID_CONTENTENCRYPTION:
|
||||
|
||||
while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
|
||||
switch ($sub_sub_sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_CONTENTENCALGO:
|
||||
case EBML_ID_CONTENTSIGALGO:
|
||||
case EBML_ID_CONTENTSIGHASHALGO:
|
||||
|
@ -773,10 +784,11 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case EBML_ID_INFO: // Contains miscellaneous general information and statistics on the file.
|
||||
$info_entry = [];
|
||||
$info_entry = array();
|
||||
|
||||
while ($this->getEBMLelement($subelement, $element_data['end'], true)) {
|
||||
switch ($subelement['id']) {
|
||||
|
||||
case EBML_ID_TIMECODESCALE:
|
||||
$info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
|
||||
break;
|
||||
|
@ -811,10 +823,11 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case EBML_ID_CHAPTERTRANSLATE:
|
||||
$chaptertranslate_entry = [];
|
||||
$chaptertranslate_entry = array();
|
||||
|
||||
while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
|
||||
switch ($sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_CHAPTERTRANSLATEEDITIONUID:
|
||||
$chaptertranslate_entry[$sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_subelement['data']);
|
||||
break;
|
||||
|
@ -848,20 +861,23 @@ class getid3_matroska extends getid3_handler
|
|||
$this->current_offset = $element_data['end'];
|
||||
break;
|
||||
}
|
||||
$cues_entry = [];
|
||||
$cues_entry = array();
|
||||
|
||||
while ($this->getEBMLelement($subelement, $element_data['end'])) {
|
||||
switch ($subelement['id']) {
|
||||
case EBML_ID_CUEPOINT:
|
||||
$cuepoint_entry = [];
|
||||
|
||||
while ($this->getEBMLelement($sub_subelement, $subelement['end'], [EBML_ID_CUETRACKPOSITIONS])) {
|
||||
case EBML_ID_CUEPOINT:
|
||||
$cuepoint_entry = array();
|
||||
|
||||
while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CUETRACKPOSITIONS))) {
|
||||
switch ($sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_CUETRACKPOSITIONS:
|
||||
$cuetrackpositions_entry = [];
|
||||
$cuetrackpositions_entry = array();
|
||||
|
||||
while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], true)) {
|
||||
switch ($sub_sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_CUETRACK:
|
||||
case EBML_ID_CUECLUSTERPOSITION:
|
||||
case EBML_ID_CUEBLOCKNUMBER:
|
||||
|
@ -898,20 +914,23 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case EBML_ID_TAGS: // Element containing elements specific to Tracks/Chapters.
|
||||
$tags_entry = [];
|
||||
$tags_entry = array();
|
||||
|
||||
while ($this->getEBMLelement($subelement, $element_data['end'], false)) {
|
||||
switch ($subelement['id']) {
|
||||
|
||||
case EBML_ID_TAG:
|
||||
$tag_entry = [];
|
||||
$tag_entry = array();
|
||||
|
||||
while ($this->getEBMLelement($sub_subelement, $subelement['end'], false)) {
|
||||
switch ($sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_TARGETS:
|
||||
$targets_entry = [];
|
||||
$targets_entry = array();
|
||||
|
||||
while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], true)) {
|
||||
switch ($sub_sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_TARGETTYPEVALUE:
|
||||
$targets_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
|
||||
$targets_entry[strtolower($sub_sub_subelement['id_name']).'_long'] = self::TargetTypeValue($targets_entry[$sub_sub_subelement['id_name']]);
|
||||
|
@ -956,14 +975,17 @@ class getid3_matroska extends getid3_handler
|
|||
$info['matroska']['tags'] = $tags_entry;
|
||||
break;
|
||||
|
||||
case EBML_ID_ATTACHMENTS:
|
||||
case EBML_ID_ATTACHMENTS: // Contain attached files.
|
||||
|
||||
while ($this->getEBMLelement($subelement, $element_data['end'])) {
|
||||
switch ($subelement['id']) {
|
||||
case EBML_ID_ATTACHEDFILE:
|
||||
$attachedfile_entry = [];
|
||||
|
||||
while ($this->getEBMLelement($sub_subelement, $subelement['end'], [EBML_ID_FILEDATA])) {
|
||||
case EBML_ID_ATTACHEDFILE:
|
||||
$attachedfile_entry = array();
|
||||
|
||||
while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_FILEDATA))) {
|
||||
switch ($sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_FILEDESCRIPTION:
|
||||
case EBML_ID_FILENAME:
|
||||
case EBML_ID_FILEMIMETYPE:
|
||||
|
@ -977,8 +999,7 @@ class getid3_matroska extends getid3_handler
|
|||
$attachedfile_entry[$sub_subelement['id_name']] = $this->saveAttachment(
|
||||
$attachedfile_entry['FileName'],
|
||||
$attachedfile_entry['data_offset'],
|
||||
$attachedfile_entry['data_length']
|
||||
);
|
||||
$attachedfile_entry['data_length']);
|
||||
|
||||
$this->current_offset = $sub_subelement['end'];
|
||||
break;
|
||||
|
@ -1003,13 +1024,16 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case EBML_ID_CHAPTERS:
|
||||
|
||||
while ($this->getEBMLelement($subelement, $element_data['end'])) {
|
||||
switch ($subelement['id']) {
|
||||
case EBML_ID_EDITIONENTRY:
|
||||
$editionentry_entry = [];
|
||||
|
||||
while ($this->getEBMLelement($sub_subelement, $subelement['end'], [EBML_ID_CHAPTERATOM])) {
|
||||
case EBML_ID_EDITIONENTRY:
|
||||
$editionentry_entry = array();
|
||||
|
||||
while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CHAPTERATOM))) {
|
||||
switch ($sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_EDITIONUID:
|
||||
$editionentry_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
|
||||
break;
|
||||
|
@ -1021,10 +1045,11 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case EBML_ID_CHAPTERATOM:
|
||||
$chapteratom_entry = [];
|
||||
$chapteratom_entry = array();
|
||||
|
||||
while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], [EBML_ID_CHAPTERTRACK, EBML_ID_CHAPTERDISPLAY])) {
|
||||
while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], array(EBML_ID_CHAPTERTRACK, EBML_ID_CHAPTERDISPLAY))) {
|
||||
switch ($sub_sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_CHAPTERSEGMENTUID:
|
||||
case EBML_ID_CHAPTERSEGMENTEDITIONUID:
|
||||
$chapteratom_entry[$sub_sub_subelement['id_name']] = $sub_sub_subelement['data'];
|
||||
|
@ -1042,10 +1067,11 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case EBML_ID_CHAPTERTRACK:
|
||||
$chaptertrack_entry = [];
|
||||
$chaptertrack_entry = array();
|
||||
|
||||
while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
|
||||
switch ($sub_sub_sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_CHAPTERTRACKNUMBER:
|
||||
$chaptertrack_entry[$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
|
||||
break;
|
||||
|
@ -1059,10 +1085,11 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case EBML_ID_CHAPTERDISPLAY:
|
||||
$chapterdisplay_entry = [];
|
||||
$chapterdisplay_entry = array();
|
||||
|
||||
while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
|
||||
switch ($sub_sub_sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_CHAPSTRING:
|
||||
case EBML_ID_CHAPLANGUAGE:
|
||||
case EBML_ID_CHAPCOUNTRY:
|
||||
|
@ -1101,10 +1128,11 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case EBML_ID_CLUSTER: // The lower level element containing the (monolithic) Block structure.
|
||||
$cluster_entry = [];
|
||||
$cluster_entry = array();
|
||||
|
||||
while ($this->getEBMLelement($subelement, $element_data['end'], [EBML_ID_CLUSTERSILENTTRACKS, EBML_ID_CLUSTERBLOCKGROUP, EBML_ID_CLUSTERSIMPLEBLOCK])) {
|
||||
while ($this->getEBMLelement($subelement, $element_data['end'], array(EBML_ID_CLUSTERSILENTTRACKS, EBML_ID_CLUSTERBLOCKGROUP, EBML_ID_CLUSTERSIMPLEBLOCK))) {
|
||||
switch ($subelement['id']) {
|
||||
|
||||
case EBML_ID_CLUSTERTIMECODE:
|
||||
case EBML_ID_CLUSTERPOSITION:
|
||||
case EBML_ID_CLUSTERPREVSIZE:
|
||||
|
@ -1112,10 +1140,11 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case EBML_ID_CLUSTERSILENTTRACKS:
|
||||
$cluster_silent_tracks = [];
|
||||
$cluster_silent_tracks = array();
|
||||
|
||||
while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
|
||||
switch ($sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_CLUSTERSILENTTRACKNUMBER:
|
||||
$cluster_silent_tracks[] = getid3_lib::BigEndian2Int($sub_subelement['data']);
|
||||
break;
|
||||
|
@ -1129,10 +1158,11 @@ class getid3_matroska extends getid3_handler
|
|||
break;
|
||||
|
||||
case EBML_ID_CLUSTERBLOCKGROUP:
|
||||
$cluster_block_group = ['offset' => $this->current_offset];
|
||||
$cluster_block_group = array('offset' => $this->current_offset);
|
||||
|
||||
while ($this->getEBMLelement($sub_subelement, $subelement['end'], [EBML_ID_CLUSTERBLOCK])) {
|
||||
while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CLUSTERBLOCK))) {
|
||||
switch ($sub_subelement['id']) {
|
||||
|
||||
case EBML_ID_CLUSTERBLOCK:
|
||||
$cluster_block_group[$sub_subelement['id_name']] = $this->HandleEMBLClusterBlock($sub_subelement, EBML_ID_CLUSTERBLOCK, $info);
|
||||
break;
|
||||
|
@ -1198,8 +1228,7 @@ class getid3_matroska extends getid3_handler
|
|||
}
|
||||
}
|
||||
|
||||
private function EnsureBufferHasEnoughData($min_data = 1024)
|
||||
{
|
||||
private function EnsureBufferHasEnoughData($min_data=1024) {
|
||||
if (($this->current_offset - $this->EBMLbuffer_offset) >= ($this->EBMLbuffer_length - $min_data)) {
|
||||
$read_bytes = max($min_data, $this->getid3->fread_buffer_size());
|
||||
|
||||
|
@ -1220,8 +1249,7 @@ class getid3_matroska extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
private function readEBMLint()
|
||||
{
|
||||
private function readEBMLint() {
|
||||
$actual_offset = $this->current_offset - $this->EBMLbuffer_offset;
|
||||
|
||||
// get length of integer
|
||||
|
@ -1253,8 +1281,7 @@ class getid3_matroska extends getid3_handler
|
|||
return $int_value;
|
||||
}
|
||||
|
||||
private function readEBMLelementData($length, $check_buffer = false)
|
||||
{
|
||||
private function readEBMLelementData($length, $check_buffer=false) {
|
||||
if ($check_buffer && !$this->EnsureBufferHasEnoughData($length)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1263,8 +1290,7 @@ class getid3_matroska extends getid3_handler
|
|||
return $data;
|
||||
}
|
||||
|
||||
private function getEBMLelement(&$element, $parent_end, $get_data = false)
|
||||
{
|
||||
private function getEBMLelement(&$element, $parent_end, $get_data=false) {
|
||||
if ($this->current_offset >= $parent_end) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1274,7 +1300,7 @@ class getid3_matroska extends getid3_handler
|
|||
return false;
|
||||
}
|
||||
|
||||
$element = [];
|
||||
$element = array();
|
||||
|
||||
// set offset
|
||||
$element['offset'] = $this->current_offset;
|
||||
|
@ -1300,8 +1326,7 @@ class getid3_matroska extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
private function unhandledElement($type, $line, $element)
|
||||
{
|
||||
private function unhandledElement($type, $line, $element) {
|
||||
// warn only about unknown and missed elements, not about unuseful
|
||||
if (!in_array($element['id'], $this->unuseful_elements)) {
|
||||
$this->warning('Unhandled '.$type.' element ['.basename(__FILE__).':'.$line.'] ('.$element['id'].'::'.$element['id_name'].' ['.$element['length'].' bytes]) at '.$element['offset']);
|
||||
|
@ -1313,8 +1338,7 @@ class getid3_matroska extends getid3_handler
|
|||
}
|
||||
}
|
||||
|
||||
private function ExtractCommentsSimpleTag($SimpleTagArray)
|
||||
{
|
||||
private function ExtractCommentsSimpleTag($SimpleTagArray) {
|
||||
if (!empty($SimpleTagArray['SimpleTag'])) {
|
||||
foreach ($SimpleTagArray['SimpleTag'] as $SimpleTagKey => $SimpleTagData) {
|
||||
if (!empty($SimpleTagData['TagName']) && !empty($SimpleTagData['TagString'])) {
|
||||
|
@ -1329,12 +1353,12 @@ class getid3_matroska extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
private function HandleEMBLSimpleTag($parent_end)
|
||||
{
|
||||
$simpletag_entry = [];
|
||||
private function HandleEMBLSimpleTag($parent_end) {
|
||||
$simpletag_entry = array();
|
||||
|
||||
while ($this->getEBMLelement($element, $parent_end, [EBML_ID_SIMPLETAG])) {
|
||||
while ($this->getEBMLelement($element, $parent_end, array(EBML_ID_SIMPLETAG))) {
|
||||
switch ($element['id']) {
|
||||
|
||||
case EBML_ID_TAGNAME:
|
||||
case EBML_ID_TAGLANGUAGE:
|
||||
case EBML_ID_TAGSTRING:
|
||||
|
@ -1359,12 +1383,11 @@ class getid3_matroska extends getid3_handler
|
|||
return $simpletag_entry;
|
||||
}
|
||||
|
||||
private function HandleEMBLClusterBlock($element, $block_type, &$info)
|
||||
{
|
||||
private function HandleEMBLClusterBlock($element, $block_type, &$info) {
|
||||
// http://www.matroska.org/technical/specs/index.html#block_structure
|
||||
// http://www.matroska.org/technical/specs/index.html#simpleblock_structure
|
||||
|
||||
$block_data = [];
|
||||
$block_data = array();
|
||||
$block_data['tracknumber'] = $this->readEBMLint();
|
||||
$block_data['timecode'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(2), false, true);
|
||||
$block_data['flags_raw'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(1));
|
||||
|
@ -1372,14 +1395,16 @@ class getid3_matroska extends getid3_handler
|
|||
if ($block_type == EBML_ID_CLUSTERSIMPLEBLOCK) {
|
||||
$block_data['flags']['keyframe'] = (($block_data['flags_raw'] & 0x80) >> 7);
|
||||
//$block_data['flags']['reserved1'] = (($block_data['flags_raw'] & 0x70) >> 4);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
//$block_data['flags']['reserved1'] = (($block_data['flags_raw'] & 0xF0) >> 4);
|
||||
}
|
||||
$block_data['flags']['invisible'] = (bool)(($block_data['flags_raw'] & 0x08) >> 3);
|
||||
$block_data['flags']['lacing'] = (($block_data['flags_raw'] & 0x06) >> 1); // 00=no lacing; 01=Xiph lacing; 11=EBML lacing; 10=fixed-size lacing
|
||||
if ($block_type == EBML_ID_CLUSTERSIMPLEBLOCK) {
|
||||
$block_data['flags']['discardable'] = (($block_data['flags_raw'] & 0x01));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
//$block_data['flags']['reserved2'] = (($block_data['flags_raw'] & 0x01) >> 0);
|
||||
}
|
||||
$block_data['flags']['lacing_type'] = self::BlockLacingType($block_data['flags']['lacing']);
|
||||
|
@ -1391,12 +1416,14 @@ class getid3_matroska extends getid3_handler
|
|||
for ($i = 1; $i < $block_data['lace_frames']; $i ++) { // Lace-coded size of each frame of the lace, except for the last one (multiple uint8). *This is not used with Fixed-size lacing as it is calculated automatically from (total size of lace) / (number of frames in lace).
|
||||
if ($block_data['flags']['lacing'] == 0x03) { // EBML lacing
|
||||
$block_data['lace_frames_size'][$i] = $this->readEBMLint(); // TODO: read size correctly, calc size for the last frame. For now offsets are deteminded OK with readEBMLint() and that's the most important thing.
|
||||
} else { // Xiph lacing
|
||||
}
|
||||
else { // Xiph lacing
|
||||
$block_data['lace_frames_size'][$i] = 0;
|
||||
do {
|
||||
$size = getid3_lib::BigEndian2Int($this->readEBMLelementData(1));
|
||||
$block_data['lace_frames_size'][$i] += $size;
|
||||
} while ($size == 255);
|
||||
}
|
||||
while ($size == 255);
|
||||
}
|
||||
}
|
||||
if ($block_data['flags']['lacing'] == 0x01) { // calc size of the last frame only for Xiph lacing, till EBML sizes are now anyway determined incorrectly
|
||||
|
@ -1419,8 +1446,7 @@ class getid3_matroska extends getid3_handler
|
|||
return $block_data;
|
||||
}
|
||||
|
||||
private static function EBML2Int($EBMLstring)
|
||||
{
|
||||
private static function EBML2Int($EBMLstring) {
|
||||
// http://matroska.org/specs/
|
||||
|
||||
// Element ID coded with an UTF-8 like system:
|
||||
|
@ -1462,17 +1488,15 @@ class getid3_matroska extends getid3_handler
|
|||
return getid3_lib::BigEndian2Int($EBMLstring);
|
||||
}
|
||||
|
||||
private static function EBMLdate2unix($EBMLdatestamp)
|
||||
{
|
||||
private static function EBMLdate2unix($EBMLdatestamp) {
|
||||
// Date - signed 8 octets integer in nanoseconds with 0 indicating the precise beginning of the millennium (at 2001-01-01T00:00:00,000000000 UTC)
|
||||
// 978307200 == mktime(0, 0, 0, 1, 1, 2001) == January 1, 2001 12:00:00am UTC
|
||||
return round(($EBMLdatestamp / 1000000000) + 978307200);
|
||||
}
|
||||
|
||||
public static function TargetTypeValue($target_type)
|
||||
{
|
||||
public static function TargetTypeValue($target_type) {
|
||||
// http://www.matroska.org/technical/specs/tagging/index.html
|
||||
static $TargetTypeValue = [];
|
||||
static $TargetTypeValue = array();
|
||||
if (empty($TargetTypeValue)) {
|
||||
$TargetTypeValue[10] = 'A: ~ V:shot'; // the lowest hierarchy found in music or movies
|
||||
$TargetTypeValue[20] = 'A:subtrack/part/movement ~ V:scene'; // corresponds to parts of a track for audio (like a movement)
|
||||
|
@ -1485,10 +1509,9 @@ class getid3_matroska extends getid3_handler
|
|||
return (isset($TargetTypeValue[$target_type]) ? $TargetTypeValue[$target_type] : $target_type);
|
||||
}
|
||||
|
||||
public static function BlockLacingType($lacingtype)
|
||||
{
|
||||
public static function BlockLacingType($lacingtype) {
|
||||
// http://matroska.org/technical/specs/index.html#block_structure
|
||||
static $BlockLacingType = [];
|
||||
static $BlockLacingType = array();
|
||||
if (empty($BlockLacingType)) {
|
||||
$BlockLacingType[0x00] = 'no lacing';
|
||||
$BlockLacingType[0x01] = 'Xiph lacing';
|
||||
|
@ -1498,14 +1521,14 @@ class getid3_matroska extends getid3_handler
|
|||
return (isset($BlockLacingType[$lacingtype]) ? $BlockLacingType[$lacingtype] : $lacingtype);
|
||||
}
|
||||
|
||||
public static function CodecIDtoCommonName($codecid)
|
||||
{
|
||||
public static function CodecIDtoCommonName($codecid) {
|
||||
// http://www.matroska.org/technical/specs/codecid/index.html
|
||||
static $CodecIDlist = [];
|
||||
static $CodecIDlist = array();
|
||||
if (empty($CodecIDlist)) {
|
||||
$CodecIDlist['A_AAC'] = 'aac';
|
||||
$CodecIDlist['A_AAC/MPEG2/LC'] = 'aac';
|
||||
$CodecIDlist['A_AC3'] = 'ac3';
|
||||
$CodecIDlist['A_EAC3'] = 'eac3';
|
||||
$CodecIDlist['A_DTS'] = 'dts';
|
||||
$CodecIDlist['A_FLAC'] = 'flac';
|
||||
$CodecIDlist['A_MPEG/L1'] = 'mp1';
|
||||
|
@ -1534,9 +1557,8 @@ class getid3_matroska extends getid3_handler
|
|||
return (isset($CodecIDlist[$codecid]) ? $CodecIDlist[$codecid] : $codecid);
|
||||
}
|
||||
|
||||
private static function EBMLidName($value)
|
||||
{
|
||||
static $EBMLidList = [];
|
||||
private static function EBMLidName($value) {
|
||||
static $EBMLidList = array();
|
||||
if (empty($EBMLidList)) {
|
||||
$EBMLidList[EBML_ID_ASPECTRATIOTYPE] = 'AspectRatioType';
|
||||
$EBMLidList[EBML_ID_ATTACHEDFILE] = 'AttachedFile';
|
||||
|
@ -1733,14 +1755,13 @@ class getid3_matroska extends getid3_handler
|
|||
return (isset($EBMLidList[$value]) ? $EBMLidList[$value] : dechex($value));
|
||||
}
|
||||
|
||||
public static function displayUnit($value)
|
||||
{
|
||||
public static function displayUnit($value) {
|
||||
// http://www.matroska.org/technical/specs/index.html#DisplayUnit
|
||||
static $units = [
|
||||
static $units = array(
|
||||
0 => 'pixels',
|
||||
1 => 'centimeters',
|
||||
2 => 'inches',
|
||||
3 => 'Display Aspect Ratio'];
|
||||
3 => 'Display Aspect Ratio');
|
||||
|
||||
return (isset($units[$value]) ? $units[$value] : 'unknown');
|
||||
}
|
||||
|
@ -1753,7 +1774,7 @@ class getid3_matroska extends getid3_handler
|
|||
}
|
||||
}
|
||||
|
||||
$unset = ['default', 'name'];
|
||||
$unset = array('default', 'name');
|
||||
foreach ($unset as $u) {
|
||||
if (isset($stream[$u])) {
|
||||
unset($stream[$u]);
|
||||
|
@ -1765,4 +1786,5 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
return $info;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
|
||||
|
||||
class getid3_mpeg extends getid3_handler
|
||||
{
|
||||
class getid3_mpeg extends getid3_handler {
|
||||
|
||||
const START_CODE_BASE = "\x00\x00\x01";
|
||||
const VIDEO_PICTURE_START = "\x00\x00\x01\x00";
|
||||
|
@ -30,8 +29,7 @@ class getid3_mpeg extends getid3_handler
|
|||
const AUDIO_START = "\x00\x00\x01\xC0";
|
||||
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'mpeg';
|
||||
|
@ -45,8 +43,8 @@ class getid3_mpeg extends getid3_handler
|
|||
$prevStartCodeValue = false;
|
||||
|
||||
$GOPcounter = -1;
|
||||
$FramesByGOP = [];
|
||||
$ParsedAVchannels = [];
|
||||
$FramesByGOP = array();
|
||||
$ParsedAVchannels = array();
|
||||
|
||||
do {
|
||||
//echo $MPEGstreamDataOffset.' vs '.(strlen($MPEGstreamData) - 1024).'<Br>';
|
||||
|
@ -71,12 +69,13 @@ class getid3_mpeg extends getid3_handler
|
|||
}
|
||||
$MPEGstreamDataOffset += 4;
|
||||
switch ($StartCodeValue) {
|
||||
|
||||
case 0x00: // picture_start_code
|
||||
if (!empty($info['mpeg']['video']['bitrate_mode']) && ($info['mpeg']['video']['bitrate_mode'] == 'vbr')) {
|
||||
$bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 4, 4));
|
||||
$bitstreamoffset = 0;
|
||||
|
||||
$PictureHeader = [];
|
||||
$PictureHeader = array();
|
||||
|
||||
$PictureHeader['temporal_reference'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 10); // 10-bit unsigned integer associated with each input picture. It is incremented by one, modulo 1024, for each input frame. When a frame is coded as two fields the temporal reference in the picture header of both fields is the same. Following a group start header the temporal reference of the earliest picture (in display order) shall be reset to zero.
|
||||
$PictureHeader['picture_coding_type'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 3); // 3 bits for picture_coding_type
|
||||
|
@ -263,7 +262,7 @@ class getid3_mpeg extends getid3_handler
|
|||
$bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 4, 4)); // 27 bits needed for group_of_pictures_header
|
||||
$bitstreamoffset = 0;
|
||||
|
||||
$GOPheader = [];
|
||||
$GOPheader = array();
|
||||
|
||||
$GOPheader['byte_offset'] = $MPEGstreamBaseOffset + $StartCodeOffset;
|
||||
$GOPheader['drop_frame_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: drop_frame_flag
|
||||
|
@ -460,7 +459,7 @@ $PackedElementaryStream['additional_header_bytes'] = $additional_header_bytes;
|
|||
// // 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.';
|
||||
// //$this->warning('Interleaved MPEG audio/video playtime may be inaccurate. With current hack should be within a few seconds of accurate. Report to info@getid3.org if off by more than 10 seconds.');
|
||||
// if ($info['video']['bitrate'] < 50000) {
|
||||
// $this->warning('Interleaved MPEG audio/video playtime may be slightly inaccurate for video bitrates below 100kbps. Except in extreme low-bitrate situations, error should be less than 1%. Report to info@getid3.org if greater than this.');
|
||||
// }
|
||||
|
@ -503,8 +502,7 @@ echo 'average_File_bitrate = '.number_format(array_sum($vbr_bitrates) / count($v
|
|||
return true;
|
||||
}
|
||||
|
||||
private function readBitsFromStream(&$bitstream, &$bitstreamoffset, $bits_to_read, $return_singlebit_as_boolean = true)
|
||||
{
|
||||
private function readBitsFromStream(&$bitstream, &$bitstreamoffset, $bits_to_read, $return_singlebit_as_boolean=true) {
|
||||
$return = bindec(substr($bitstream, $bitstreamoffset, $bits_to_read));
|
||||
$bitstreamoffset += $bits_to_read;
|
||||
if (($bits_to_read == 1) && $return_singlebit_as_boolean) {
|
||||
|
@ -514,8 +512,7 @@ echo 'average_File_bitrate = '.number_format(array_sum($vbr_bitrates) / count($v
|
|||
}
|
||||
|
||||
|
||||
public static function systemNonOverheadPercentage($VideoBitrate, $AudioBitrate)
|
||||
{
|
||||
public static function systemNonOverheadPercentage($VideoBitrate, $AudioBitrate) {
|
||||
$OverheadPercentage = 0;
|
||||
|
||||
$AudioBitrate = max(min($AudioBitrate / 1000, 384), 32); // limit to range of 32kbps - 384kbps (should be only legal bitrates, but maybe VBR?)
|
||||
|
@ -523,18 +520,18 @@ echo 'average_File_bitrate = '.number_format(array_sum($vbr_bitrates) / count($v
|
|||
|
||||
|
||||
//OMBB[audiobitrate] = array(video-10kbps, video-100kbps, video-1000kbps, video-10000kbps)
|
||||
$OverheadMultiplierByBitrate[32] = [0, 0.9676287944368530, 0.9802276264360310, 0.9844916183244460, 0.9852821845179940];
|
||||
$OverheadMultiplierByBitrate[48] = [0, 0.9779100089209830, 0.9787770035359320, 0.9846738664076130, 0.9852683013799960];
|
||||
$OverheadMultiplierByBitrate[56] = [0, 0.9731249855367600, 0.9776624308938040, 0.9832606361852130, 0.9843922606633340];
|
||||
$OverheadMultiplierByBitrate[64] = [0, 0.9755642683275760, 0.9795256705493390, 0.9836573009193170, 0.9851122539404470];
|
||||
$OverheadMultiplierByBitrate[96] = [0, 0.9788025247497290, 0.9798553314148700, 0.9822956869792560, 0.9834815119124690];
|
||||
$OverheadMultiplierByBitrate[128] = [0, 0.9816940050925480, 0.9821675936072120, 0.9829756927470870, 0.9839763420152050];
|
||||
$OverheadMultiplierByBitrate[160] = [0, 0.9825894094561180, 0.9820913399073960, 0.9823907143253970, 0.9832821783651570];
|
||||
$OverheadMultiplierByBitrate[192] = [0, 0.9832038474336260, 0.9825731694317960, 0.9821028622712400, 0.9828262076447620];
|
||||
$OverheadMultiplierByBitrate[224] = [0, 0.9836516298538770, 0.9824718601823890, 0.9818302180625380, 0.9823735101626480];
|
||||
$OverheadMultiplierByBitrate[256] = [0, 0.9845863022094920, 0.9837229411967540, 0.9824521662210830, 0.9828645172100790];
|
||||
$OverheadMultiplierByBitrate[320] = [0, 0.9849565280263180, 0.9837683142805110, 0.9822885275960400, 0.9824424382727190];
|
||||
$OverheadMultiplierByBitrate[384] = [0, 0.9856094774357600, 0.9844573394432720, 0.9825970399837330, 0.9824673808303890];
|
||||
$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;
|
||||
|
@ -567,49 +564,43 @@ echo 'average_File_bitrate = '.number_format(array_sum($vbr_bitrates) / count($v
|
|||
}
|
||||
|
||||
|
||||
public static function videoFramerateLookup($rawframerate)
|
||||
{
|
||||
$lookup = [0, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60];
|
||||
public static function videoFramerateLookup($rawframerate) {
|
||||
$lookup = array(0, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60);
|
||||
return (isset($lookup[$rawframerate]) ? (float) $lookup[$rawframerate] : (float) 0);
|
||||
}
|
||||
|
||||
public static function videoAspectRatioLookup($rawaspectratio)
|
||||
{
|
||||
$lookup = [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];
|
||||
public static function videoAspectRatioLookup($rawaspectratio) {
|
||||
$lookup = 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($lookup[$rawaspectratio]) ? (float) $lookup[$rawaspectratio] : (float) 0);
|
||||
}
|
||||
|
||||
public static function videoAspectRatioTextLookup($rawaspectratio)
|
||||
{
|
||||
$lookup = ['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'];
|
||||
public static function videoAspectRatioTextLookup($rawaspectratio) {
|
||||
$lookup = 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($lookup[$rawaspectratio]) ? $lookup[$rawaspectratio] : '');
|
||||
}
|
||||
|
||||
public static function videoFormatTextLookup($video_format)
|
||||
{
|
||||
public static function videoFormatTextLookup($video_format) {
|
||||
// ISO/IEC 13818-2, section 6.3.6, Table 6-6. Meaning of video_format
|
||||
$lookup = ['component', 'PAL', 'NTSC', 'SECAM', 'MAC', 'Unspecified video format', 'reserved(6)', 'reserved(7)'];
|
||||
$lookup = array('component', 'PAL', 'NTSC', 'SECAM', 'MAC', 'Unspecified video format', 'reserved(6)', 'reserved(7)');
|
||||
return (isset($lookup[$video_format]) ? $lookup[$video_format] : '');
|
||||
}
|
||||
|
||||
public static function scalableModeTextLookup($scalable_mode)
|
||||
{
|
||||
public static function scalableModeTextLookup($scalable_mode) {
|
||||
// ISO/IEC 13818-2, section 6.3.8, Table 6-10. Definition of scalable_mode
|
||||
$lookup = ['data partitioning', 'spatial scalability', 'SNR scalability', 'temporal scalability'];
|
||||
$lookup = array('data partitioning', 'spatial scalability', 'SNR scalability', 'temporal scalability');
|
||||
return (isset($lookup[$scalable_mode]) ? $lookup[$scalable_mode] : '');
|
||||
}
|
||||
|
||||
public static function pictureStructureTextLookup($picture_structure)
|
||||
{
|
||||
public static function pictureStructureTextLookup($picture_structure) {
|
||||
// ISO/IEC 13818-2, section 6.3.11, Table 6-14 Meaning of picture_structure
|
||||
$lookup = ['reserved', 'Top Field', 'Bottom Field', 'Frame picture'];
|
||||
$lookup = array('reserved', 'Top Field', 'Bottom Field', 'Frame picture');
|
||||
return (isset($lookup[$picture_structure]) ? $lookup[$picture_structure] : '');
|
||||
}
|
||||
|
||||
public static function chromaFormatTextLookup($chroma_format)
|
||||
{
|
||||
public static function chromaFormatTextLookup($chroma_format) {
|
||||
// ISO/IEC 13818-2, section 6.3.11, Table 6-14 Meaning of picture_structure
|
||||
$lookup = ['reserved', '4:2:0', '4:2:2', '4:4:4'];
|
||||
$lookup = array('reserved', '4:2:0', '4:2:2', '4:4:4');
|
||||
return (isset($lookup[$chroma_format]) ? $lookup[$chroma_format] : '');
|
||||
}
|
||||
|
||||
}
|
|
@ -18,8 +18,7 @@
|
|||
class getid3_nsv extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
@ -48,20 +47,19 @@ class getid3_nsv extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Expecting "NSVs" or "NSVf" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($NSVheader).'"';
|
||||
$this->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';
|
||||
$this->warning('NSVf header not present - cannot calculate playtime or bitrate');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getNSVsHeaderFilepointer($fileoffset)
|
||||
{
|
||||
public function getNSVsHeaderFilepointer($fileoffset) {
|
||||
$info = &$this->getid3->info;
|
||||
$this->fseek($fileoffset);
|
||||
$NSVsheader = $this->fread(28);
|
||||
|
@ -71,7 +69,7 @@ class getid3_nsv extends getid3_handler
|
|||
$offset += 4;
|
||||
|
||||
if ($info['nsv']['NSVs']['identifier'] != 'NSVs') {
|
||||
$info['error'][] = 'expected "NSVs" at offset ('.$fileoffset.'), found "'.$info['nsv']['NSVs']['identifier'].'" instead';
|
||||
$this->error('expected "NSVs" at offset ('.$fileoffset.'), found "'.$info['nsv']['NSVs']['identifier'].'" instead');
|
||||
unset($info['nsv']['NSVs']);
|
||||
return false;
|
||||
}
|
||||
|
@ -134,8 +132,7 @@ class getid3_nsv extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function getNSVfHeaderFilepointer($fileoffset, $getTOCoffsets = false)
|
||||
{
|
||||
public function getNSVfHeaderFilepointer($fileoffset, $getTOCoffsets=false) {
|
||||
$info = &$this->getid3->info;
|
||||
$this->fseek($fileoffset);
|
||||
$NSVfheader = $this->fread(28);
|
||||
|
@ -145,7 +142,7 @@ class getid3_nsv extends getid3_handler
|
|||
$offset += 4;
|
||||
|
||||
if ($info['nsv']['NSVf']['identifier'] != 'NSVf') {
|
||||
$info['error'][] = 'expected "NSVf" at offset ('.$fileoffset.'), found "'.$info['nsv']['NSVf']['identifier'].'" instead';
|
||||
$this->error('expected "NSVf" at offset ('.$fileoffset.'), found "'.$info['nsv']['NSVf']['identifier'].'" instead');
|
||||
unset($info['nsv']['NSVf']);
|
||||
return false;
|
||||
}
|
||||
|
@ -158,7 +155,7 @@ class getid3_nsv extends getid3_handler
|
|||
$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';
|
||||
$this->warning('truncated file - NSVf header indicates '.$info['nsv']['NSVf']['file_size'].' bytes, file actually '.$info['avdataend'].' bytes');
|
||||
}
|
||||
|
||||
$info['nsv']['NSVf']['playtime_ms'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
|
||||
|
@ -171,7 +168,7 @@ class getid3_nsv extends getid3_handler
|
|||
$offset += 4;
|
||||
|
||||
if ($info['nsv']['NSVf']['playtime_ms'] == 0) {
|
||||
$info['error'][] = 'Corrupt NSV file: NSVf.playtime_ms == zero';
|
||||
$this->error('Corrupt NSV file: NSVf.playtime_ms == zero');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -209,12 +206,11 @@ class getid3_nsv extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public static function NSVframerateLookup($framerateindex)
|
||||
{
|
||||
public static function NSVframerateLookup($framerateindex) {
|
||||
if ($framerateindex <= 127) {
|
||||
return (float) $framerateindex;
|
||||
}
|
||||
static $NSVframerateLookup = [];
|
||||
static $NSVframerateLookup = array();
|
||||
if (empty($NSVframerateLookup)) {
|
||||
$NSVframerateLookup[129] = (float) 29.970;
|
||||
$NSVframerateLookup[131] = (float) 23.976;
|
||||
|
@ -224,4 +220,5 @@ class getid3_nsv extends getid3_handler
|
|||
}
|
||||
return (isset($NSVframerateLookup[$framerateindex]) ? $NSVframerateLookup[$framerateindex] : false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,8 +24,7 @@ class getid3_quicktime extends getid3_handler
|
|||
public $ReturnAtomData = true;
|
||||
public $ParseAllPossibleAtoms = false;
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'quicktime';
|
||||
|
@ -36,10 +35,10 @@ class getid3_quicktime extends getid3_handler
|
|||
|
||||
$offset = 0;
|
||||
$atomcounter = 0;
|
||||
$atom_data_read_buffer_size = ($info['php_memory_limit'] ? round($info['php_memory_limit'] / 2) : $this->getid3->option_fread_buffer_size * 1024); // allow [default: 32MB] if PHP configured with no memory_limit
|
||||
$atom_data_read_buffer_size = max($this->getid3->option_fread_buffer_size * 1024, ($info['php_memory_limit'] ? round($info['php_memory_limit'] / 4) : 1024)); // set read buffer to 25% of PHP memory limit (if one is specified), otherwise use option_fread_buffer_size [default: 32MB]
|
||||
while ($offset < $info['avdataend']) {
|
||||
if (!getid3_lib::intValueSupported($offset)) {
|
||||
$info['error'][] = 'Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions';
|
||||
$this->error('Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions');
|
||||
break;
|
||||
}
|
||||
$this->fseek($offset);
|
||||
|
@ -58,7 +57,7 @@ class getid3_quicktime extends getid3_handler
|
|||
$info['quicktime'][$atomname]['offset'] = $offset;
|
||||
|
||||
if (($offset + $atomsize) > $info['avdataend']) {
|
||||
$info['error'][] = 'Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)';
|
||||
$this->error('Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -68,7 +67,7 @@ class getid3_quicktime extends getid3_handler
|
|||
// to read user data atoms, you should allow for the terminating 0.
|
||||
break;
|
||||
}
|
||||
$atomHierarchy = [];
|
||||
$atomHierarchy = array();
|
||||
$info['quicktime'][$atomname] = $this->QuicktimeParseAtom($atomname, $atomsize, $this->fread(min($atomsize, $atom_data_read_buffer_size)), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms);
|
||||
|
||||
$offset += $atomsize;
|
||||
|
@ -85,7 +84,7 @@ class getid3_quicktime extends getid3_handler
|
|||
if (!empty($info['quicktime']['comments']['chapters']) && is_array($info['quicktime']['comments']['chapters']) && (count($info['quicktime']['comments']['chapters']) > 0)) {
|
||||
$durations = $this->quicktime_time_to_sample_table($info);
|
||||
for ($i = 0; $i < count($info['quicktime']['comments']['chapters']); $i++) {
|
||||
$bookmark = [];
|
||||
$bookmark = array();
|
||||
$bookmark['title'] = $info['quicktime']['comments']['chapters'][$i];
|
||||
if (isset($durations[$i])) {
|
||||
$bookmark['duration_sample'] = $durations[$i]['sample_duration'];
|
||||
|
@ -151,7 +150,7 @@ class getid3_quicktime extends getid3_handler
|
|||
}
|
||||
}
|
||||
if ($latitude === false) {
|
||||
$info['warning'][] = 'location.ISO6709 string not parsed correctly: "'.$ISO6709string.'", please submit as a bug';
|
||||
$this->warning('location.ISO6709 string not parsed correctly: "'.$ISO6709string.'", please submit as a bug');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -174,10 +173,14 @@ class getid3_quicktime extends getid3_handler
|
|||
}
|
||||
}
|
||||
}
|
||||
if (($info['audio']['dataformat'] == 'mp4') && empty($info['video']['resolution_x'])) {
|
||||
if ($info['audio']['dataformat'] == 'mp4') {
|
||||
$info['fileformat'] = 'mp4';
|
||||
if (empty($info['video']['resolution_x'])) {
|
||||
$info['mime_type'] = 'audio/mp4';
|
||||
unset($info['video']['dataformat']);
|
||||
} else {
|
||||
$info['mime_type'] = 'video/mp4';
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->ReturnAtomData) {
|
||||
|
@ -194,8 +197,7 @@ class getid3_quicktime extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms)
|
||||
{
|
||||
public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
|
||||
// http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
|
||||
// https://code.google.com/p/mp4v2/wiki/iTunesMetadata
|
||||
|
||||
|
@ -236,7 +238,7 @@ class getid3_quicktime extends getid3_handler
|
|||
}
|
||||
}
|
||||
if ($allnumericnames) {
|
||||
$newData = [];
|
||||
$newData = array();
|
||||
foreach ($atom_structure['subatoms'] as $subatomarray) {
|
||||
foreach ($subatomarray['subatoms'] as $newData_subatomarray) {
|
||||
unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']);
|
||||
|
@ -403,7 +405,7 @@ class getid3_quicktime extends getid3_handler
|
|||
$boxsmalltype = substr($atom_data, $atomoffset + 2, 2);
|
||||
$boxsmalldata = substr($atom_data, $atomoffset + 4, $boxsmallsize);
|
||||
if ($boxsmallsize <= 1) {
|
||||
$info['warning'][] = 'Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset);
|
||||
$this->warning('Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset));
|
||||
$atom_structure['data'] = null;
|
||||
$atomoffset = strlen($atom_data);
|
||||
break;
|
||||
|
@ -413,7 +415,7 @@ class getid3_quicktime extends getid3_handler
|
|||
$atom_structure['data'] = $boxsmalldata;
|
||||
break;
|
||||
default:
|
||||
$info['warning'][] = 'Unknown QuickTime smallbox type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxsmalltype).'" ('.trim(getid3_lib::PrintHexBytes($boxsmalltype)).') at offset '.$baseoffset;
|
||||
$this->warning('Unknown QuickTime smallbox type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxsmalltype).'" ('.trim(getid3_lib::PrintHexBytes($boxsmalltype)).') at offset '.$baseoffset);
|
||||
$atom_structure['data'] = $atom_data;
|
||||
break;
|
||||
}
|
||||
|
@ -425,7 +427,7 @@ class getid3_quicktime extends getid3_handler
|
|||
$boxtype = substr($atom_data, $atomoffset + 4, 4);
|
||||
$boxdata = substr($atom_data, $atomoffset + 8, $boxsize - 8);
|
||||
if ($boxsize <= 1) {
|
||||
$info['warning'][] = 'Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset);
|
||||
$this->warning('Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset));
|
||||
$atom_structure['data'] = null;
|
||||
$atomoffset = strlen($atom_data);
|
||||
break;
|
||||
|
@ -539,12 +541,14 @@ class getid3_quicktime extends getid3_handler
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unknown QuickTime box type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxtype).'" ('.trim(getid3_lib::PrintHexBytes($boxtype)).') at offset '.$baseoffset;
|
||||
$this->warning('Unknown QuickTime box type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxtype).'" ('.trim(getid3_lib::PrintHexBytes($boxtype)).') at offset '.$baseoffset);
|
||||
$atom_structure['data'] = $atom_data;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -590,7 +594,7 @@ class getid3_quicktime extends getid3_handler
|
|||
if ($UncompressedHeader = @gzuncompress($CompressedFileData)) {
|
||||
$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms);
|
||||
} else {
|
||||
$info['warning'][] = 'Error decompressing compressed MOV atom at offset '.$atom_structure['offset'];
|
||||
$this->warning('Error decompressing compressed MOV atom at offset '.$atom_structure['offset']);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -709,7 +713,7 @@ class getid3_quicktime extends getid3_handler
|
|||
if (isset($ptv_lookup[$atom_structure['display_size_raw']])) {
|
||||
$atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']];
|
||||
} else {
|
||||
$info['warning'][] = 'unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')';
|
||||
$this->warning('unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')');
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -736,6 +740,7 @@ class getid3_quicktime extends getid3_handler
|
|||
$atom_structure['sample_description_table'][$i]['encoder_vendor'] = substr($atom_structure['sample_description_table'][$i]['data'], 4, 4);
|
||||
|
||||
switch ($atom_structure['sample_description_table'][$i]['encoder_vendor']) {
|
||||
|
||||
case "\x00\x00\x00\x00":
|
||||
// audio tracks
|
||||
$atom_structure['sample_description_table'][$i]['audio_channels'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 2));
|
||||
|
@ -914,7 +919,7 @@ class getid3_quicktime extends getid3_handler
|
|||
|
||||
$max_stts_entries_to_scan = ($info['php_memory_limit'] ? min(floor($this->getid3->memory_limit / 10000), $atom_structure['number_entries']) : $atom_structure['number_entries']);
|
||||
if ($max_stts_entries_to_scan < $atom_structure['number_entries']) {
|
||||
$info['warning'][] = 'QuickTime atom "stts" has '.$atom_structure['number_entries'].' but only scanning the first '.$max_stts_entries_to_scan.' entries due to limited PHP memory available ('.floor($atom_structure['number_entries'] / 1048576).'MB).';
|
||||
$this->warning('QuickTime atom "stts" has '.$atom_structure['number_entries'].' but only scanning the first '.$max_stts_entries_to_scan.' entries due to limited PHP memory available ('.floor($atom_structure['number_entries'] / 1048576).'MB).');
|
||||
}
|
||||
for ($i = 0; $i < $max_stts_entries_to_scan; $i++) {
|
||||
$atom_structure['time_to_sample_table'][$i]['sample_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
|
||||
|
@ -1114,7 +1119,7 @@ class getid3_quicktime extends getid3_handler
|
|||
$atom_structure['quality'] = getid3_lib::BigEndian2Int(substr($atom_data, 22, 2));
|
||||
|
||||
if ($atom_structure['time_scale'] == 0) {
|
||||
$info['error'][] = 'Corrupt Quicktime file: mdhd.time_scale == zero';
|
||||
$this->error('Corrupt Quicktime file: mdhd.time_scale == zero');
|
||||
return false;
|
||||
}
|
||||
$info['quicktime']['time_scale'] = ((isset($info['quicktime']['time_scale']) && ($info['quicktime']['time_scale'] < 1000)) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
|
||||
|
@ -1228,7 +1233,7 @@ class getid3_quicktime extends getid3_handler
|
|||
$atom_structure['next_track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 96, 4));
|
||||
|
||||
if ($atom_structure['time_scale'] == 0) {
|
||||
$info['error'][] = 'Corrupt Quicktime file: mvhd.time_scale == zero';
|
||||
$this->error('Corrupt Quicktime file: mvhd.time_scale == zero');
|
||||
return false;
|
||||
}
|
||||
$atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
|
||||
|
@ -1370,6 +1375,7 @@ class getid3_quicktime extends getid3_handler
|
|||
|
||||
|
||||
if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) {
|
||||
|
||||
$info['avdataoffset'] = $atom_structure['offset'] + 8; // $info['quicktime'][$atomname]['offset'] + 8;
|
||||
$OldAVDataEnd = $info['avdataend'];
|
||||
$info['avdataend'] = $atom_structure['offset'] + $atom_structure['size']; // $info['quicktime'][$atomname]['offset'] + $info['quicktime'][$atomname]['size'];
|
||||
|
@ -1383,7 +1389,7 @@ class getid3_quicktime extends getid3_handler
|
|||
$getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
|
||||
if (!empty($getid3_temp->info['warning'])) {
|
||||
foreach ($getid3_temp->info['warning'] as $value) {
|
||||
$info['warning'][] = $value;
|
||||
$this->warning($value);
|
||||
}
|
||||
}
|
||||
if (!empty($getid3_temp->info['mpeg'])) {
|
||||
|
@ -1402,6 +1408,7 @@ class getid3_quicktime extends getid3_handler
|
|||
unset($getid3_mp3, $getid3_temp);
|
||||
$info['avdataend'] = $OldAVDataEnd;
|
||||
unset($OldAVDataEnd);
|
||||
|
||||
}
|
||||
|
||||
unset($mdat_offset, $chapter_string_length, $chapter_matches);
|
||||
|
@ -1485,7 +1492,7 @@ class getid3_quicktime extends getid3_handler
|
|||
$info['quicktime']['comments']['gps_altitude'][] = floatval($altitude);
|
||||
}
|
||||
} else {
|
||||
$info['warning'][] = 'QuickTime atom "©xyz" data does not match expected data pattern at offset '.$baseoffset.'. Please report as getID3() bug.';
|
||||
$this->warning('QuickTime atom "©xyz" data does not match expected data pattern at offset '.$baseoffset.'. Please report as getID3() bug.');
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1501,7 +1508,7 @@ class getid3_quicktime extends getid3_handler
|
|||
$atom_structure['data'] = $atom_data;
|
||||
$atom_structure['image_mime'] = 'image/jpeg';
|
||||
$atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image'));
|
||||
$info['quicktime']['comments']['picture'][] = ['image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']];
|
||||
$info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']);
|
||||
}
|
||||
break;
|
||||
case 'NCTG': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
|
||||
|
@ -1564,7 +1571,7 @@ class getid3_quicktime extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unknown QuickTime atom type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" ('.trim(getid3_lib::PrintHexBytes($atomname)).') at offset '.$baseoffset;
|
||||
$this->warning('Unknown QuickTime atom type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" ('.trim(getid3_lib::PrintHexBytes($atomname)).') at offset '.$baseoffset);
|
||||
$atom_structure['data'] = $atom_data;
|
||||
break;
|
||||
}
|
||||
|
@ -1572,8 +1579,7 @@ class getid3_quicktime extends getid3_handler
|
|||
return $atom_structure;
|
||||
}
|
||||
|
||||
public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms)
|
||||
{
|
||||
public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
|
||||
//echo 'QuicktimeParseContainerAtom('.substr($atom_data, 4, 4).') @ '.$baseoffset.'<br><br>';
|
||||
$atom_structure = false;
|
||||
$subatomoffset = 0;
|
||||
|
@ -1605,8 +1611,7 @@ class getid3_quicktime extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function quicktime_read_mp4_descr_length($data, &$offset)
|
||||
{
|
||||
public function quicktime_read_mp4_descr_length($data, &$offset) {
|
||||
// http://libquicktime.sourcearchive.com/documentation/2:1.0.2plus-pdebian-2build1/esds_8c-source.html
|
||||
$num_bytes = 0;
|
||||
$length = 0;
|
||||
|
@ -1618,10 +1623,9 @@ class getid3_quicktime extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function QuicktimeLanguageLookup($languageid)
|
||||
{
|
||||
public function QuicktimeLanguageLookup($languageid) {
|
||||
// http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-34353
|
||||
static $QuicktimeLanguageLookup = [];
|
||||
static $QuicktimeLanguageLookup = array();
|
||||
if (empty($QuicktimeLanguageLookup)) {
|
||||
$QuicktimeLanguageLookup[0] = 'English';
|
||||
$QuicktimeLanguageLookup[1] = 'French';
|
||||
|
@ -1756,9 +1760,8 @@ class getid3_quicktime extends getid3_handler
|
|||
return (isset($QuicktimeLanguageLookup[$languageid]) ? $QuicktimeLanguageLookup[$languageid] : 'invalid');
|
||||
}
|
||||
|
||||
public function QuicktimeVideoCodecLookup($codecid)
|
||||
{
|
||||
static $QuicktimeVideoCodecLookup = [];
|
||||
public function QuicktimeVideoCodecLookup($codecid) {
|
||||
static $QuicktimeVideoCodecLookup = array();
|
||||
if (empty($QuicktimeVideoCodecLookup)) {
|
||||
$QuicktimeVideoCodecLookup['.SGI'] = 'SGI';
|
||||
$QuicktimeVideoCodecLookup['3IV1'] = '3ivx MPEG-4 v1';
|
||||
|
@ -1816,9 +1819,8 @@ class getid3_quicktime extends getid3_handler
|
|||
return (isset($QuicktimeVideoCodecLookup[$codecid]) ? $QuicktimeVideoCodecLookup[$codecid] : '');
|
||||
}
|
||||
|
||||
public function QuicktimeAudioCodecLookup($codecid)
|
||||
{
|
||||
static $QuicktimeAudioCodecLookup = [];
|
||||
public function QuicktimeAudioCodecLookup($codecid) {
|
||||
static $QuicktimeAudioCodecLookup = array();
|
||||
if (empty($QuicktimeAudioCodecLookup)) {
|
||||
$QuicktimeAudioCodecLookup['.mp3'] = 'Fraunhofer MPEG Layer-III alias';
|
||||
$QuicktimeAudioCodecLookup['aac '] = 'ISO/IEC 14496-3 AAC';
|
||||
|
@ -1862,9 +1864,8 @@ class getid3_quicktime extends getid3_handler
|
|||
return (isset($QuicktimeAudioCodecLookup[$codecid]) ? $QuicktimeAudioCodecLookup[$codecid] : '');
|
||||
}
|
||||
|
||||
public function QuicktimeDCOMLookup($compressionid)
|
||||
{
|
||||
static $QuicktimeDCOMLookup = [];
|
||||
public function QuicktimeDCOMLookup($compressionid) {
|
||||
static $QuicktimeDCOMLookup = array();
|
||||
if (empty($QuicktimeDCOMLookup)) {
|
||||
$QuicktimeDCOMLookup['zlib'] = 'ZLib Deflate';
|
||||
$QuicktimeDCOMLookup['adec'] = 'Apple Compression';
|
||||
|
@ -1872,9 +1873,8 @@ class getid3_quicktime extends getid3_handler
|
|||
return (isset($QuicktimeDCOMLookup[$compressionid]) ? $QuicktimeDCOMLookup[$compressionid] : '');
|
||||
}
|
||||
|
||||
public function QuicktimeColorNameLookup($colordepthid)
|
||||
{
|
||||
static $QuicktimeColorNameLookup = [];
|
||||
public function QuicktimeColorNameLookup($colordepthid) {
|
||||
static $QuicktimeColorNameLookup = array();
|
||||
if (empty($QuicktimeColorNameLookup)) {
|
||||
$QuicktimeColorNameLookup[1] = '2-color (monochrome)';
|
||||
$QuicktimeColorNameLookup[2] = '4-color';
|
||||
|
@ -1891,9 +1891,8 @@ class getid3_quicktime extends getid3_handler
|
|||
return (isset($QuicktimeColorNameLookup[$colordepthid]) ? $QuicktimeColorNameLookup[$colordepthid] : 'invalid');
|
||||
}
|
||||
|
||||
public function QuicktimeSTIKLookup($stik)
|
||||
{
|
||||
static $QuicktimeSTIKLookup = [];
|
||||
public function QuicktimeSTIKLookup($stik) {
|
||||
static $QuicktimeSTIKLookup = array();
|
||||
if (empty($QuicktimeSTIKLookup)) {
|
||||
$QuicktimeSTIKLookup[0] = 'Movie';
|
||||
$QuicktimeSTIKLookup[1] = 'Normal';
|
||||
|
@ -1909,11 +1908,10 @@ class getid3_quicktime extends getid3_handler
|
|||
return (isset($QuicktimeSTIKLookup[$stik]) ? $QuicktimeSTIKLookup[$stik] : 'invalid');
|
||||
}
|
||||
|
||||
public function QuicktimeIODSaudioProfileName($audio_profile_id)
|
||||
{
|
||||
static $QuicktimeIODSaudioProfileNameLookup = [];
|
||||
public function QuicktimeIODSaudioProfileName($audio_profile_id) {
|
||||
static $QuicktimeIODSaudioProfileNameLookup = array();
|
||||
if (empty($QuicktimeIODSaudioProfileNameLookup)) {
|
||||
$QuicktimeIODSaudioProfileNameLookup = [
|
||||
$QuicktimeIODSaudioProfileNameLookup = array(
|
||||
0x00 => 'ISO Reserved (0x00)',
|
||||
0x01 => 'Main Audio Profile @ Level 1',
|
||||
0x02 => 'Main Audio Profile @ Level 2',
|
||||
|
@ -1964,17 +1962,16 @@ class getid3_quicktime extends getid3_handler
|
|||
0x2F => 'High Efficiency AAC Profile @ Level 5',
|
||||
0xFE => 'Not part of MPEG-4 audio profiles',
|
||||
0xFF => 'No audio capability required',
|
||||
];
|
||||
);
|
||||
}
|
||||
return (isset($QuicktimeIODSaudioProfileNameLookup[$audio_profile_id]) ? $QuicktimeIODSaudioProfileNameLookup[$audio_profile_id] : 'ISO Reserved / User Private');
|
||||
}
|
||||
|
||||
|
||||
public function QuicktimeIODSvideoProfileName($video_profile_id)
|
||||
{
|
||||
static $QuicktimeIODSvideoProfileNameLookup = [];
|
||||
public function QuicktimeIODSvideoProfileName($video_profile_id) {
|
||||
static $QuicktimeIODSvideoProfileNameLookup = array();
|
||||
if (empty($QuicktimeIODSvideoProfileNameLookup)) {
|
||||
$QuicktimeIODSvideoProfileNameLookup = [
|
||||
$QuicktimeIODSvideoProfileNameLookup = array(
|
||||
0x00 => 'Reserved (0x00) Profile',
|
||||
0x01 => 'Simple Profile @ Level 1',
|
||||
0x02 => 'Simple Profile @ Level 2',
|
||||
|
@ -2037,15 +2034,14 @@ class getid3_quicktime extends getid3_handler
|
|||
0xFD => 'Fine Granularity Scalable Profile @ Level 5',
|
||||
0xFE => 'Not part of MPEG-4 Visual profiles',
|
||||
0xFF => 'No visual capability required',
|
||||
];
|
||||
);
|
||||
}
|
||||
return (isset($QuicktimeIODSvideoProfileNameLookup[$video_profile_id]) ? $QuicktimeIODSvideoProfileNameLookup[$video_profile_id] : 'ISO Reserved Profile');
|
||||
}
|
||||
|
||||
|
||||
public function QuicktimeContentRatingLookup($rtng)
|
||||
{
|
||||
static $QuicktimeContentRatingLookup = [];
|
||||
public function QuicktimeContentRatingLookup($rtng) {
|
||||
static $QuicktimeContentRatingLookup = array();
|
||||
if (empty($QuicktimeContentRatingLookup)) {
|
||||
$QuicktimeContentRatingLookup[0] = 'None';
|
||||
$QuicktimeContentRatingLookup[2] = 'Clean';
|
||||
|
@ -2054,9 +2050,8 @@ class getid3_quicktime extends getid3_handler
|
|||
return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid');
|
||||
}
|
||||
|
||||
public function QuicktimeStoreAccountTypeLookup($akid)
|
||||
{
|
||||
static $QuicktimeStoreAccountTypeLookup = [];
|
||||
public function QuicktimeStoreAccountTypeLookup($akid) {
|
||||
static $QuicktimeStoreAccountTypeLookup = array();
|
||||
if (empty($QuicktimeStoreAccountTypeLookup)) {
|
||||
$QuicktimeStoreAccountTypeLookup[0] = 'iTunes';
|
||||
$QuicktimeStoreAccountTypeLookup[1] = 'AOL';
|
||||
|
@ -2064,9 +2059,8 @@ class getid3_quicktime extends getid3_handler
|
|||
return (isset($QuicktimeStoreAccountTypeLookup[$akid]) ? $QuicktimeStoreAccountTypeLookup[$akid] : 'invalid');
|
||||
}
|
||||
|
||||
public function QuicktimeStoreFrontCodeLookup($sfid)
|
||||
{
|
||||
static $QuicktimeStoreFrontCodeLookup = [];
|
||||
public function QuicktimeStoreFrontCodeLookup($sfid) {
|
||||
static $QuicktimeStoreFrontCodeLookup = array();
|
||||
if (empty($QuicktimeStoreFrontCodeLookup)) {
|
||||
$QuicktimeStoreFrontCodeLookup[143460] = 'Australia';
|
||||
$QuicktimeStoreFrontCodeLookup[143445] = 'Austria';
|
||||
|
@ -2094,8 +2088,7 @@ class getid3_quicktime extends getid3_handler
|
|||
return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid');
|
||||
}
|
||||
|
||||
public function QuicktimeParseNikonNCTG($atom_data)
|
||||
{
|
||||
public function QuicktimeParseNikonNCTG($atom_data) {
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
|
||||
// Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
|
||||
// Data is stored as records of:
|
||||
|
@ -2112,7 +2105,7 @@ class getid3_quicktime extends getid3_handler
|
|||
// * ? bytes data (string data may be null-padded; datestamp fields are in the format "2011:05:25 20:24:15")
|
||||
// all integers are stored BigEndian
|
||||
|
||||
$NCTGtagName = [
|
||||
$NCTGtagName = array(
|
||||
0x00000001 => 'Make',
|
||||
0x00000002 => 'Model',
|
||||
0x00000003 => 'Software',
|
||||
|
@ -2134,19 +2127,16 @@ class getid3_quicktime extends getid3_handler
|
|||
0x02000032 => 'UnknownInfo',
|
||||
0x02000083 => 'LensType',
|
||||
0x02000084 => 'Lens',
|
||||
];
|
||||
);
|
||||
|
||||
$offset = 0;
|
||||
$datalength = strlen($atom_data);
|
||||
$parsed = [];
|
||||
$parsed = array();
|
||||
while ($offset < $datalength) {
|
||||
//echo getid3_lib::PrintHexBytes(substr($atom_data, $offset, 4)).'<br>';
|
||||
$record_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4));
|
||||
$offset += 4;
|
||||
$data_size_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));
|
||||
$offset += 2;
|
||||
$data_size = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));
|
||||
$offset += 2;
|
||||
$record_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4)); $offset += 4;
|
||||
$data_size_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2;
|
||||
$data_size = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2;
|
||||
switch ($data_size_type) {
|
||||
case 0x0001: // 0x0001 = flag (size field *= 1-byte)
|
||||
$data = getid3_lib::BigEndian2Int(substr($atom_data, $offset, $data_size * 1));
|
||||
|
@ -2174,7 +2164,7 @@ class getid3_quicktime extends getid3_handler
|
|||
$offset += ($data_size * 4);
|
||||
break;
|
||||
case 0x0005: // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
|
||||
$data = [];
|
||||
$data = array();
|
||||
for ($i = 0; $i < $data_size; $i++) {
|
||||
$numerator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 0, 4));
|
||||
$denomninator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 4, 4));
|
||||
|
@ -2218,10 +2208,10 @@ class getid3_quicktime extends getid3_handler
|
|||
}
|
||||
break;
|
||||
case 0x02000023: // PictureControlData
|
||||
$PictureControlAdjust = [0=>'default', 1=>'quick', 2=>'full'];
|
||||
$FilterEffect = [0x80=>'off', 0x81=>'yellow', 0x82=>'orange', 0x83=>'red', 0x84=>'green', 0xff=>'n/a'];
|
||||
$ToningEffect = [0x80=>'b&w', 0x81=>'sepia', 0x82=>'cyanotype', 0x83=>'red', 0x84=>'yellow', 0x85=>'green', 0x86=>'blue-green', 0x87=>'blue', 0x88=>'purple-blue', 0x89=>'red-purple', 0xff=>'n/a'];
|
||||
$data = [
|
||||
$PictureControlAdjust = array(0=>'default', 1=>'quick', 2=>'full');
|
||||
$FilterEffect = array(0x80=>'off', 0x81=>'yellow', 0x82=>'orange', 0x83=>'red', 0x84=>'green', 0xff=>'n/a');
|
||||
$ToningEffect = array(0x80=>'b&w', 0x81=>'sepia', 0x82=>'cyanotype', 0x83=>'red', 0x84=>'yellow', 0x85=>'green', 0x86=>'blue-green', 0x87=>'blue', 0x88=>'purple-blue', 0x89=>'red-purple', 0xff=>'n/a');
|
||||
$data = array(
|
||||
'PictureControlVersion' => substr($data, 0, 4),
|
||||
'PictureControlName' => rtrim(substr($data, 4, 20), "\x00"),
|
||||
'PictureControlBase' => rtrim(substr($data, 24, 20), "\x00"),
|
||||
|
@ -2236,7 +2226,7 @@ class getid3_quicktime extends getid3_handler
|
|||
'FilterEffect' => $FilterEffect[ord(substr($data, 55, 1))],
|
||||
'ToningEffect' => $ToningEffect[ord(substr($data, 56, 1))],
|
||||
'ToningSaturation' => ord(substr($data, 57, 1)),
|
||||
];
|
||||
);
|
||||
break;
|
||||
case 0x02000024: // WorldTime
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime
|
||||
|
@ -2250,27 +2240,24 @@ class getid3_quicktime extends getid3_handler
|
|||
$dst = (bool) getid3_lib::BigEndian2Int(substr($data, 2, 1));
|
||||
switch (getid3_lib::BigEndian2Int(substr($data, 3, 1))) {
|
||||
case 2:
|
||||
$datedisplayformat = 'D/M/Y';
|
||||
break;
|
||||
$datedisplayformat = 'D/M/Y'; break;
|
||||
case 1:
|
||||
$datedisplayformat = 'M/D/Y';
|
||||
break;
|
||||
$datedisplayformat = 'M/D/Y'; break;
|
||||
case 0:
|
||||
default:
|
||||
$datedisplayformat = 'Y/M/D';
|
||||
break;
|
||||
$datedisplayformat = 'Y/M/D'; break;
|
||||
}
|
||||
|
||||
$data = ['timezone'=>floatval($timezone), 'dst'=>$dst, 'display'=>$datedisplayformat];
|
||||
$data = array('timezone'=>floatval($timezone), 'dst'=>$dst, 'display'=>$datedisplayformat);
|
||||
break;
|
||||
case 0x02000083: // LensType
|
||||
$data = [
|
||||
$data = array(
|
||||
//'_' => $data,
|
||||
'mf' => (bool) ($data & 0x01),
|
||||
'd' => (bool) ($data & 0x02),
|
||||
'g' => (bool) ($data & 0x04),
|
||||
'vr' => (bool) ($data & 0x08),
|
||||
];
|
||||
);
|
||||
break;
|
||||
}
|
||||
$tag_name = (isset($NCTGtagName[$record_type]) ? $NCTGtagName[$record_type] : '0x'.str_pad(dechex($record_type), 8, '0', STR_PAD_LEFT));
|
||||
|
@ -2280,9 +2267,8 @@ class getid3_quicktime extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function CopyToAppropriateCommentsSection($keyname, $data, $boxname = '')
|
||||
{
|
||||
static $handyatomtranslatorarray = [];
|
||||
public function CopyToAppropriateCommentsSection($keyname, $data, $boxname='') {
|
||||
static $handyatomtranslatorarray = array();
|
||||
if (empty($handyatomtranslatorarray)) {
|
||||
// http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
|
||||
// http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt
|
||||
|
@ -2401,10 +2387,10 @@ class getid3_quicktime extends getid3_handler
|
|||
} elseif (preg_match('#^BM#', $data)) {
|
||||
$image_mime = 'image/bmp';
|
||||
}
|
||||
$data = ['data'=>$data, 'image_mime'=>$image_mime];
|
||||
$data = array('data'=>$data, 'image_mime'=>$image_mime);
|
||||
}
|
||||
}
|
||||
$gooddata = [$data];
|
||||
$gooddata = array($data);
|
||||
if ($comment_key == 'genre') {
|
||||
// some other taggers separate multiple genres with semicolon, e.g. "Heavy Metal;Thrash Metal;Metal"
|
||||
$gooddata = explode(';', $data);
|
||||
|
@ -2416,8 +2402,7 @@ class getid3_quicktime extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function NoNullString($nullterminatedstring)
|
||||
{
|
||||
public function NoNullString($nullterminatedstring) {
|
||||
// remove the single null terminator on null terminated strings
|
||||
if (substr($nullterminatedstring, strlen($nullterminatedstring) - 1, 1) === "\x00") {
|
||||
return substr($nullterminatedstring, 0, strlen($nullterminatedstring) - 1);
|
||||
|
@ -2425,8 +2410,7 @@ class getid3_quicktime extends getid3_handler
|
|||
return $nullterminatedstring;
|
||||
}
|
||||
|
||||
public function Pascal2String($pascalstring)
|
||||
{
|
||||
public function Pascal2String($pascalstring) {
|
||||
// Pascal strings have 1 unsigned byte at the beginning saying how many chars (1-255) are in the string
|
||||
return substr($pascalstring, 1);
|
||||
}
|
||||
|
@ -2436,12 +2420,11 @@ class getid3_quicktime extends getid3_handler
|
|||
// helper functions for m4b audiobook chapters
|
||||
// code by Steffen Hartmann 2015-Nov-08
|
||||
*/
|
||||
public function search_tag_by_key($info, $tag, $history, &$result)
|
||||
{
|
||||
public function search_tag_by_key($info, $tag, $history, &$result) {
|
||||
foreach ($info as $key => $value) {
|
||||
$key_history = $history.'/'.$key;
|
||||
if ($key === $tag) {
|
||||
$result[] = [$key_history, $info];
|
||||
$result[] = array($key_history, $info);
|
||||
} else {
|
||||
if (is_array($value)) {
|
||||
$this->search_tag_by_key($value, $tag, $key_history, $result);
|
||||
|
@ -2450,12 +2433,11 @@ class getid3_quicktime extends getid3_handler
|
|||
}
|
||||
}
|
||||
|
||||
public function search_tag_by_pair($info, $k, $v, $history, &$result)
|
||||
{
|
||||
public function search_tag_by_pair($info, $k, $v, $history, &$result) {
|
||||
foreach ($info as $key => $value) {
|
||||
$key_history = $history.'/'.$key;
|
||||
if (($key === $k) && ($value === $v)) {
|
||||
$result[] = [$key_history, $info];
|
||||
$result[] = array($key_history, $info);
|
||||
} else {
|
||||
if (is_array($value)) {
|
||||
$this->search_tag_by_pair($value, $k, $v, $key_history, $result);
|
||||
|
@ -2464,35 +2446,33 @@ class getid3_quicktime extends getid3_handler
|
|||
}
|
||||
}
|
||||
|
||||
public function quicktime_time_to_sample_table($info)
|
||||
{
|
||||
$res = [];
|
||||
public function quicktime_time_to_sample_table($info) {
|
||||
$res = array();
|
||||
$this->search_tag_by_pair($info['quicktime']['moov'], 'name', 'stbl', 'quicktime/moov', $res);
|
||||
foreach ($res as $value) {
|
||||
$stbl_res = [];
|
||||
$stbl_res = array();
|
||||
$this->search_tag_by_pair($value[1], 'data_format', 'text', $value[0], $stbl_res);
|
||||
if (count($stbl_res) > 0) {
|
||||
$stts_res = [];
|
||||
$stts_res = array();
|
||||
$this->search_tag_by_key($value[1], 'time_to_sample_table', $value[0], $stts_res);
|
||||
if (count($stts_res) > 0) {
|
||||
return $stts_res[0][1]['time_to_sample_table'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return [];
|
||||
return array();
|
||||
}
|
||||
|
||||
function quicktime_bookmark_time_scale($info)
|
||||
{
|
||||
function quicktime_bookmark_time_scale($info) {
|
||||
$time_scale = '';
|
||||
$ts_prefix_len = 0;
|
||||
$res = [];
|
||||
$res = array();
|
||||
$this->search_tag_by_pair($info['quicktime']['moov'], 'name', 'stbl', 'quicktime/moov', $res);
|
||||
foreach ($res as $value) {
|
||||
$stbl_res = [];
|
||||
$stbl_res = array();
|
||||
$this->search_tag_by_pair($value[1], 'data_format', 'text', $value[0], $stbl_res);
|
||||
if (count($stbl_res) > 0) {
|
||||
$ts_res = [];
|
||||
$ts_res = array();
|
||||
$this->search_tag_by_key($info['quicktime']['moov'], 'time_scale', 'quicktime/moov', $ts_res);
|
||||
foreach ($ts_res as $value) {
|
||||
$prefix = substr($value[0], 0, -12);
|
||||
|
@ -2508,4 +2488,6 @@ class getid3_quicktime extends getid3_handler
|
|||
/*
|
||||
// END helper functions for m4b audiobook chapters
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -19,8 +19,7 @@ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php',
|
|||
class getid3_real extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'real';
|
||||
|
@ -54,37 +53,43 @@ class getid3_real extends getid3_handler
|
|||
}
|
||||
return true;
|
||||
}
|
||||
$info['error'][] = 'There was a problem parsing this RealAudio file. Please submit it for analysis to info@getid3.org';
|
||||
$this->error('There was a problem parsing this RealAudio file. Please submit it for analysis to info@getid3.org');
|
||||
unset($info['bitrate']);
|
||||
unset($info['playtime_seconds']);
|
||||
return false;
|
||||
}
|
||||
|
||||
// shortcut
|
||||
$info['real']['chunks'][$ChunkCounter] = [];
|
||||
$info['real']['chunks'][$ChunkCounter] = array();
|
||||
$thisfile_real_chunks_currentchunk = &$info['real']['chunks'][$ChunkCounter];
|
||||
|
||||
$thisfile_real_chunks_currentchunk['name'] = $ChunkName;
|
||||
$thisfile_real_chunks_currentchunk['offset'] = $this->ftell() - 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';
|
||||
$this->warning('Chunk "'.$thisfile_real_chunks_currentchunk['name'].'" at offset '.$thisfile_real_chunks_currentchunk['offset'].' claims to be '.$thisfile_real_chunks_currentchunk['length'].' bytes long, which is beyond end of file');
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($ChunkSize > ($this->getid3->fread_buffer_size() + 8)) {
|
||||
|
||||
$ChunkData .= $this->fread($this->getid3->fread_buffer_size() - 8);
|
||||
$this->fseek($thisfile_real_chunks_currentchunk['offset'] + $ChunkSize);
|
||||
|
||||
} elseif(($ChunkSize - 8) > 0) {
|
||||
|
||||
$ChunkData .= $this->fread($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;
|
||||
|
@ -93,8 +98,9 @@ class getid3_real extends getid3_handler
|
|||
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)';
|
||||
//$this->warning('Expected .RMF-object_version to be "0", actual value is "'.$thisfile_real_chunks_currentchunk['object_version'].'" (should not be a problem)');
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -177,7 +183,7 @@ class getid3_real extends getid3_handler
|
|||
// http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html
|
||||
|
||||
// shortcut
|
||||
$thisfile_real_chunks_currentchunk['video_info'] = [];
|
||||
$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));
|
||||
|
@ -224,7 +230,7 @@ class getid3_real extends getid3_handler
|
|||
|
||||
case 'logical-fileinfo':
|
||||
// shortcut
|
||||
$thisfile_real_chunks_currentchunk['logical_fileinfo'] = [];
|
||||
$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;
|
||||
|
@ -248,6 +254,7 @@ class getid3_real extends getid3_handler
|
|||
//$thisfile_real_chunks_currentchunk_logicalfileinfo_offset += (6 + $thisfile_real_chunks_currentchunk_logicalfileinfo_thislength);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -310,12 +317,13 @@ class getid3_real extends getid3_handler
|
|||
$offset += $thisfile_real_chunks_currentchunk['comment_len'];
|
||||
|
||||
|
||||
$commentkeystocopy = ['title'=>'title', 'artist'=>'artist', 'copyright'=>'copyright', 'comment'=>'comment'];
|
||||
$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;
|
||||
|
||||
|
@ -346,7 +354,7 @@ class getid3_real extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unhandled RealMedia chunk "'.$ChunkName.'" at offset '.$thisfile_real_chunks_currentchunk['offset'];
|
||||
$this->warning('Unhandled RealMedia chunk "'.$ChunkName.'" at offset '.$thisfile_real_chunks_currentchunk['offset']);
|
||||
break;
|
||||
}
|
||||
$ChunkCounter++;
|
||||
|
@ -363,11 +371,10 @@ class getid3_real extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function ParseOldRAheader($OldRAheaderData, &$ParsedArray)
|
||||
{
|
||||
public function ParseOldRAheader($OldRAheaderData, &$ParsedArray) {
|
||||
// http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html
|
||||
|
||||
$ParsedArray = [];
|
||||
$ParsedArray = array();
|
||||
$ParsedArray['magic'] = substr($OldRAheaderData, 0, 4);
|
||||
if ($ParsedArray['magic'] != '.ra'."\xFD") {
|
||||
return false;
|
||||
|
@ -375,8 +382,11 @@ class getid3_real extends getid3_handler
|
|||
$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?
|
||||
|
@ -406,7 +416,9 @@ class getid3_real extends getid3_handler
|
|||
$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));
|
||||
|
@ -423,6 +435,7 @@ class getid3_real extends getid3_handler
|
|||
//$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));
|
||||
|
@ -457,10 +470,11 @@ class getid3_real extends getid3_handler
|
|||
$ParsedArray['channels'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 60, 2));
|
||||
$ParsedArray['genr'] = substr($OldRAheaderData, 62, 4);
|
||||
$ParsedArray['fourcc3'] = substr($OldRAheaderData, 66, 4);
|
||||
$ParsedArray['comments'] = [];
|
||||
$ParsedArray['comments'] = array();
|
||||
break;
|
||||
}
|
||||
$ParsedArray['fourcc'] = $ParsedArray['fourcc3'];
|
||||
|
||||
}
|
||||
foreach ($ParsedArray['comments'] as $key => $value) {
|
||||
if ($ParsedArray['comments'][$key][0] === false) {
|
||||
|
@ -471,9 +485,8 @@ class getid3_real extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function RealAudioCodecFourCClookup($fourcc, $bitrate)
|
||||
{
|
||||
static $RealAudioCodecFourCClookup = [];
|
||||
public 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
|
||||
|
@ -511,4 +524,5 @@ class getid3_real extends getid3_handler
|
|||
}
|
||||
return $fourcc;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,18 +27,16 @@ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE_
|
|||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true);
|
||||
|
||||
class getid3_riff extends getid3_handler
|
||||
{
|
||||
class getid3_riff extends getid3_handler {
|
||||
|
||||
protected $container = 'riff'; // default
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// initialize these values to an empty array, otherwise they default to NULL
|
||||
// and you can't append array values to a NULL value
|
||||
$info['riff'] = ['raw'=>[]];
|
||||
$info['riff'] = array('raw'=>array());
|
||||
|
||||
// Shortcuts
|
||||
$thisfile_riff = &$info['riff'];
|
||||
|
@ -60,6 +58,7 @@ class getid3_riff extends getid3_handler
|
|||
$RIFFsubtype = substr($RIFFheader, 8, 4);
|
||||
|
||||
switch ($RIFFtype) {
|
||||
|
||||
case 'FORM': // AIFF, AIFC
|
||||
//$info['fileformat'] = 'aiff';
|
||||
$this->container = 'aiff';
|
||||
|
@ -113,7 +112,7 @@ class getid3_riff extends getid3_handler
|
|||
$nextRIFFheaderID = substr($nextRIFFheader, 0, 4);
|
||||
$nextRIFFsize = $this->EitherEndian2Int(substr($nextRIFFheader, 4, 4));
|
||||
$nextRIFFtype = substr($nextRIFFheader, 8, 4);
|
||||
$chunkdata = [];
|
||||
$chunkdata = array();
|
||||
$chunkdata['offset'] = $nextRIFFoffset + 8;
|
||||
$chunkdata['size'] = $nextRIFFsize;
|
||||
$nextRIFFoffset = $chunkdata['offset'] + $chunkdata['size'];
|
||||
|
@ -122,7 +121,7 @@ class getid3_riff extends getid3_handler
|
|||
case 'RIFF':
|
||||
$chunkdata['chunks'] = $this->ParseRIFF($chunkdata['offset'] + 4, $nextRIFFoffset);
|
||||
if (!isset($thisfile_riff[$nextRIFFtype])) {
|
||||
$thisfile_riff[$nextRIFFtype] = [];
|
||||
$thisfile_riff[$nextRIFFtype] = array();
|
||||
}
|
||||
$thisfile_riff[$nextRIFFtype][] = $chunkdata;
|
||||
break;
|
||||
|
@ -153,7 +152,9 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
$this->warning('Expecting "RIFF|JUNK|IDVX" at '.$nextRIFFoffset.', found "'.$nextRIFFheaderID.'" ('.getid3_lib::PrintHexBytes($nextRIFFheaderID).') - skipping rest of file');
|
||||
break 2;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if ($RIFFsubtype == 'WAVE') {
|
||||
$thisfile_riff_WAVE = &$thisfile_riff['WAVE'];
|
||||
|
@ -168,6 +169,7 @@ class getid3_riff extends getid3_handler
|
|||
|
||||
$streamindex = 0;
|
||||
switch ($RIFFsubtype) {
|
||||
|
||||
// http://en.wikipedia.org/wiki/Wav
|
||||
case 'WAVE':
|
||||
$info['fileformat'] = 'wav';
|
||||
|
@ -184,10 +186,11 @@ class getid3_riff extends getid3_handler
|
|||
$info['avdataend'] = $info['avdataoffset'] + $thisfile_riff_WAVE['data'][0]['size'];
|
||||
}
|
||||
if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) {
|
||||
|
||||
$thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($thisfile_riff_WAVE['fmt '][0]['data']);
|
||||
$thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
|
||||
if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) || ($thisfile_riff_audio[$streamindex]['bitrate'] == 0)) {
|
||||
$info['error'][] = 'Corrupt RIFF file: bitrate_audio == zero';
|
||||
$this->error('Corrupt RIFF file: bitrate_audio == zero');
|
||||
return false;
|
||||
}
|
||||
$thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw'];
|
||||
|
@ -196,7 +199,7 @@ class getid3_riff extends getid3_handler
|
|||
|
||||
$thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
|
||||
if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
|
||||
$info['warning'][] = 'Audio codec = '.$thisfile_audio['codec'];
|
||||
$this->warning('Audio codec = '.$thisfile_audio['codec']);
|
||||
}
|
||||
$thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
|
||||
|
||||
|
@ -207,6 +210,7 @@ class getid3_riff extends getid3_handler
|
|||
$thisfile_audio['lossless'] = false;
|
||||
if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
|
||||
switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
|
||||
|
||||
case 0x0001: // PCM
|
||||
$thisfile_audio['lossless'] = true;
|
||||
break;
|
||||
|
@ -218,6 +222,7 @@ class getid3_riff extends getid3_handler
|
|||
default:
|
||||
// do nothing
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
$thisfile_audio['streams'][$streamindex]['wformattag'] = $thisfile_audio['wformattag'];
|
||||
|
@ -227,9 +232,10 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
|
||||
if (isset($thisfile_riff_WAVE['rgad'][0]['data'])) {
|
||||
|
||||
// shortcuts
|
||||
$rgadData = &$thisfile_riff_WAVE['rgad'][0]['data'];
|
||||
$thisfile_riff_raw['rgad'] = ['track'=>[], 'album'=>[]];
|
||||
$thisfile_riff_raw['rgad'] = array('track'=>array(), 'album'=>array());
|
||||
$thisfile_riff_raw_rgad = &$thisfile_riff_raw['rgad'];
|
||||
$thisfile_riff_raw_rgad_track = &$thisfile_riff_raw_rgad['track'];
|
||||
$thisfile_riff_raw_rgad_album = &$thisfile_riff_raw_rgad['album'];
|
||||
|
@ -296,10 +302,10 @@ class getid3_riff extends getid3_handler
|
|||
list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time;
|
||||
$thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime($bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second'], $bext_timestamp['month'], $bext_timestamp['day'], $bext_timestamp['year']);
|
||||
} else {
|
||||
$info['warning'][] = 'RIFF.WAVE.BEXT.origin_time is invalid';
|
||||
$this->warning('RIFF.WAVE.BEXT.origin_time is invalid');
|
||||
}
|
||||
} else {
|
||||
$info['warning'][] = 'RIFF.WAVE.BEXT.origin_date is invalid';
|
||||
$this->warning('RIFF.WAVE.BEXT.origin_date is invalid');
|
||||
}
|
||||
$thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author'];
|
||||
$thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title'];
|
||||
|
@ -379,10 +385,10 @@ class getid3_riff extends getid3_handler
|
|||
$SNDM_thisTagOffset += $SNDM_thisTagDataSize;
|
||||
|
||||
if ($SNDM_thisTagSize != (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize)) {
|
||||
$info['warning'][] = 'RIFF.WAVE.SNDM.data contains tag not expected length (expected: '.$SNDM_thisTagSize.', found: '.(4 + 4 + 2 + 2 + $SNDM_thisTagDataSize).') at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';
|
||||
$this->warning('RIFF.WAVE.SNDM.data contains tag not expected length (expected: '.$SNDM_thisTagSize.', found: '.(4 + 4 + 2 + 2 + $SNDM_thisTagDataSize).') at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')');
|
||||
break;
|
||||
} elseif ($SNDM_thisTagSize <= 0) {
|
||||
$info['warning'][] = 'RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';
|
||||
$this->warning('RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')');
|
||||
break;
|
||||
}
|
||||
$SNDM_startoffset += $SNDM_thisTagSize;
|
||||
|
@ -391,16 +397,16 @@ class getid3_riff extends getid3_handler
|
|||
if ($parsedkey = self::waveSNDMtagLookup($SNDM_thisTagKey)) {
|
||||
$thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText;
|
||||
} else {
|
||||
$info['warning'][] = 'RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';
|
||||
$this->warning('RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')');
|
||||
}
|
||||
}
|
||||
|
||||
$tagmapping = [
|
||||
$tagmapping = array(
|
||||
'tracktitle'=>'title',
|
||||
'category' =>'genre',
|
||||
'cdtitle' =>'album',
|
||||
'tracktitle'=>'title',
|
||||
];
|
||||
);
|
||||
foreach ($tagmapping as $fromkey => $tokey) {
|
||||
if (isset($thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey])) {
|
||||
$thisfile_riff['comments'][$tokey][] = $thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey];
|
||||
|
@ -422,13 +428,15 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) {
|
||||
$samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0'));
|
||||
$thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE'];
|
||||
$timestamp_sample_rate = (is_array($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) ? max($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) : $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']); // XML could possibly contain more than one TIMESTAMP_SAMPLE_RATE tag, returning as array instead of integer [why? does it make sense? perhaps doesn't matter but getID3 needs to deal with it] - see https://github.com/JamesHeinrich/getID3/issues/105
|
||||
$thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $timestamp_sample_rate;
|
||||
$h = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] / 3600);
|
||||
$m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600)) / 60);
|
||||
$s = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60));
|
||||
$f = ($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60) - $s) * $thisfile_riff_WAVE['iXML'][0]['timecode_rate'];
|
||||
$thisfile_riff_WAVE['iXML'][0]['timecode_string'] = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s, $f);
|
||||
$thisfile_riff_WAVE['iXML'][0]['timecode_string_round'] = sprintf('%02d:%02d:%02d:%02d', $h, $m, $s, round($f));
|
||||
unset($samples_since_midnight, $timestamp_sample_rate, $h, $m, $s, $f);
|
||||
}
|
||||
unset($parsedXML);
|
||||
}
|
||||
|
@ -511,11 +519,11 @@ class getid3_riff extends getid3_handler
|
|||
// }SLwFormat, *PSLwFormat;
|
||||
|
||||
// shortcut
|
||||
$thisfile_riff['litewave']['raw'] = [];
|
||||
$thisfile_riff['litewave']['raw'] = array();
|
||||
$riff_litewave = &$thisfile_riff['litewave'];
|
||||
$riff_litewave_raw = &$riff_litewave['raw'];
|
||||
|
||||
$flags = [
|
||||
$flags = array(
|
||||
'compression_method' => 1,
|
||||
'compression_flags' => 1,
|
||||
'm_dwScale' => 4,
|
||||
|
@ -526,7 +534,7 @@ class getid3_riff extends getid3_handler
|
|||
'm_dwOrgSize' => 4,
|
||||
'm_bFactExists' => 2,
|
||||
'm_dwRiffChunkSize' => 4,
|
||||
];
|
||||
);
|
||||
$litewave_offset = 18;
|
||||
foreach ($flags as $flag => $length) {
|
||||
$riff_litewave_raw[$flag] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], $litewave_offset, $length));
|
||||
|
@ -564,7 +572,7 @@ class getid3_riff extends getid3_handler
|
|||
// byte, in which case - skip warning
|
||||
} else {
|
||||
// Short by more than one byte, throw warning
|
||||
$info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';
|
||||
$this->warning('Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)');
|
||||
$info['avdataend'] = $info['filesize'];
|
||||
}
|
||||
break;
|
||||
|
@ -573,11 +581,11 @@ class getid3_riff extends getid3_handler
|
|||
if ((($info['avdataend'] - $info['filesize']) == 1) && (($thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2) == 0) && ((($info['filesize'] - $info['avdataoffset']) % 2) == 1)) {
|
||||
// output file appears to be incorrectly *not* padded to nearest WORD boundary
|
||||
// Output less severe warning
|
||||
$info['warning'][] = 'File should probably be padded to nearest WORD boundary, but it is not (expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' therefore short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';
|
||||
$this->warning('File should probably be padded to nearest WORD boundary, but it is not (expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' therefore short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)');
|
||||
$info['avdataend'] = $info['filesize'];
|
||||
} else {
|
||||
// Short by more than one byte, throw warning
|
||||
$info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';
|
||||
$this->warning('Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)');
|
||||
$info['avdataend'] = $info['filesize'];
|
||||
}
|
||||
break;
|
||||
|
@ -586,7 +594,7 @@ class getid3_riff extends getid3_handler
|
|||
if (!empty($info['mpeg']['audio']['LAME']['audio_bytes'])) {
|
||||
if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) {
|
||||
$info['avdataend']--;
|
||||
$info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
|
||||
$this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored');
|
||||
}
|
||||
}
|
||||
if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) {
|
||||
|
@ -613,7 +621,7 @@ class getid3_riff extends getid3_handler
|
|||
$info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] + $thisfile_riff['AVI ']['movi']['size'];
|
||||
}
|
||||
if ($info['avdataend'] > $info['filesize']) {
|
||||
$info['warning'][] = 'Probably truncated file - expecting '.($info['avdataend'] - $info['avdataoffset']).' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($info['avdataend'] - $info['filesize']).' bytes)';
|
||||
$this->warning('Probably truncated file - expecting '.($info['avdataend'] - $info['avdataoffset']).' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($info['avdataend'] - $info['filesize']).' bytes)');
|
||||
$info['avdataend'] = $info['filesize'];
|
||||
}
|
||||
}
|
||||
|
@ -649,16 +657,16 @@ class getid3_riff extends getid3_handler
|
|||
$avihData = $thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'];
|
||||
|
||||
// shortcut
|
||||
$thisfile_riff_raw['avih'] = [];
|
||||
$thisfile_riff_raw['avih'] = array();
|
||||
$thisfile_riff_raw_avih = &$thisfile_riff_raw['avih'];
|
||||
|
||||
$thisfile_riff_raw_avih['dwMicroSecPerFrame'] = $this->EitherEndian2Int(substr($avihData, 0, 4)); // frame display rate (or 0L)
|
||||
if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) {
|
||||
$info['error'][] = 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero';
|
||||
$this->error('Corrupt RIFF file: avih.dwMicroSecPerFrame == zero');
|
||||
return false;
|
||||
}
|
||||
|
||||
$flags = [
|
||||
$flags = array(
|
||||
'dwMaxBytesPerSec', // max. transfer rate
|
||||
'dwPaddingGranularity', // pad to multiples of this size; normally 2K.
|
||||
'dwFlags', // the ever-present flags
|
||||
|
@ -672,27 +680,27 @@ class getid3_riff extends getid3_handler
|
|||
'dwRate', //
|
||||
'dwStart', //
|
||||
'dwLength', //
|
||||
];
|
||||
);
|
||||
$avih_offset = 4;
|
||||
foreach ($flags as $flag) {
|
||||
$thisfile_riff_raw_avih[$flag] = $this->EitherEndian2Int(substr($avihData, $avih_offset, 4));
|
||||
$avih_offset += 4;
|
||||
}
|
||||
|
||||
$flags = [
|
||||
$flags = array(
|
||||
'hasindex' => 0x00000010,
|
||||
'mustuseindex' => 0x00000020,
|
||||
'interleaved' => 0x00000100,
|
||||
'trustcktype' => 0x00000800,
|
||||
'capturedfile' => 0x00010000,
|
||||
'copyrighted' => 0x00020010,
|
||||
];
|
||||
);
|
||||
foreach ($flags as $flag => $value) {
|
||||
$thisfile_riff_raw_avih['flags'][$flag] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & $value);
|
||||
}
|
||||
|
||||
// shortcut
|
||||
$thisfile_riff_video[$streamindex] = [];
|
||||
$thisfile_riff_video[$streamindex] = array();
|
||||
$thisfile_riff_video_current = &$thisfile_riff_video[$streamindex];
|
||||
|
||||
if ($thisfile_riff_raw_avih['dwWidth'] > 0) {
|
||||
|
@ -797,7 +805,7 @@ class getid3_riff extends getid3_handler
|
|||
case 'iavs':
|
||||
case 'vids':
|
||||
// shortcut
|
||||
$thisfile_riff_raw['strh'][$i] = [];
|
||||
$thisfile_riff_raw['strh'][$i] = array();
|
||||
$thisfile_riff_raw_strh_current = &$thisfile_riff_raw['strh'][$i];
|
||||
|
||||
$thisfile_riff_raw_strh_current['fccType'] = substr($strhData, 0, 4); // same as $strhfccType;
|
||||
|
@ -852,13 +860,15 @@ class getid3_riff extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"';
|
||||
$this->warning('Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"');
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
|
||||
|
||||
$thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
|
||||
if (self::fourccLookup($thisfile_video['fourcc'])) {
|
||||
$thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_video['fourcc']);
|
||||
|
@ -878,6 +888,7 @@ class getid3_riff extends getid3_handler
|
|||
//$thisfile_video['bits_per_sample'] = 24;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -954,13 +965,14 @@ class getid3_riff extends getid3_handler
|
|||
// structures rounded to 2-byte boundary, but dumb encoders
|
||||
// forget to pad end of file to make this actually work
|
||||
} else {
|
||||
$info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found';
|
||||
$this->warning('Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found');
|
||||
}
|
||||
$info['avdataend'] = $info['filesize'];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($thisfile_riff[$RIFFsubtype]['COMM'][0]['data'])) {
|
||||
|
||||
// shortcut
|
||||
$thisfile_riff_RIFFsubtype_COMM_0_data = &$thisfile_riff[$RIFFsubtype]['COMM'][0]['data'];
|
||||
|
||||
|
@ -1010,7 +1022,7 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
$thisfile_audio['sample_rate'] = $thisfile_riff_audio['sample_rate'];
|
||||
if ($thisfile_audio['sample_rate'] == 0) {
|
||||
$info['error'][] = 'Corrupted AIFF file: sample_rate == zero';
|
||||
$this->error('Corrupted AIFF file: sample_rate == zero');
|
||||
return false;
|
||||
}
|
||||
$info['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate'];
|
||||
|
@ -1035,7 +1047,7 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
}
|
||||
|
||||
$CommentsChunkNames = ['NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment'];
|
||||
$CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment');
|
||||
foreach ($CommentsChunkNames as $key => $value) {
|
||||
if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
|
||||
$thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
|
||||
|
@ -1070,7 +1082,7 @@ class getid3_riff extends getid3_handler
|
|||
$info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8;
|
||||
$info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'];
|
||||
if ($info['avdataend'] > $info['filesize']) {
|
||||
$info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found';
|
||||
$this->warning('Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1102,7 +1114,7 @@ class getid3_riff extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.sCompression.'"';
|
||||
$this->warning('Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.sCompression.'"');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1120,12 +1132,13 @@ class getid3_riff extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"';
|
||||
$this->warning('Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"');
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$CommentsChunkNames = ['NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment'];
|
||||
$CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment');
|
||||
foreach ($CommentsChunkNames as $key => $value) {
|
||||
if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
|
||||
$thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
|
||||
|
@ -1164,11 +1177,11 @@ class getid3_riff extends getid3_handler
|
|||
$info['fileformat'] = 'webp';
|
||||
$info['mime_type'] = 'image/webp';
|
||||
|
||||
$info['error'][] = 'WebP image parsing not supported in this version of getID3()';
|
||||
$this->error('WebP image parsing not supported in this version of getID3()');
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA|WEBP), found "'.$RIFFsubtype.'" instead';
|
||||
$this->error('Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA|WEBP), found "'.$RIFFsubtype.'" instead');
|
||||
//unset($info['fileformat']);
|
||||
}
|
||||
|
||||
|
@ -1177,11 +1190,11 @@ class getid3_riff extends getid3_handler
|
|||
case 'AIFF':
|
||||
case 'AIFC':
|
||||
$ID3v2_key_good = 'id3 ';
|
||||
$ID3v2_keys_bad = ['ID3 ', 'tag '];
|
||||
$ID3v2_keys_bad = array('ID3 ', 'tag ');
|
||||
foreach ($ID3v2_keys_bad as $ID3v2_key_bad) {
|
||||
if (isset($thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]) && !array_key_exists($ID3v2_key_good, $thisfile_riff[$RIFFsubtype])) {
|
||||
$thisfile_riff[$RIFFsubtype][$ID3v2_key_good] = $thisfile_riff[$RIFFsubtype][$ID3v2_key_bad];
|
||||
$info['warning'][] = 'mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"';
|
||||
$this->warning('mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1226,22 +1239,29 @@ class getid3_riff extends getid3_handler
|
|||
|
||||
if ($info['playtime_seconds'] > 0) {
|
||||
if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
|
||||
|
||||
if (!isset($info['bitrate'])) {
|
||||
$info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
|
||||
}
|
||||
|
||||
} elseif (isset($thisfile_riff_audio) && !isset($thisfile_riff_video)) {
|
||||
|
||||
if (!isset($thisfile_audio['bitrate'])) {
|
||||
$thisfile_audio['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
|
||||
}
|
||||
|
||||
} elseif (!isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
|
||||
|
||||
if (!isset($thisfile_video['bitrate'])) {
|
||||
$thisfile_video['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isset($thisfile_riff_video) && isset($thisfile_audio['bitrate']) && ($thisfile_audio['bitrate'] > 0) && ($info['playtime_seconds'] > 0)) {
|
||||
|
||||
$info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
|
||||
$thisfile_audio['bitrate'] = 0;
|
||||
$thisfile_video['bitrate'] = $info['bitrate'];
|
||||
|
@ -1309,8 +1329,7 @@ class getid3_riff extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function ParseRIFFAMV($startoffset, $maxoffset)
|
||||
{
|
||||
public function ParseRIFFAMV($startoffset, $maxoffset) {
|
||||
// AMV files are RIFF-AVI files with parts of the spec deliberately broken, such as chunk size fields hardcoded to zero (because players known in hardware that these fields are always a certain size
|
||||
|
||||
// https://code.google.com/p/amv-codec-tools/wiki/AmvDocumentation
|
||||
|
@ -1333,6 +1352,7 @@ class getid3_riff extends getid3_handler
|
|||
$RIFFchunk = false;
|
||||
|
||||
try {
|
||||
|
||||
$this->fseek($startoffset);
|
||||
$maxoffset = min($maxoffset, $info['avdataend']);
|
||||
$AMVheader = $this->fread(284);
|
||||
|
@ -1342,7 +1362,7 @@ class getid3_riff extends getid3_handler
|
|||
if (substr($AMVheader, 8, 4) != "\x38\x00\x00\x00") { // "amvh" chunk size, hardcoded to 0x38 = 56 bytes
|
||||
throw new Exception('expecting "0x38000000" at offset '.($startoffset + 8).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 8, 4)).'"');
|
||||
}
|
||||
$RIFFchunk = [];
|
||||
$RIFFchunk = array();
|
||||
$RIFFchunk['amvh']['us_per_frame'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 12, 4));
|
||||
$RIFFchunk['amvh']['reserved28'] = substr($AMVheader, 16, 28); // null? reserved?
|
||||
$RIFFchunk['amvh']['resolution_x'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 44, 4));
|
||||
|
@ -1404,6 +1424,8 @@ class getid3_riff extends getid3_handler
|
|||
$info['audio']['bits_per_sample'] = $RIFFchunk['strf']['wbitspersample'];
|
||||
$info['audio']['bitrate'] = $info['audio']['sample_rate'] * $info['audio']['channels'] * $info['audio']['bits_per_sample'];
|
||||
$info['audio']['bitrate_mode'] = 'cbr';
|
||||
|
||||
|
||||
} catch (getid3_exception $e) {
|
||||
if ($e->getCode() == 10) {
|
||||
$this->warning('RIFFAMV parser: '.$e->getMessage());
|
||||
|
@ -1416,8 +1438,7 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function ParseRIFF($startoffset, $maxoffset)
|
||||
{
|
||||
public function ParseRIFF($startoffset, $maxoffset) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$RIFFchunk = false;
|
||||
|
@ -1482,7 +1503,9 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
unset($getid3_temp, $getid3_mp3);
|
||||
}
|
||||
|
||||
} elseif (strpos($FirstFourBytes, getid3_ac3::syncword) === 0) {
|
||||
|
||||
// AC3
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
|
@ -1495,7 +1518,7 @@ class getid3_riff extends getid3_handler
|
|||
$info['ac3'] = $getid3_temp->info['ac3'];
|
||||
if (!empty($getid3_temp->info['warning'])) {
|
||||
foreach ($getid3_temp->info['warning'] as $key => $value) {
|
||||
$info['warning'][] = $value;
|
||||
$this->warning($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1506,15 +1529,18 @@ class getid3_riff extends getid3_handler
|
|||
$this->fseek($WhereWeWere);
|
||||
}
|
||||
$this->fseek($chunksize - 4, SEEK_CUR);
|
||||
|
||||
} else {
|
||||
|
||||
if (!isset($RIFFchunk[$listname])) {
|
||||
$RIFFchunk[$listname] = [];
|
||||
$RIFFchunk[$listname] = array();
|
||||
}
|
||||
$LISTchunkParent = $listname;
|
||||
$LISTchunkMaxOffset = $this->ftell() - 4 + $chunksize;
|
||||
if ($parsedChunk = $this->ParseRIFF($this->ftell(), $LISTchunkMaxOffset)) {
|
||||
$RIFFchunk[$listname] = array_merge_recursive($RIFFchunk[$listname], $parsedChunk);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1539,6 +1565,7 @@ class getid3_riff extends getid3_handler
|
|||
break;
|
||||
}
|
||||
if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', substr($testData, 0, 4))) {
|
||||
|
||||
// Probably is MP3 data
|
||||
if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
|
||||
$getid3_temp = new getID3();
|
||||
|
@ -1553,7 +1580,9 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
unset($getid3_temp, $getid3_mp3);
|
||||
}
|
||||
|
||||
} elseif (($isRegularAC3 = (substr($testData, 0, 2) == getid3_ac3::syncword)) || substr($testData, 8, 2) == strrev(getid3_ac3::syncword)) {
|
||||
|
||||
// This is probably AC-3 data
|
||||
$getid3_temp = new getID3();
|
||||
if ($isRegularAC3) {
|
||||
|
@ -1586,7 +1615,9 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
}
|
||||
unset($getid3_temp, $getid3_ac3);
|
||||
|
||||
} elseif (preg_match('/^('.implode('|', array_map('preg_quote', getid3_dts::$syncwords)).')/', $testData)) {
|
||||
|
||||
// This is probably DTS data
|
||||
$getid3_temp = new getID3();
|
||||
$getid3_temp->openfile($this->getid3->filename);
|
||||
|
@ -1605,11 +1636,14 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
|
||||
unset($getid3_temp, $getid3_dts);
|
||||
|
||||
} elseif (substr($testData, 0, 4) == 'wvpk') {
|
||||
|
||||
// This is WavPack data
|
||||
$info['wavpack']['offset'] = $info['avdataoffset'];
|
||||
$info['wavpack']['size'] = getid3_lib::LittleEndian2Int(substr($testData, 4, 4));
|
||||
$this->parseWavPackHeader(substr($testData, 8, 28));
|
||||
|
||||
} else {
|
||||
// This is some other kind of data (quite possibly just PCM)
|
||||
// do nothing special, just skip it
|
||||
|
@ -1678,6 +1712,7 @@ class getid3_riff extends getid3_handler
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (getid3_exception $e) {
|
||||
if ($e->getCode() == 10) {
|
||||
$this->warning('RIFF parser: '.$e->getMessage());
|
||||
|
@ -1689,8 +1724,7 @@ class getid3_riff extends getid3_handler
|
|||
return $RIFFchunk;
|
||||
}
|
||||
|
||||
public function ParseRIFFdata(&$RIFFdata)
|
||||
{
|
||||
public function ParseRIFFdata(&$RIFFdata) {
|
||||
$info = &$this->getid3->info;
|
||||
if ($RIFFdata) {
|
||||
$tempfile = tempnam(GETID3_TEMP_DIR, 'getID3');
|
||||
|
@ -1711,8 +1745,8 @@ class getid3_riff extends getid3_handler
|
|||
$getid3_temp->info['warning'] = $info['warning'];
|
||||
$getid3_temp->info['error'] = $info['error'];
|
||||
$getid3_temp->info['comments'] = $info['comments'];
|
||||
$getid3_temp->info['audio'] = (isset($info['audio']) ? $info['audio'] : []);
|
||||
$getid3_temp->info['video'] = (isset($info['video']) ? $info['video'] : []);
|
||||
$getid3_temp->info['audio'] = (isset($info['audio']) ? $info['audio'] : array());
|
||||
$getid3_temp->info['video'] = (isset($info['video']) ? $info['video'] : array());
|
||||
$getid3_riff = new getid3_riff($getid3_temp);
|
||||
$getid3_riff->Analyze();
|
||||
|
||||
|
@ -1727,9 +1761,8 @@ class getid3_riff extends getid3_handler
|
|||
return false;
|
||||
}
|
||||
|
||||
public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray)
|
||||
{
|
||||
$RIFFinfoKeyLookup = [
|
||||
public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) {
|
||||
$RIFFinfoKeyLookup = array(
|
||||
'IARL'=>'archivallocation',
|
||||
'IART'=>'artist',
|
||||
'ICDS'=>'costumedesigner',
|
||||
|
@ -1770,7 +1803,7 @@ class getid3_riff extends getid3_handler
|
|||
'IWEB'=>'url',
|
||||
'IWRI'=>'writer',
|
||||
'____'=>'comment',
|
||||
];
|
||||
);
|
||||
foreach ($RIFFinfoKeyLookup as $key => $value) {
|
||||
if (isset($RIFFinfoArray[$key])) {
|
||||
foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) {
|
||||
|
@ -1778,7 +1811,7 @@ class getid3_riff extends getid3_handler
|
|||
if (isset($CommentsTargetArray[$value])) {
|
||||
$CommentsTargetArray[$value][] = trim($commentdata['data']);
|
||||
} else {
|
||||
$CommentsTargetArray[$value] = [trim($commentdata['data'])];
|
||||
$CommentsTargetArray[$value] = array(trim($commentdata['data']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1787,10 +1820,9 @@ class getid3_riff extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public static function parseWAVEFORMATex($WaveFormatExData)
|
||||
{
|
||||
public static function parseWAVEFORMATex($WaveFormatExData) {
|
||||
// shortcut
|
||||
$WaveFormatEx['raw'] = [];
|
||||
$WaveFormatEx['raw'] = array();
|
||||
$WaveFormatEx_raw = &$WaveFormatEx['raw'];
|
||||
|
||||
$WaveFormatEx_raw['wFormatTag'] = substr($WaveFormatExData, 0, 2);
|
||||
|
@ -1813,8 +1845,7 @@ class getid3_riff extends getid3_handler
|
|||
return $WaveFormatEx;
|
||||
}
|
||||
|
||||
public function parseWavPackHeader($WavPackChunkData)
|
||||
{
|
||||
public function parseWavPackHeader($WavPackChunkData) {
|
||||
// typedef struct {
|
||||
// char ckID [4];
|
||||
// long ckSize;
|
||||
|
@ -1827,7 +1858,7 @@ class getid3_riff extends getid3_handler
|
|||
|
||||
// shortcut
|
||||
$info = &$this->getid3->info;
|
||||
$info['wavpack'] = [];
|
||||
$info['wavpack'] = array();
|
||||
$thisfile_wavpack = &$info['wavpack'];
|
||||
|
||||
$thisfile_wavpack['version'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 0, 2));
|
||||
|
@ -1847,7 +1878,7 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
|
||||
// shortcut
|
||||
$thisfile_wavpack['flags'] = [];
|
||||
$thisfile_wavpack['flags'] = array();
|
||||
$thisfile_wavpack_flags = &$thisfile_wavpack['flags'];
|
||||
|
||||
$thisfile_wavpack_flags['mono'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000001);
|
||||
|
@ -1875,8 +1906,7 @@ class getid3_riff extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian = true)
|
||||
{
|
||||
public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) {
|
||||
|
||||
$parsed['biSize'] = substr($BITMAPINFOHEADER, 0, 4); // number of bytes required by the BITMAPINFOHEADER structure
|
||||
$parsed['biWidth'] = substr($BITMAPINFOHEADER, 4, 4); // width of the bitmap in pixels
|
||||
|
@ -1895,8 +1925,7 @@ class getid3_riff extends getid3_handler
|
|||
return $parsed;
|
||||
}
|
||||
|
||||
public static function ParseDIVXTAG($DIVXTAG, $raw = false)
|
||||
{
|
||||
public static function ParseDIVXTAG($DIVXTAG, $raw=false) {
|
||||
// structure from "IDivX" source, Form1.frm, by "Greg Frazier of Daemonic Software Group", email: gfrazier@icestorm.net, web: http://dsg.cjb.net/
|
||||
// source available at http://files.divx-digest.com/download/c663efe7ef8ad2e90bf4af4d3ea6188a/on0SWN2r/edit/IDivX.zip
|
||||
// 'Byte Layout: '1111111111111111
|
||||
|
@ -1909,7 +1938,7 @@ class getid3_riff extends getid3_handler
|
|||
// '5 for Future Additions - 0 '333400000DIVXTAG
|
||||
// '128 bytes total
|
||||
|
||||
static $DIVXTAGgenre = [
|
||||
static $DIVXTAGgenre = array(
|
||||
0 => 'Action',
|
||||
1 => 'Action/Adventure',
|
||||
2 => 'Adventure',
|
||||
|
@ -1932,15 +1961,15 @@ class getid3_riff extends getid3_handler
|
|||
19 => 'Sci Fi',
|
||||
20 => 'Thriller',
|
||||
21 => 'Western',
|
||||
],
|
||||
$DIVXTAGrating = [
|
||||
),
|
||||
$DIVXTAGrating = array(
|
||||
0 => 'Unrated',
|
||||
1 => 'G',
|
||||
2 => 'PG',
|
||||
3 => 'PG-13',
|
||||
4 => 'R',
|
||||
5 => 'NC-17',
|
||||
];
|
||||
);
|
||||
|
||||
$parsed['title'] = trim(substr($DIVXTAG, 0, 32));
|
||||
$parsed['artist'] = trim(substr($DIVXTAG, 32, 28));
|
||||
|
@ -1964,14 +1993,13 @@ class getid3_riff extends getid3_handler
|
|||
}
|
||||
|
||||
foreach ($parsed as $tag => $value) {
|
||||
$parsed[$tag] = [$value];
|
||||
$parsed[$tag] = array($value);
|
||||
}
|
||||
|
||||
return $parsed;
|
||||
}
|
||||
|
||||
public static function waveSNDMtagLookup($tagshortname)
|
||||
{
|
||||
public static function waveSNDMtagLookup($tagshortname) {
|
||||
$begin = __LINE__;
|
||||
|
||||
/** This is not a comment!
|
||||
|
@ -1994,8 +2022,7 @@ class getid3_riff extends getid3_handler
|
|||
return getid3_lib::EmbeddedLookup($tagshortname, $begin, __LINE__, __FILE__, 'riff-sndm');
|
||||
}
|
||||
|
||||
public static function wFormatTagLookup($wFormatTag)
|
||||
{
|
||||
public static function wFormatTagLookup($wFormatTag) {
|
||||
|
||||
$begin = __LINE__;
|
||||
|
||||
|
@ -2164,8 +2191,7 @@ class getid3_riff extends getid3_handler
|
|||
return getid3_lib::EmbeddedLookup('0x'.str_pad(strtoupper(dechex($wFormatTag)), 4, '0', STR_PAD_LEFT), $begin, __LINE__, __FILE__, 'riff-wFormatTag');
|
||||
}
|
||||
|
||||
public static function fourccLookup($fourcc)
|
||||
{
|
||||
public static function fourccLookup($fourcc) {
|
||||
|
||||
$begin = __LINE__;
|
||||
|
||||
|
@ -2559,11 +2585,11 @@ class getid3_riff extends getid3_handler
|
|||
return getid3_lib::EmbeddedLookup($fourcc, $begin, __LINE__, __FILE__, 'riff-fourcc');
|
||||
}
|
||||
|
||||
private function EitherEndian2Int($byteword, $signed = false)
|
||||
{
|
||||
private function EitherEndian2Int($byteword, $signed=false) {
|
||||
if ($this->container == 'riff') {
|
||||
return getid3_lib::LittleEndian2Int($byteword, $signed);
|
||||
}
|
||||
return getid3_lib::BigEndian2Int($byteword, false, $signed);
|
||||
}
|
||||
|
||||
}
|
|
@ -19,8 +19,7 @@ class getid3_swf extends getid3_handler
|
|||
{
|
||||
public $ReturnAllTagData = false;
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'swf';
|
||||
|
@ -43,7 +42,7 @@ class getid3_swf extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Expecting "FWS" or "CWS" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['swf']['header']['signature']).'"';
|
||||
$this->error('Expecting "FWS" or "CWS" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['swf']['header']['signature']).'"');
|
||||
unset($info['swf']);
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
|
@ -58,7 +57,7 @@ class getid3_swf extends getid3_handler
|
|||
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)';
|
||||
$this->error('Error decompressing compressed SWF data ('.strlen($SWFfileData).' bytes compressed, should be '.($info['swf']['header']['length'] - 8).' bytes uncompressed)');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -137,4 +136,5 @@ class getid3_swf extends getid3_handler
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,15 +18,14 @@
|
|||
class getid3_ts extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$TSheader = $this->fread(19);
|
||||
$magic = "\x47";
|
||||
if (substr($TSheader, 0, 1) != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($TSheader, 0, 1)).' instead.';
|
||||
$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($TSheader, 0, 1)).' instead.');
|
||||
return false;
|
||||
}
|
||||
$info['fileformat'] = 'ts';
|
||||
|
@ -34,12 +33,9 @@ class getid3_ts extends getid3_handler
|
|||
// http://en.wikipedia.org/wiki/.ts
|
||||
|
||||
$offset = 0;
|
||||
$info['ts']['packet']['sync'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 1));
|
||||
$offset += 1;
|
||||
$pid_flags_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$SAC_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 1));
|
||||
$offset += 1;
|
||||
$info['ts']['packet']['sync'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 1)); $offset += 1;
|
||||
$pid_flags_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 2)); $offset += 2;
|
||||
$SAC_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 1)); $offset += 1;
|
||||
$info['ts']['packet']['flags']['transport_error_indicator'] = (bool) ($pid_flags_raw & 0x8000); // Set by demodulator if can't correct errors in the stream, to tell the demultiplexer that the packet has an uncorrectable error
|
||||
$info['ts']['packet']['flags']['payload_unit_start_indicator'] = (bool) ($pid_flags_raw & 0x4000); // 1 means start of PES data or PSI otherwise zero only.
|
||||
$info['ts']['packet']['flags']['transport_high_priority'] = (bool) ($pid_flags_raw & 0x2000); // 1 means higher priority than other packets with the same PID.
|
||||
|
@ -52,8 +48,7 @@ class getid3_ts extends getid3_handler
|
|||
$info['ts']['packet']['scrambling_control'] = $this->TSscramblingControlLookup($info['ts']['packet']['raw']['scrambling_control']);
|
||||
|
||||
if ($info['ts']['packet']['flags']['adaption_field_exists']) {
|
||||
$AdaptionField_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 2));
|
||||
$offset += 2;
|
||||
$AdaptionField_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 2)); $offset += 2;
|
||||
$info['ts']['packet']['adaption']['field_length'] = ($AdaptionField_raw & 0xFF00) >> 8; // Number of bytes in the adaptation field immediately following this byte
|
||||
$info['ts']['packet']['adaption']['flags']['discontinuity'] = (bool) ($AdaptionField_raw & 0x0080); // Set to 1 if current TS packet is in a discontinuity state with respect to either the continuity counter or the program clock reference
|
||||
$info['ts']['packet']['adaption']['flags']['random_access'] = (bool) ($AdaptionField_raw & 0x0040); // Set to 1 if the PES packet in this TS packet starts a video/audio sequence
|
||||
|
@ -64,23 +59,21 @@ class getid3_ts extends getid3_handler
|
|||
$info['ts']['packet']['adaption']['flags']['private_data'] = (bool) ($AdaptionField_raw & 0x0002); // 1 means presence of private data bytes in adaptation field
|
||||
$info['ts']['packet']['adaption']['flags']['extension'] = (bool) ($AdaptionField_raw & 0x0001); // 1 means presence of adaptation field extension
|
||||
if ($info['ts']['packet']['adaption']['flags']['pcr']) {
|
||||
$info['ts']['packet']['adaption']['raw']['pcr'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 6));
|
||||
$offset += 6;
|
||||
$info['ts']['packet']['adaption']['raw']['pcr'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 6)); $offset += 6;
|
||||
}
|
||||
if ($info['ts']['packet']['adaption']['flags']['opcr']) {
|
||||
$info['ts']['packet']['adaption']['raw']['opcr'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 6));
|
||||
$offset += 6;
|
||||
$info['ts']['packet']['adaption']['raw']['opcr'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 6)); $offset += 6;
|
||||
}
|
||||
}
|
||||
|
||||
$info['error'][] = 'MPEG Transport Stream (.ts) parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
|
||||
$this->error('MPEG Transport Stream (.ts) parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function TSscramblingControlLookup($raw)
|
||||
{
|
||||
$TSscramblingControlLookup = [0x00=>'not scrambled', 0x01=>'reserved', 0x02=>'scrambled, even key', 0x03=>'scrambled, odd key'];
|
||||
public function TSscramblingControlLookup($raw) {
|
||||
$TSscramblingControlLookup = array(0x00=>'not scrambled', 0x01=>'reserved', 0x02=>'scrambled, even key', 0x03=>'scrambled, odd key');
|
||||
return (isset($TSscramblingControlLookup[$raw]) ? $TSscramblingControlLookup[$raw] : 'invalid');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
class getid3_aa extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
@ -27,24 +26,24 @@ class getid3_aa extends getid3_handler
|
|||
|
||||
$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)).'"';
|
||||
$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AAheader, 4, 4)).'"');
|
||||
return false;
|
||||
}
|
||||
|
||||
// shortcut
|
||||
$info['aa'] = [];
|
||||
$info['aa'] = array();
|
||||
$thisfile_aa = &$info['aa'];
|
||||
|
||||
$info['fileformat'] = 'aa';
|
||||
$info['audio']['dataformat'] = 'aa';
|
||||
$info['error'][] = 'Audible Audiobook (.aa) parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
|
||||
$this->error('Audible Audiobook (.aa) parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
|
||||
return false;
|
||||
$info['audio']['bitrate_mode'] = 'cbr'; // is it?
|
||||
$thisfile_aa['encoding'] = 'ISO-8859-1';
|
||||
|
||||
$thisfile_aa['filesize'] = getid3_lib::BigEndian2Int(substr($AUheader, 0, 4));
|
||||
if ($thisfile_aa['filesize'] > ($info['avdataend'] - $info['avdataoffset'])) {
|
||||
$info['warning'][] = 'Possible truncated file - expecting "'.$thisfile_aa['filesize'].'" bytes of data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"';
|
||||
$this->warning('Possible truncated file - expecting "'.$thisfile_aa['filesize'].'" bytes of data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"');
|
||||
}
|
||||
|
||||
$info['audio']['bits_per_sample'] = 16; // is it?
|
||||
|
@ -56,4 +55,5 @@ class getid3_aa extends getid3_handler
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,8 +17,7 @@
|
|||
|
||||
class getid3_aac extends getid3_handler
|
||||
{
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
$this->fseek($info['avdataoffset']);
|
||||
if ($this->fread(4) == 'ADIF') {
|
||||
|
@ -31,8 +30,7 @@ class getid3_aac extends getid3_handler
|
|||
|
||||
|
||||
|
||||
public function getAACADIFheaderFilepointer()
|
||||
{
|
||||
public function getAACADIFheaderFilepointer() {
|
||||
$info = &$this->getid3->info;
|
||||
$info['fileformat'] = 'aac';
|
||||
$info['audio']['dataformat'] = 'aac';
|
||||
|
@ -43,6 +41,7 @@ class getid3_aac extends getid3_handler
|
|||
$offset = 0;
|
||||
|
||||
if (substr($AACheader, 0, 4) == 'ADIF') {
|
||||
|
||||
// http://faac.sourceforge.net/wiki/index.php?page=ADIF
|
||||
|
||||
// http://libmpeg.org/mpeg4/doc/w2203tfs.pdf
|
||||
|
@ -93,7 +92,7 @@ class getid3_aac extends getid3_handler
|
|||
$info['audio']['bitrate'] = $info['aac']['header']['bitrate'];
|
||||
}
|
||||
if ($info['audio']['bitrate'] == 0) {
|
||||
$info['error'][] = 'Corrupt AAC file: bitrate_audio == zero';
|
||||
$this->error('Corrupt AAC file: bitrate_audio == zero');
|
||||
return false;
|
||||
}
|
||||
$info['aac']['header']['num_program_configs'] = 1 + getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
|
||||
|
@ -246,17 +245,20 @@ class getid3_aac extends getid3_handler
|
|||
|
||||
|
||||
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)';
|
||||
$this->error('AAC-ADIF synch not found at offset '.$info['avdataoffset'].' (expected "ADIF", found "'.substr($AACheader, 0, 4).'" instead)');
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function getAACADTSheaderFilepointer($MaxFramesToScan = 1000000, $ReturnExtendedInfo = false)
|
||||
{
|
||||
public function getAACADTSheaderFilepointer($MaxFramesToScan=1000000, $ReturnExtendedInfo=false) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// based loosely on code from AACfile by Jurgen Faul <jfaulØgmx.de>
|
||||
|
@ -293,7 +295,7 @@ class getid3_aac extends getid3_handler
|
|||
$framenumber = 0;
|
||||
|
||||
// Init bit pattern array
|
||||
static $decbin = [];
|
||||
static $decbin = array();
|
||||
|
||||
// Populate $bindec
|
||||
for ($i = 0; $i < 256; $i++) {
|
||||
|
@ -301,7 +303,7 @@ class getid3_aac extends getid3_handler
|
|||
}
|
||||
|
||||
// used to calculate bitrate below
|
||||
$BitrateCache = [];
|
||||
$BitrateCache = array();
|
||||
|
||||
|
||||
while (true) {
|
||||
|
@ -309,7 +311,7 @@ class getid3_aac extends getid3_handler
|
|||
// or MaxFramesToScan frames have been scanned
|
||||
|
||||
if (!getid3_lib::intValueSupported($byteoffset)) {
|
||||
$info['warning'][] = 'Unable to parse AAC file beyond '.$this->ftell().' (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)';
|
||||
$this->warning('Unable to parse AAC file beyond '.$this->ftell().' (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)');
|
||||
return false;
|
||||
}
|
||||
$this->fseek($byteoffset);
|
||||
|
@ -318,7 +320,7 @@ class getid3_aac extends getid3_handler
|
|||
$substring = $this->fread(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 '.($this->ftell() - $substringlength).' (only read '.$substringlength.' bytes)';
|
||||
$this->error('Failed to read 7 bytes at offset '.($this->ftell() - $substringlength).' (only read '.$substringlength.' bytes)');
|
||||
return false;
|
||||
}
|
||||
// this would be easier with 64-bit math, but split it up to allow for 32-bit:
|
||||
|
@ -328,7 +330,7 @@ class getid3_aac extends getid3_handler
|
|||
|
||||
$info['aac']['header']['raw']['syncword'] = ($header1 & 0xFFF0) >> 4;
|
||||
if ($info['aac']['header']['raw']['syncword'] != 0x0FFF) {
|
||||
$info['error'][] = 'Synch pattern (0x0FFF) not found at offset '.($this->ftell() - $substringlength).' (found 0x0'.strtoupper(dechex($info['aac']['header']['raw']['syncword'])).' instead)';
|
||||
$this->error('Synch pattern (0x0FFF) not found at offset '.($this->ftell() - $substringlength).' (found 0x0'.strtoupper(dechex($info['aac']['header']['raw']['syncword'])).' instead)');
|
||||
//if ($info['fileformat'] == 'aac') {
|
||||
// return true;
|
||||
//}
|
||||
|
@ -370,10 +372,10 @@ class getid3_aac extends getid3_handler
|
|||
}
|
||||
|
||||
if ($info['aac']['header']['raw']['mpeg_layer'] != 0) {
|
||||
$info['warning'][] = 'Layer error - expected "0", found "'.$info['aac']['header']['raw']['mpeg_layer'].'" instead';
|
||||
$this->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';
|
||||
$this->error('Corrupt AAC file: sample_frequency == zero');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -418,12 +420,15 @@ class getid3_aac extends getid3_handler
|
|||
|
||||
$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';
|
||||
$this->error('Corrupt AAC file: playtime_seconds == zero');
|
||||
return false;
|
||||
}
|
||||
$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
|
@ -432,14 +437,14 @@ class getid3_aac extends getid3_handler
|
|||
$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 = [];
|
||||
public static function AACsampleRateLookup($samplerateid) {
|
||||
static $AACsampleRateLookup = array();
|
||||
if (empty($AACsampleRateLookup)) {
|
||||
$AACsampleRateLookup[0] = 96000;
|
||||
$AACsampleRateLookup[1] = 88200;
|
||||
|
@ -461,9 +466,8 @@ class getid3_aac extends getid3_handler
|
|||
return (isset($AACsampleRateLookup[$samplerateid]) ? $AACsampleRateLookup[$samplerateid] : 'invalid');
|
||||
}
|
||||
|
||||
public static function AACprofileLookup($profileid, $mpegversion)
|
||||
{
|
||||
static $AACprofileLookup = [];
|
||||
public static function AACprofileLookup($profileid, $mpegversion) {
|
||||
static $AACprofileLookup = array();
|
||||
if (empty($AACprofileLookup)) {
|
||||
$AACprofileLookup[2][0] = 'Main profile';
|
||||
$AACprofileLookup[2][1] = 'Low Complexity profile (LC)';
|
||||
|
@ -477,8 +481,7 @@ class getid3_aac extends getid3_handler
|
|||
return (isset($AACprofileLookup[$mpegversion][$profileid]) ? $AACprofileLookup[$mpegversion][$profileid] : 'invalid');
|
||||
}
|
||||
|
||||
public static function AACchannelCountCalculate($program_configs)
|
||||
{
|
||||
public static function AACchannelCountCalculate($program_configs) {
|
||||
$channels = 0;
|
||||
for ($i = 0; $i < $program_configs['num_front_channel_elements']; $i++) {
|
||||
$channels++;
|
||||
|
@ -506,4 +509,5 @@ class getid3_aac extends getid3_handler
|
|||
}
|
||||
return $channels;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,17 +17,16 @@
|
|||
|
||||
class getid3_ac3 extends getid3_handler
|
||||
{
|
||||
private $AC3header = [];
|
||||
private $AC3header = array();
|
||||
private $BSIoffset = 0;
|
||||
|
||||
const syncword = "\x0B\x77";
|
||||
const syncword = 0x0B77;
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
///AH
|
||||
$info['ac3']['raw']['bsi'] = [];
|
||||
$info['ac3']['raw']['bsi'] = array();
|
||||
$thisfile_ac3 = &$info['ac3'];
|
||||
$thisfile_ac3_raw = &$thisfile_ac3['raw'];
|
||||
$thisfile_ac3_raw_bsi = &$thisfile_ac3_raw['bsi'];
|
||||
|
@ -56,54 +55,390 @@ class getid3_ac3 extends getid3_handler
|
|||
// } /* end of syncinfo */
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$this->AC3header['syncinfo'] = $this->fread(5);
|
||||
$tempAC3header = $this->fread(100); // should be enough to cover all data, there are some variable-length fields...?
|
||||
$this->AC3header['syncinfo'] = getid3_lib::BigEndian2Int(substr($tempAC3header, 0, 2));
|
||||
$this->AC3header['bsi'] = getid3_lib::BigEndian2Bin(substr($tempAC3header, 2));
|
||||
$thisfile_ac3_raw_bsi['bsid'] = (getid3_lib::LittleEndian2Int(substr($tempAC3header, 5, 1)) & 0xF8) >> 3; // AC3 and E-AC3 put the "bsid" version identifier in the same place, but unfortnately the 4 bytes between the syncword and the version identifier are interpreted differently, so grab it here so the following code structure can make sense
|
||||
unset($tempAC3header);
|
||||
|
||||
if (strpos($this->AC3header['syncinfo'], self::syncword) === 0) {
|
||||
$thisfile_ac3_raw['synchinfo']['synchword'] = self::syncword;
|
||||
$offset = 2;
|
||||
} else {
|
||||
if ($this->AC3header['syncinfo'] !== self::syncword) {
|
||||
if (!$this->isDependencyFor('matroska')) {
|
||||
unset($info['fileformat'], $info['ac3']);
|
||||
return $this->error('Expecting "'.getid3_lib::PrintHexBytes(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($this->AC3header['syncinfo'], 0, 2)).'"');
|
||||
return $this->error('Expecting "'.dechex(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.dechex($this->AC3header['syncinfo']).'"');
|
||||
}
|
||||
$offset = 0;
|
||||
$this->fseek(-2, SEEK_CUR);
|
||||
}
|
||||
|
||||
$info['audio']['dataformat'] = 'ac3';
|
||||
$info['audio']['bitrate_mode'] = 'cbr';
|
||||
$info['audio']['lossless'] = false;
|
||||
|
||||
$thisfile_ac3_raw['synchinfo']['crc1'] = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], $offset, 2));
|
||||
$ac3_synchinfo_fscod_frmsizecod = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], ($offset + 2), 1));
|
||||
$thisfile_ac3_raw['synchinfo']['fscod'] = ($ac3_synchinfo_fscod_frmsizecod & 0xC0) >> 6;
|
||||
$thisfile_ac3_raw['synchinfo']['frmsizecod'] = ($ac3_synchinfo_fscod_frmsizecod & 0x3F);
|
||||
if ($thisfile_ac3_raw_bsi['bsid'] <= 8) {
|
||||
|
||||
$thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup($thisfile_ac3_raw['synchinfo']['fscod']);
|
||||
if ($thisfile_ac3_raw['synchinfo']['fscod'] <= 3) {
|
||||
$info['audio']['sample_rate'] = $thisfile_ac3['sample_rate'];
|
||||
}
|
||||
|
||||
$thisfile_ac3['frame_length'] = self::frameSizeLookup($thisfile_ac3_raw['synchinfo']['frmsizecod'], $thisfile_ac3_raw['synchinfo']['fscod']);
|
||||
$thisfile_ac3['bitrate'] = self::bitrateLookup($thisfile_ac3_raw['synchinfo']['frmsizecod']);
|
||||
$info['audio']['bitrate'] = $thisfile_ac3['bitrate'];
|
||||
|
||||
$this->AC3header['bsi'] = getid3_lib::BigEndian2Bin($this->fread(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.
|
||||
$this->error('Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 8');
|
||||
unset($info['ac3']);
|
||||
return false;
|
||||
$thisfile_ac3_raw_bsi['crc1'] = getid3_lib::Bin2Dec($this->readHeaderBSI(16));
|
||||
$thisfile_ac3_raw_bsi['fscod'] = $this->readHeaderBSI(2); // 5.4.1.3
|
||||
$thisfile_ac3_raw_bsi['frmsizecod'] = $this->readHeaderBSI(6); // 5.4.1.4
|
||||
if ($thisfile_ac3_raw_bsi['frmsizecod'] > 37) { // binary: 100101 - see Table 5.18 Frame Size Code Table (1 word = 16 bits)
|
||||
$this->warning('Unexpected ac3.bsi.frmsizecod value: '.$thisfile_ac3_raw_bsi['frmsizecod'].', bitrate not set correctly');
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5); // we already know this from pre-parsing the version identifier, but re-read it to let the bitstream flow as intended
|
||||
$thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3);
|
||||
$thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3);
|
||||
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] & 0x01) {
|
||||
// If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream.
|
||||
$thisfile_ac3_raw_bsi['cmixlev'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3['center_mix_level'] = self::centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']);
|
||||
}
|
||||
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) {
|
||||
// If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream.
|
||||
$thisfile_ac3_raw_bsi['surmixlev'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3['surround_mix_level'] = self::surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']);
|
||||
}
|
||||
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] == 0x02) {
|
||||
// When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround.
|
||||
$thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3['dolby_surround_mode'] = self::dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['lfeon'] = (bool) $this->readHeaderBSI(1);
|
||||
|
||||
// This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31.
|
||||
// The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
|
||||
$thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5); // 5.4.2.8 dialnorm: Dialogue Normalization, 5 Bits
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['compr'] = (bool) $this->readHeaderBSI(1); // 5.4.2.9 compre: Compression Gain Word Exists, 1 Bit
|
||||
if ($thisfile_ac3_raw_bsi['flags']['compr']) {
|
||||
$thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8); // 5.4.2.10 compr: Compression Gain Word, 8 Bits
|
||||
$thisfile_ac3['heavy_compression'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr']);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['langcod'] = (bool) $this->readHeaderBSI(1); // 5.4.2.11 langcode: Language Code Exists, 1 Bit
|
||||
if ($thisfile_ac3_raw_bsi['flags']['langcod']) {
|
||||
$thisfile_ac3_raw_bsi['langcod'] = $this->readHeaderBSI(8); // 5.4.2.12 langcod: Language Code, 8 Bits
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['audprodinfo'] = (bool) $this->readHeaderBSI(1); // 5.4.2.13 audprodie: Audio Production Information Exists, 1 Bit
|
||||
if ($thisfile_ac3_raw_bsi['flags']['audprodinfo']) {
|
||||
$thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5); // 5.4.2.14 mixlevel: Mixing Level, 5 Bits
|
||||
$thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2); // 5.4.2.15 roomtyp: Room Type, 2 Bits
|
||||
|
||||
$thisfile_ac3['mixing_level'] = (80 + $thisfile_ac3_raw_bsi['mixlevel']).'dB';
|
||||
$thisfile_ac3['room_type'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp']);
|
||||
}
|
||||
|
||||
|
||||
$thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5); // 5.4.2.16 dialnorm2: Dialogue Normalization, ch2, 5 Bits
|
||||
$thisfile_ac3['dialogue_normalization2'] = '-'.$thisfile_ac3_raw_bsi['dialnorm2'].'dB'; // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31. The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['compr2'] = (bool) $this->readHeaderBSI(1); // 5.4.2.17 compr2e: Compression Gain Word Exists, ch2, 1 Bit
|
||||
if ($thisfile_ac3_raw_bsi['flags']['compr2']) {
|
||||
$thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8); // 5.4.2.18 compr2: Compression Gain Word, ch2, 8 Bits
|
||||
$thisfile_ac3['heavy_compression2'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr2']);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['langcod2'] = (bool) $this->readHeaderBSI(1); // 5.4.2.19 langcod2e: Language Code Exists, ch2, 1 Bit
|
||||
if ($thisfile_ac3_raw_bsi['flags']['langcod2']) {
|
||||
$thisfile_ac3_raw_bsi['langcod2'] = $this->readHeaderBSI(8); // 5.4.2.20 langcod2: Language Code, ch2, 8 Bits
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['audprodinfo2'] = (bool) $this->readHeaderBSI(1); // 5.4.2.21 audprodi2e: Audio Production Information Exists, ch2, 1 Bit
|
||||
if ($thisfile_ac3_raw_bsi['flags']['audprodinfo2']) {
|
||||
$thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5); // 5.4.2.22 mixlevel2: Mixing Level, ch2, 5 Bits
|
||||
$thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2); // 5.4.2.23 roomtyp2: Room Type, ch2, 2 Bits
|
||||
|
||||
$thisfile_ac3['mixing_level2'] = (80 + $thisfile_ac3_raw_bsi['mixlevel2']).'dB';
|
||||
$thisfile_ac3['room_type2'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp2']);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['copyright'] = (bool) $this->readHeaderBSI(1); // 5.4.2.24 copyrightb: Copyright Bit, 1 Bit
|
||||
|
||||
$thisfile_ac3_raw_bsi['original'] = (bool) $this->readHeaderBSI(1); // 5.4.2.25 origbs: Original Bit Stream, 1 Bit
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['timecod1'] = $this->readHeaderBSI(2); // 5.4.2.26 timecod1e, timcode2e: Time Code (first and second) Halves Exist, 2 Bits
|
||||
if ($thisfile_ac3_raw_bsi['flags']['timecod1'] & 0x01) {
|
||||
$thisfile_ac3_raw_bsi['timecod1'] = $this->readHeaderBSI(14); // 5.4.2.27 timecod1: Time code first half, 14 bits
|
||||
$thisfile_ac3['timecode1'] = 0;
|
||||
$thisfile_ac3['timecode1'] += (($thisfile_ac3_raw_bsi['timecod1'] & 0x3E00) >> 9) * 3600; // The first 5 bits of this 14-bit field represent the time in hours, with valid values of 0–23
|
||||
$thisfile_ac3['timecode1'] += (($thisfile_ac3_raw_bsi['timecod1'] & 0x01F8) >> 3) * 60; // The next 6 bits represent the time in minutes, with valid values of 0–59
|
||||
$thisfile_ac3['timecode1'] += (($thisfile_ac3_raw_bsi['timecod1'] & 0x0003) >> 0) * 8; // The final 3 bits represents the time in 8 second increments, with valid values of 0–7 (representing 0, 8, 16, ... 56 seconds)
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['flags']['timecod1'] & 0x02) {
|
||||
$thisfile_ac3_raw_bsi['timecod2'] = $this->readHeaderBSI(14); // 5.4.2.28 timecod2: Time code second half, 14 bits
|
||||
$thisfile_ac3['timecode2'] = 0;
|
||||
$thisfile_ac3['timecode2'] += (($thisfile_ac3_raw_bsi['timecod2'] & 0x3800) >> 11) * 1; // The first 3 bits of this 14-bit field represent the time in seconds, with valid values from 0–7 (representing 0-7 seconds)
|
||||
$thisfile_ac3['timecode2'] += (($thisfile_ac3_raw_bsi['timecod2'] & 0x07C0) >> 6) * (1 / 30); // The next 5 bits represents the time in frames, with valid values from 0–29 (one frame = 1/30th of a second)
|
||||
$thisfile_ac3['timecode2'] += (($thisfile_ac3_raw_bsi['timecod2'] & 0x003F) >> 0) * ((1 / 30) / 60); // The final 6 bits represents fractions of 1/64 of a frame, with valid values from 0–63
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['flags']['addbsi'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['addbsi']) {
|
||||
$thisfile_ac3_raw_bsi['addbsi_length'] = $this->readHeaderBSI(6) + 1; // This 6-bit code, which exists only if addbside is a 1, indicates the length in bytes of additional bit stream information. The valid range of addbsil is 0–63, indicating 1–64 additional bytes, respectively.
|
||||
|
||||
$this->AC3header['bsi'] .= getid3_lib::BigEndian2Bin($this->fread($thisfile_ac3_raw_bsi['addbsi_length']));
|
||||
|
||||
$thisfile_ac3_raw_bsi['addbsi_data'] = substr($this->AC3header['bsi'], $this->BSIoffset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8);
|
||||
$this->BSIoffset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8;
|
||||
}
|
||||
|
||||
|
||||
} elseif ($thisfile_ac3_raw_bsi['bsid'] <= 16) { // E-AC3
|
||||
|
||||
|
||||
$this->error('E-AC3 parsing is incomplete and experimental in this version of getID3 ('.$this->getid3->version().'). Notably the bitrate calculations are wrong -- value might (or not) be correct, but it is not calculated correctly. Email info@getid3.org if you know how to calculate EAC3 bitrate correctly.');
|
||||
$info['audio']['dataformat'] = 'eac3';
|
||||
|
||||
$thisfile_ac3_raw_bsi['strmtyp'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3_raw_bsi['substreamid'] = $this->readHeaderBSI(3);
|
||||
$thisfile_ac3_raw_bsi['frmsiz'] = $this->readHeaderBSI(11);
|
||||
$thisfile_ac3_raw_bsi['fscod'] = $this->readHeaderBSI(2);
|
||||
if ($thisfile_ac3_raw_bsi['fscod'] == 3) {
|
||||
$thisfile_ac3_raw_bsi['fscod2'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3_raw_bsi['numblkscod'] = 3; // six blocks per syncframe
|
||||
} else {
|
||||
$thisfile_ac3_raw_bsi['numblkscod'] = $this->readHeaderBSI(2);
|
||||
}
|
||||
$thisfile_ac3['bsi']['blocks_per_sync_frame'] = self::blocksPerSyncFrame($thisfile_ac3_raw_bsi['numblkscod']);
|
||||
$thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3);
|
||||
$thisfile_ac3_raw_bsi['flags']['lfeon'] = (bool) $this->readHeaderBSI(1);
|
||||
$thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5); // we already know this from pre-parsing the version identifier, but re-read it to let the bitstream flow as intended
|
||||
$thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5);
|
||||
$thisfile_ac3_raw_bsi['flags']['compr'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['compr']) {
|
||||
$thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] == 0) { // if 1+1 mode (dual mono, so some items need a second value)
|
||||
$thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5);
|
||||
$thisfile_ac3_raw_bsi['flags']['compr2'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['compr2']) {
|
||||
$thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8);
|
||||
}
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['strmtyp'] == 1) { // if dependent stream
|
||||
$thisfile_ac3_raw_bsi['flags']['chanmap'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['chanmap']) {
|
||||
$thisfile_ac3_raw_bsi['chanmap'] = $this->readHeaderBSI(8);
|
||||
}
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['mixmdat'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['mixmdat']) { // Mixing metadata
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] > 2) { // if more than 2 channels
|
||||
$thisfile_ac3_raw_bsi['dmixmod'] = $this->readHeaderBSI(2);
|
||||
}
|
||||
if (($thisfile_ac3_raw_bsi['acmod'] & 0x01) && ($thisfile_ac3_raw_bsi['acmod'] > 2)) { // if three front channels exist
|
||||
$thisfile_ac3_raw_bsi['ltrtcmixlev'] = $this->readHeaderBSI(3);
|
||||
$thisfile_ac3_raw_bsi['lorocmixlev'] = $this->readHeaderBSI(3);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) { // if a surround channel exists
|
||||
$thisfile_ac3_raw_bsi['ltrtsurmixlev'] = $this->readHeaderBSI(3);
|
||||
$thisfile_ac3_raw_bsi['lorosurmixlev'] = $this->readHeaderBSI(3);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['flags']['lfeon']) { // if the LFE channel exists
|
||||
$thisfile_ac3_raw_bsi['flags']['lfemixlevcod'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['lfemixlevcod']) {
|
||||
$thisfile_ac3_raw_bsi['lfemixlevcod'] = $this->readHeaderBSI(5);
|
||||
}
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['strmtyp'] == 0) { // if independent stream
|
||||
$thisfile_ac3_raw_bsi['flags']['pgmscl'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['pgmscl']) {
|
||||
$thisfile_ac3_raw_bsi['pgmscl'] = $this->readHeaderBSI(6);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] == 0) { // if 1+1 mode (dual mono, so some items need a second value)
|
||||
$thisfile_ac3_raw_bsi['flags']['pgmscl2'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['pgmscl2']) {
|
||||
$thisfile_ac3_raw_bsi['pgmscl2'] = $this->readHeaderBSI(6);
|
||||
}
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmscl'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmscl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmscl'] = $this->readHeaderBSI(6);
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['mixdef'] = $this->readHeaderBSI(2);
|
||||
if ($thisfile_ac3_raw_bsi['mixdef'] == 1) { // mixing option 2
|
||||
$thisfile_ac3_raw_bsi['premixcmpsel'] = (bool) $this->readHeaderBSI(1);
|
||||
$thisfile_ac3_raw_bsi['drcsrc'] = (bool) $this->readHeaderBSI(1);
|
||||
$thisfile_ac3_raw_bsi['premixcmpscl'] = $this->readHeaderBSI(3);
|
||||
} elseif ($thisfile_ac3_raw_bsi['mixdef'] == 2) { // mixing option 3
|
||||
$thisfile_ac3_raw_bsi['mixdata'] = $this->readHeaderBSI(12);
|
||||
} elseif ($thisfile_ac3_raw_bsi['mixdef'] == 3) { // mixing option 4
|
||||
$mixdefbitsread = 0;
|
||||
$thisfile_ac3_raw_bsi['mixdeflen'] = $this->readHeaderBSI(5); $mixdefbitsread += 5;
|
||||
$thisfile_ac3_raw_bsi['flags']['mixdata2'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['mixdata2']) {
|
||||
$thisfile_ac3_raw_bsi['premixcmpsel'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
$thisfile_ac3_raw_bsi['drcsrc'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
$thisfile_ac3_raw_bsi['premixcmpscl'] = $this->readHeaderBSI(3); $mixdefbitsread += 3;
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmlscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmlscl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmlscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmcscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmcscl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmcscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmrscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmrscl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmrscl'] = $this->readHeaderBSI(4);
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmlsscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmlsscl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmlsscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmrsscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmrsscl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmrsscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmlfescl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmlfescl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmlfescl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['dmixscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['dmixscl']) {
|
||||
$thisfile_ac3_raw_bsi['dmixscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['addch'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['addch']) {
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmaux1scl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmaux1scl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmaux1scl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['extpgmaux2scl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['extpgmaux2scl']) {
|
||||
$thisfile_ac3_raw_bsi['extpgmaux2scl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['mixdata3'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['mixdata3']) {
|
||||
$thisfile_ac3_raw_bsi['spchdat'] = $this->readHeaderBSI(5); $mixdefbitsread += 5;
|
||||
$thisfile_ac3_raw_bsi['flags']['addspchdat'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['addspchdat']) {
|
||||
$thisfile_ac3_raw_bsi['spchdat1'] = $this->readHeaderBSI(5); $mixdefbitsread += 5;
|
||||
$thisfile_ac3_raw_bsi['spchan1att'] = $this->readHeaderBSI(2); $mixdefbitsread += 2;
|
||||
$thisfile_ac3_raw_bsi['flags']['addspchdat1'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1;
|
||||
if ($thisfile_ac3_raw_bsi['flags']['addspchdat1']) {
|
||||
$thisfile_ac3_raw_bsi['spchdat2'] = $this->readHeaderBSI(5); $mixdefbitsread += 5;
|
||||
$thisfile_ac3_raw_bsi['spchan2att'] = $this->readHeaderBSI(3); $mixdefbitsread += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
$mixdata_bits = (8 * ($thisfile_ac3_raw_bsi['mixdeflen'] + 2)) - $mixdefbitsread;
|
||||
$mixdata_fill = (($mixdata_bits % 8) ? 8 - ($mixdata_bits % 8) : 0);
|
||||
$thisfile_ac3_raw_bsi['mixdata'] = $this->readHeaderBSI($mixdata_bits);
|
||||
$thisfile_ac3_raw_bsi['mixdatafill'] = $this->readHeaderBSI($mixdata_fill);
|
||||
unset($mixdefbitsread, $mixdata_bits, $mixdata_fill);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] < 2) { // if mono or dual mono source
|
||||
$thisfile_ac3_raw_bsi['flags']['paninfo'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['paninfo']) {
|
||||
$thisfile_ac3_raw_bsi['panmean'] = $this->readHeaderBSI(8);
|
||||
$thisfile_ac3_raw_bsi['paninfo'] = $this->readHeaderBSI(6);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] == 0) { // if 1+1 mode (dual mono, so some items need a second value)
|
||||
$thisfile_ac3_raw_bsi['flags']['paninfo2'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['paninfo2']) {
|
||||
$thisfile_ac3_raw_bsi['panmean2'] = $this->readHeaderBSI(8);
|
||||
$thisfile_ac3_raw_bsi['paninfo2'] = $this->readHeaderBSI(6);
|
||||
}
|
||||
}
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['frmmixcfginfo'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['frmmixcfginfo']) { // mixing configuration information
|
||||
if ($thisfile_ac3_raw_bsi['numblkscod'] == 0) {
|
||||
$thisfile_ac3_raw_bsi['blkmixcfginfo'][0] = $this->readHeaderBSI(5);
|
||||
} else {
|
||||
for ($blk = 0; $blk < $thisfile_ac3_raw_bsi['numblkscod']; $blk++) {
|
||||
$thisfile_ac3_raw_bsi['flags']['blkmixcfginfo'.$blk] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['blkmixcfginfo'.$blk]) { // mixing configuration information
|
||||
$thisfile_ac3_raw_bsi['blkmixcfginfo'][$blk] = $this->readHeaderBSI(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['infomdat'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['infomdat']) { // Informational metadata
|
||||
$thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3);
|
||||
$thisfile_ac3_raw_bsi['flags']['copyrightb'] = (bool) $this->readHeaderBSI(1);
|
||||
$thisfile_ac3_raw_bsi['flags']['origbs'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] == 2) { // if in 2/0 mode
|
||||
$thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3_raw_bsi['dheadphonmod'] = $this->readHeaderBSI(2);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] >= 6) { // if both surround channels exist
|
||||
$thisfile_ac3_raw_bsi['dsurexmod'] = $this->readHeaderBSI(2);
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['audprodi'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['audprodi']) {
|
||||
$thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5);
|
||||
$thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3_raw_bsi['flags']['adconvtyp'] = (bool) $this->readHeaderBSI(1);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] == 0) { // if 1+1 mode (dual mono, so some items need a second value)
|
||||
$thisfile_ac3_raw_bsi['flags']['audprodi2'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['audprodi2']) {
|
||||
$thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5);
|
||||
$thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3_raw_bsi['flags']['adconvtyp2'] = (bool) $this->readHeaderBSI(1);
|
||||
}
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['fscod'] < 3) { // if not half sample rate
|
||||
$thisfile_ac3_raw_bsi['flags']['sourcefscod'] = (bool) $this->readHeaderBSI(1);
|
||||
}
|
||||
}
|
||||
if (($thisfile_ac3_raw_bsi['strmtyp'] == 0) && ($thisfile_ac3_raw_bsi['numblkscod'] != 3)) { // if both surround channels exist
|
||||
$thisfile_ac3_raw_bsi['flags']['convsync'] = (bool) $this->readHeaderBSI(1);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['strmtyp'] == 2) { // if bit stream converted from AC-3
|
||||
if ($thisfile_ac3_raw_bsi['numblkscod'] != 3) { // 6 blocks per syncframe
|
||||
$thisfile_ac3_raw_bsi['flags']['blkid'] = 1;
|
||||
} else {
|
||||
$thisfile_ac3_raw_bsi['flags']['blkid'] = (bool) $this->readHeaderBSI(1);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['flags']['blkid']) {
|
||||
$thisfile_ac3_raw_bsi['frmsizecod'] = $this->readHeaderBSI(6);
|
||||
}
|
||||
}
|
||||
$thisfile_ac3_raw_bsi['flags']['addbsi'] = (bool) $this->readHeaderBSI(1);
|
||||
if ($thisfile_ac3_raw_bsi['flags']['addbsi']) {
|
||||
$thisfile_ac3_raw_bsi['addbsil'] = $this->readHeaderBSI(6);
|
||||
$thisfile_ac3_raw_bsi['addbsi'] = $this->readHeaderBSI(($thisfile_ac3_raw_bsi['addbsil'] + 1) * 8);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$this->error('Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 16. Please submit a support ticket with a sample file.');
|
||||
unset($info['ac3']);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
if (isset($thisfile_ac3_raw_bsi['fscod2'])) {
|
||||
$thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup2($thisfile_ac3_raw_bsi['fscod2']);
|
||||
} else {
|
||||
$thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup($thisfile_ac3_raw_bsi['fscod']);
|
||||
}
|
||||
if ($thisfile_ac3_raw_bsi['fscod'] <= 3) {
|
||||
$info['audio']['sample_rate'] = $thisfile_ac3['sample_rate'];
|
||||
} else {
|
||||
$this->warning('Unexpected ac3.bsi.fscod value: '.$thisfile_ac3_raw_bsi['fscod']);
|
||||
}
|
||||
if (isset($thisfile_ac3_raw_bsi['frmsizecod'])) {
|
||||
$thisfile_ac3['frame_length'] = self::frameSizeLookup($thisfile_ac3_raw_bsi['frmsizecod'], $thisfile_ac3_raw_bsi['fscod']);
|
||||
$thisfile_ac3['bitrate'] = self::bitrateLookup($thisfile_ac3_raw_bsi['frmsizecod']);
|
||||
} elseif (!empty($thisfile_ac3_raw_bsi['frmsiz'])) {
|
||||
// this isn't right, but it's (usually) close, roughly 5% less than it should be.
|
||||
// but WHERE is the actual bitrate value stored in EAC3?? email info@getid3.org if you know!
|
||||
$thisfile_ac3['bitrate'] = ($thisfile_ac3_raw_bsi['frmsiz'] + 1) * 16 * 30; // The frmsiz field shall contain a value one less than the overall size of the coded syncframe in 16-bit words. That is, this field may assume a value ranging from 0 to 2047, and these values correspond to syncframe sizes ranging from 1 to 2048.
|
||||
// kludge-fix to make it approximately the expected value, still not "right":
|
||||
$thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16000;
|
||||
}
|
||||
$info['audio']['bitrate'] = $thisfile_ac3['bitrate'];
|
||||
|
||||
$thisfile_ac3['service_type'] = self::serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']);
|
||||
$ac3_coding_mode = self::audioCodingModeLookup($thisfile_ac3_raw_bsi['acmod']);
|
||||
foreach($ac3_coding_mode as $key => $value) {
|
||||
|
@ -124,138 +459,46 @@ class getid3_ac3 extends getid3_handler
|
|||
}
|
||||
$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'] = self::centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']);
|
||||
}
|
||||
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) {
|
||||
// If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream.
|
||||
$thisfile_ac3_raw_bsi['surmixlev'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3['surround_mix_level'] = self::surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']);
|
||||
}
|
||||
|
||||
if ($thisfile_ac3_raw_bsi['acmod'] == 0x02) {
|
||||
// When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround.
|
||||
$thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2);
|
||||
$thisfile_ac3['dolby_surround_mode'] = self::dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']);
|
||||
}
|
||||
|
||||
$thisfile_ac3_raw_bsi['lfeon'] = (bool) $this->readHeaderBSI(1);
|
||||
$thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['lfeon'];
|
||||
if ($thisfile_ac3_raw_bsi['lfeon']) {
|
||||
//$info['audio']['channels']++;
|
||||
$thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['flags']['lfeon'];
|
||||
if ($thisfile_ac3_raw_bsi['flags']['lfeon']) {
|
||||
$info['audio']['channels'] .= '.1';
|
||||
}
|
||||
|
||||
$thisfile_ac3['channels_enabled'] = self::channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['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['channels_enabled'] = self::channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['flags']['lfeon']);
|
||||
$thisfile_ac3['dialogue_normalization'] = '-'.$thisfile_ac3_raw_bsi['dialnorm'].'dB';
|
||||
|
||||
$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'] = self::heavyCompression($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'] = self::roomTypeLookup($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'] = self::heavyCompression($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'] = self::roomTypeLookup($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($this->fread($thisfile_ac3_raw_bsi['addbsi_length']));
|
||||
|
||||
$thisfile_ac3_raw_bsi['addbsi_data'] = substr($this->AC3header['bsi'], $this->BSIoffset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8);
|
||||
$this->BSIoffset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function readHeaderBSI($length)
|
||||
{
|
||||
private function readHeaderBSI($length) {
|
||||
$data = substr($this->AC3header['bsi'], $this->BSIoffset, $length);
|
||||
$this->BSIoffset += $length;
|
||||
|
||||
return bindec($data);
|
||||
}
|
||||
|
||||
public static function sampleRateCodeLookup($fscod)
|
||||
{
|
||||
static $sampleRateCodeLookup = [
|
||||
public static function sampleRateCodeLookup($fscod) {
|
||||
static $sampleRateCodeLookup = array(
|
||||
0 => 48000,
|
||||
1 => 44100,
|
||||
2 => 32000,
|
||||
3 => 'reserved' // If the reserved code is indicated, the decoder should not attempt to decode audio and should mute.
|
||||
];
|
||||
);
|
||||
return (isset($sampleRateCodeLookup[$fscod]) ? $sampleRateCodeLookup[$fscod] : false);
|
||||
}
|
||||
|
||||
public static function serviceTypeLookup($bsmod, $acmod)
|
||||
{
|
||||
static $serviceTypeLookup = [];
|
||||
public static function sampleRateCodeLookup2($fscod2) {
|
||||
static $sampleRateCodeLookup2 = array(
|
||||
0 => 24000,
|
||||
1 => 22050,
|
||||
2 => 16000,
|
||||
3 => 'reserved' // If the reserved code is indicated, the decoder should not attempt to decode audio and should mute.
|
||||
);
|
||||
return (isset($sampleRateCodeLookup2[$fscod2]) ? $sampleRateCodeLookup2[$fscod2] : false);
|
||||
}
|
||||
|
||||
public static function serviceTypeLookup($bsmod, $acmod) {
|
||||
static $serviceTypeLookup = array();
|
||||
if (empty($serviceTypeLookup)) {
|
||||
for ($i = 0; $i <= 7; $i++) {
|
||||
$serviceTypeLookup[0][$i] = 'main audio service: complete main (CM)';
|
||||
|
@ -275,64 +518,59 @@ class getid3_ac3 extends getid3_handler
|
|||
return (isset($serviceTypeLookup[$bsmod][$acmod]) ? $serviceTypeLookup[$bsmod][$acmod] : false);
|
||||
}
|
||||
|
||||
public static function audioCodingModeLookup($acmod)
|
||||
{
|
||||
public static function audioCodingModeLookup($acmod) {
|
||||
// array(channel configuration, # channels (not incl LFE), channel order)
|
||||
static $audioCodingModeLookup = [
|
||||
0 => ['channel_config'=>'1+1', 'num_channels'=>2, 'channel_order'=>'Ch1,Ch2'],
|
||||
1 => ['channel_config'=>'1/0', 'num_channels'=>1, 'channel_order'=>'C'],
|
||||
2 => ['channel_config'=>'2/0', 'num_channels'=>2, 'channel_order'=>'L,R'],
|
||||
3 => ['channel_config'=>'3/0', 'num_channels'=>3, 'channel_order'=>'L,C,R'],
|
||||
4 => ['channel_config'=>'2/1', 'num_channels'=>3, 'channel_order'=>'L,R,S'],
|
||||
5 => ['channel_config'=>'3/1', 'num_channels'=>4, 'channel_order'=>'L,C,R,S'],
|
||||
6 => ['channel_config'=>'2/2', 'num_channels'=>4, 'channel_order'=>'L,R,SL,SR'],
|
||||
7 => ['channel_config'=>'3/2', 'num_channels'=>5, 'channel_order'=>'L,C,R,SL,SR'],
|
||||
];
|
||||
static $audioCodingModeLookup = array (
|
||||
0 => array('channel_config'=>'1+1', 'num_channels'=>2, 'channel_order'=>'Ch1,Ch2'),
|
||||
1 => array('channel_config'=>'1/0', 'num_channels'=>1, 'channel_order'=>'C'),
|
||||
2 => array('channel_config'=>'2/0', 'num_channels'=>2, 'channel_order'=>'L,R'),
|
||||
3 => array('channel_config'=>'3/0', 'num_channels'=>3, 'channel_order'=>'L,C,R'),
|
||||
4 => array('channel_config'=>'2/1', 'num_channels'=>3, 'channel_order'=>'L,R,S'),
|
||||
5 => array('channel_config'=>'3/1', 'num_channels'=>4, 'channel_order'=>'L,C,R,S'),
|
||||
6 => array('channel_config'=>'2/2', 'num_channels'=>4, 'channel_order'=>'L,R,SL,SR'),
|
||||
7 => array('channel_config'=>'3/2', 'num_channels'=>5, 'channel_order'=>'L,C,R,SL,SR'),
|
||||
);
|
||||
return (isset($audioCodingModeLookup[$acmod]) ? $audioCodingModeLookup[$acmod] : false);
|
||||
}
|
||||
|
||||
public static function centerMixLevelLookup($cmixlev)
|
||||
{
|
||||
public static function centerMixLevelLookup($cmixlev) {
|
||||
static $centerMixLevelLookup;
|
||||
if (empty($centerMixLevelLookup)) {
|
||||
$centerMixLevelLookup = [
|
||||
$centerMixLevelLookup = array(
|
||||
0 => pow(2, -3.0 / 6), // 0.707 (-3.0 dB)
|
||||
1 => pow(2, -4.5 / 6), // 0.595 (-4.5 dB)
|
||||
2 => pow(2, -6.0 / 6), // 0.500 (-6.0 dB)
|
||||
3 => 'reserved'
|
||||
];
|
||||
);
|
||||
}
|
||||
return (isset($centerMixLevelLookup[$cmixlev]) ? $centerMixLevelLookup[$cmixlev] : false);
|
||||
}
|
||||
|
||||
public static function surroundMixLevelLookup($surmixlev)
|
||||
{
|
||||
public static function surroundMixLevelLookup($surmixlev) {
|
||||
static $surroundMixLevelLookup;
|
||||
if (empty($surroundMixLevelLookup)) {
|
||||
$surroundMixLevelLookup = [
|
||||
$surroundMixLevelLookup = array(
|
||||
0 => pow(2, -3.0 / 6),
|
||||
1 => pow(2, -6.0 / 6),
|
||||
2 => 0,
|
||||
3 => 'reserved'
|
||||
];
|
||||
);
|
||||
}
|
||||
return (isset($surroundMixLevelLookup[$surmixlev]) ? $surroundMixLevelLookup[$surmixlev] : false);
|
||||
}
|
||||
|
||||
public static function dolbySurroundModeLookup($dsurmod)
|
||||
{
|
||||
static $dolbySurroundModeLookup = [
|
||||
public static function dolbySurroundModeLookup($dsurmod) {
|
||||
static $dolbySurroundModeLookup = array(
|
||||
0 => 'not indicated',
|
||||
1 => 'Not Dolby Surround encoded',
|
||||
2 => 'Dolby Surround encoded',
|
||||
3 => 'reserved'
|
||||
];
|
||||
);
|
||||
return (isset($dolbySurroundModeLookup[$dsurmod]) ? $dolbySurroundModeLookup[$dsurmod] : false);
|
||||
}
|
||||
|
||||
public static function channelsEnabledLookup($acmod, $lfeon)
|
||||
{
|
||||
$lookup = [
|
||||
public static function channelsEnabledLookup($acmod, $lfeon) {
|
||||
$lookup = array(
|
||||
'ch1'=>(bool) ($acmod == 0),
|
||||
'ch2'=>(bool) ($acmod == 0),
|
||||
'left'=>(bool) ($acmod > 1),
|
||||
|
@ -341,7 +579,7 @@ class getid3_ac3 extends getid3_handler
|
|||
'surround_mono'=>false,
|
||||
'surround_left'=>false,
|
||||
'surround_right'=>false,
|
||||
'lfe'=>$lfeon];
|
||||
'lfe'=>$lfeon);
|
||||
switch ($acmod) {
|
||||
case 4:
|
||||
case 5:
|
||||
|
@ -356,8 +594,7 @@ class getid3_ac3 extends getid3_handler
|
|||
return $lookup;
|
||||
}
|
||||
|
||||
public static function heavyCompression($compre)
|
||||
{
|
||||
public static function heavyCompression($compre) {
|
||||
// The first four bits indicate gain changes in 6.02dB increments which can be
|
||||
// implemented with an arithmetic shift operation. The following four bits
|
||||
// indicate linear gain changes, and require a 5-bit multiply.
|
||||
|
@ -407,45 +644,44 @@ class getid3_ac3 extends getid3_handler
|
|||
return $log_gain - $lin_gain;
|
||||
}
|
||||
|
||||
public static function roomTypeLookup($roomtyp)
|
||||
{
|
||||
static $roomTypeLookup = [
|
||||
public static function roomTypeLookup($roomtyp) {
|
||||
static $roomTypeLookup = array(
|
||||
0 => 'not indicated',
|
||||
1 => 'large room, X curve monitor',
|
||||
2 => 'small room, flat monitor',
|
||||
3 => 'reserved'
|
||||
];
|
||||
);
|
||||
return (isset($roomTypeLookup[$roomtyp]) ? $roomTypeLookup[$roomtyp] : false);
|
||||
}
|
||||
|
||||
public static function frameSizeLookup($frmsizecod, $fscod)
|
||||
{
|
||||
$padding = (bool) ($frmsizecod % 2);
|
||||
$framesizeid = floor($frmsizecod / 2);
|
||||
public static function frameSizeLookup($frmsizecod, $fscod) {
|
||||
// LSB is whether padding is used or not
|
||||
$padding = (bool) ($frmsizecod & 0x01);
|
||||
$framesizeid = ($frmsizecod & 0x3E) >> 1;
|
||||
|
||||
static $frameSizeLookup = [];
|
||||
static $frameSizeLookup = array();
|
||||
if (empty($frameSizeLookup)) {
|
||||
$frameSizeLookup = [
|
||||
0 => [128, 138, 192],
|
||||
1 => [40, 160, 174, 240],
|
||||
2 => [48, 192, 208, 288],
|
||||
3 => [56, 224, 242, 336],
|
||||
4 => [64, 256, 278, 384],
|
||||
5 => [80, 320, 348, 480],
|
||||
6 => [96, 384, 416, 576],
|
||||
7 => [112, 448, 486, 672],
|
||||
8 => [128, 512, 556, 768],
|
||||
9 => [160, 640, 696, 960],
|
||||
10 => [192, 768, 834, 1152],
|
||||
11 => [224, 896, 974, 1344],
|
||||
12 => [256, 1024, 1114, 1536],
|
||||
13 => [320, 1280, 1392, 1920],
|
||||
14 => [384, 1536, 1670, 2304],
|
||||
15 => [448, 1792, 1950, 2688],
|
||||
16 => [512, 2048, 2228, 3072],
|
||||
17 => [576, 2304, 2506, 3456],
|
||||
18 => [640, 2560, 2786, 3840]
|
||||
];
|
||||
$frameSizeLookup = array (
|
||||
0 => array( 128, 138, 192), // 32 kbps
|
||||
1 => array( 160, 174, 240), // 40 kbps
|
||||
2 => array( 192, 208, 288), // 48 kbps
|
||||
3 => array( 224, 242, 336), // 56 kbps
|
||||
4 => array( 256, 278, 384), // 64 kbps
|
||||
5 => array( 320, 348, 480), // 80 kbps
|
||||
6 => array( 384, 416, 576), // 96 kbps
|
||||
7 => array( 448, 486, 672), // 112 kbps
|
||||
8 => array( 512, 556, 768), // 128 kbps
|
||||
9 => array( 640, 696, 960), // 160 kbps
|
||||
10 => array( 768, 834, 1152), // 192 kbps
|
||||
11 => array( 896, 974, 1344), // 224 kbps
|
||||
12 => array(1024, 1114, 1536), // 256 kbps
|
||||
13 => array(1280, 1392, 1920), // 320 kbps
|
||||
14 => array(1536, 1670, 2304), // 384 kbps
|
||||
15 => array(1792, 1950, 2688), // 448 kbps
|
||||
16 => array(2048, 2228, 3072), // 512 kbps
|
||||
17 => array(2304, 2506, 3456), // 576 kbps
|
||||
18 => array(2560, 2786, 3840) // 640 kbps
|
||||
);
|
||||
}
|
||||
if (($fscod == 1) && $padding) {
|
||||
// frame lengths are padded by 1 word (16 bits) at 44100
|
||||
|
@ -454,11 +690,12 @@ class getid3_ac3 extends getid3_handler
|
|||
return (isset($frameSizeLookup[$framesizeid][$fscod]) ? $frameSizeLookup[$framesizeid][$fscod] : false);
|
||||
}
|
||||
|
||||
public static function bitrateLookup($frmsizecod)
|
||||
{
|
||||
$framesizeid = floor($frmsizecod / 2);
|
||||
public static function bitrateLookup($frmsizecod) {
|
||||
// LSB is whether padding is used or not
|
||||
$padding = (bool) ($frmsizecod & 0x01);
|
||||
$framesizeid = ($frmsizecod & 0x3E) >> 1;
|
||||
|
||||
static $bitrateLookup = [
|
||||
static $bitrateLookup = array(
|
||||
0 => 32000,
|
||||
1 => 40000,
|
||||
2 => 48000,
|
||||
|
@ -477,8 +714,20 @@ class getid3_ac3 extends getid3_handler
|
|||
15 => 448000,
|
||||
16 => 512000,
|
||||
17 => 576000,
|
||||
18 => 640000
|
||||
];
|
||||
18 => 640000,
|
||||
);
|
||||
return (isset($bitrateLookup[$framesizeid]) ? $bitrateLookup[$framesizeid] : false);
|
||||
}
|
||||
|
||||
public static function blocksPerSyncFrame($numblkscod) {
|
||||
static $blocksPerSyncFrameLookup = array(
|
||||
0 => 1,
|
||||
1 => 2,
|
||||
2 => 3,
|
||||
3 => 6,
|
||||
);
|
||||
return (isset($blocksPerSyncFrameLookup[$numblkscod]) ? $blocksPerSyncFrameLookup[$numblkscod] : false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
class getid3_amr extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
@ -27,12 +26,12 @@ class getid3_amr extends getid3_handler
|
|||
|
||||
$magic = '#!AMR'."\x0A";
|
||||
if (substr($AMRheader, 0, 6) != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AMRheader, 0, 6)).'"';
|
||||
$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AMRheader, 0, 6)).'"');
|
||||
return false;
|
||||
}
|
||||
|
||||
// shortcut
|
||||
$info['amr'] = [];
|
||||
$info['amr'] = array();
|
||||
$thisfile_amr = &$info['amr'];
|
||||
|
||||
$info['fileformat'] = 'amr';
|
||||
|
@ -41,7 +40,7 @@ class getid3_amr extends getid3_handler
|
|||
$info['audio']['bits_per_sample'] = 13; // http://en.wikipedia.org/wiki/Adaptive_Multi-Rate_audio_codec: "Sampling frequency 8 kHz/13-bit (160 samples for 20 ms frames), filtered to 200–3400 Hz"
|
||||
$info['audio']['sample_rate'] = 8000; // http://en.wikipedia.org/wiki/Adaptive_Multi-Rate_audio_codec: "Sampling frequency 8 kHz/13-bit (160 samples for 20 ms frames), filtered to 200–3400 Hz"
|
||||
$info['audio']['channels'] = 1;
|
||||
$thisfile_amr['frame_mode_count'] = [0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0, 6=>0, 7=>0];
|
||||
$thisfile_amr['frame_mode_count'] = array(0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0, 6=>0, 7=>0);
|
||||
|
||||
$buffer = '';
|
||||
do {
|
||||
|
@ -51,7 +50,6 @@ class getid3_amr extends getid3_handler
|
|||
$AMR_frame_header = ord(substr($buffer, 0, 1));
|
||||
$codec_mode_request = ($AMR_frame_header & 0x78) >> 3; // The 2nd bit through 5th bit (counting the most significant bit as the first bit) comprise the CMR (Codec Mode Request), values 0-7 being valid for AMR. The top bit of the CMR can actually be ignored, though it is used when AMR forms RTP payloads. The lower 3-bits of the header are reserved and are not used. Viewing the header from most significant bit to least significant bit, the encoding is XCCCCXXX, where Xs are reserved (typically 0) and the Cs are the CMR.
|
||||
if ($codec_mode_request > 7) {
|
||||
$info['error'][] = '';
|
||||
break;
|
||||
}
|
||||
$thisfile_amr['frame_mode_count'][$codec_mode_request]++;
|
||||
|
@ -66,9 +64,8 @@ class getid3_amr extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function amr_mode_bitrate($key)
|
||||
{
|
||||
static $amr_mode_bitrate = [
|
||||
public function amr_mode_bitrate($key) {
|
||||
static $amr_mode_bitrate = array(
|
||||
0 => 4750,
|
||||
1 => 5150,
|
||||
2 => 5900,
|
||||
|
@ -77,13 +74,12 @@ class getid3_amr extends getid3_handler
|
|||
5 => 7950,
|
||||
6 => 10200,
|
||||
7 => 12200,
|
||||
];
|
||||
);
|
||||
return (isset($amr_mode_bitrate[$key]) ? $amr_mode_bitrate[$key] : false);
|
||||
}
|
||||
|
||||
public function amr_mode_bytes_per_frame($key)
|
||||
{
|
||||
static $amr_mode_bitrate = [
|
||||
public function amr_mode_bytes_per_frame($key) {
|
||||
static $amr_mode_bitrate = array(
|
||||
0 => 13, // 1-byte frame header + 95 bits [padded to: 12 bytes] audio data
|
||||
1 => 14, // 1-byte frame header + 103 bits [padded to: 13 bytes] audio data
|
||||
2 => 16, // 1-byte frame header + 118 bits [padded to: 15 bytes] audio data
|
||||
|
@ -92,7 +88,9 @@ class getid3_amr extends getid3_handler
|
|||
5 => 21, // 1-byte frame header + 159 bits [padded to: 20 bytes] audio data
|
||||
6 => 27, // 1-byte frame header + 204 bits [padded to: 26 bytes] audio data
|
||||
7 => 32, // 1-byte frame header + 244 bits [padded to: 31 bytes] audio data
|
||||
];
|
||||
);
|
||||
return (isset($amr_mode_bitrate[$key]) ? $amr_mode_bitrate[$key] : false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
class getid3_au extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
@ -27,12 +26,12 @@ class getid3_au extends getid3_handler
|
|||
|
||||
$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)).'"';
|
||||
$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" (".snd") at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AUheader, 0, 4)).'"');
|
||||
return false;
|
||||
}
|
||||
|
||||
// shortcut
|
||||
$info['au'] = [];
|
||||
$info['au'] = array();
|
||||
$thisfile_au = &$info['au'];
|
||||
|
||||
$info['fileformat'] = 'au';
|
||||
|
@ -62,7 +61,7 @@ class getid3_au extends getid3_handler
|
|||
$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"';
|
||||
$this->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));
|
||||
|
@ -71,9 +70,8 @@ class getid3_au extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function AUdataFormatNameLookup($id)
|
||||
{
|
||||
static $AUdataFormatNameLookup = [
|
||||
public function AUdataFormatNameLookup($id) {
|
||||
static $AUdataFormatNameLookup = array(
|
||||
0 => 'unspecified format',
|
||||
1 => '8-bit mu-law',
|
||||
2 => '8-bit linear',
|
||||
|
@ -102,13 +100,12 @@ class getid3_au extends getid3_handler
|
|||
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);
|
||||
}
|
||||
|
||||
public function AUdataFormatBitsPerSampleLookup($id)
|
||||
{
|
||||
static $AUdataFormatBitsPerSampleLookup = [
|
||||
public function AUdataFormatBitsPerSampleLookup($id) {
|
||||
static $AUdataFormatBitsPerSampleLookup = array(
|
||||
1 => 8,
|
||||
2 => 8,
|
||||
3 => 16,
|
||||
|
@ -131,13 +128,12 @@ class getid3_au extends getid3_handler
|
|||
25 => 16,
|
||||
26 => 16,
|
||||
27 => 8
|
||||
];
|
||||
);
|
||||
return (isset($AUdataFormatBitsPerSampleLookup[$id]) ? $AUdataFormatBitsPerSampleLookup[$id] : false);
|
||||
}
|
||||
|
||||
public function AUdataFormatUsedBitsPerSampleLookup($id)
|
||||
{
|
||||
static $AUdataFormatUsedBitsPerSampleLookup = [
|
||||
public function AUdataFormatUsedBitsPerSampleLookup($id) {
|
||||
static $AUdataFormatUsedBitsPerSampleLookup = array(
|
||||
1 => 8,
|
||||
2 => 8,
|
||||
3 => 16,
|
||||
|
@ -160,7 +156,8 @@ class getid3_au extends getid3_handler
|
|||
25 => 3,
|
||||
26 => 5,
|
||||
27 => 8,
|
||||
];
|
||||
);
|
||||
return (isset($AUdataFormatUsedBitsPerSampleLookup[$id]) ? $AUdataFormatUsedBitsPerSampleLookup[$id] : false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
class getid3_avr extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// http://cui.unige.ch/OSG/info/AudioFormats/ap11.html
|
||||
|
@ -70,7 +69,7 @@ class getid3_avr extends getid3_handler
|
|||
$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']).'"';
|
||||
$this->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;
|
||||
|
@ -98,7 +97,7 @@ class getid3_avr extends getid3_handler
|
|||
$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'] = [];
|
||||
$info['avr']['midi_notes'] = array();
|
||||
if (($info['avr']['raw']['midi'] & 0xFF00) != 0xFF00) {
|
||||
$info['avr']['midi_notes'][] = ($info['avr']['raw']['midi'] & 0xFF00) >> 8;
|
||||
}
|
||||
|
@ -107,7 +106,7 @@ class getid3_avr extends getid3_handler
|
|||
}
|
||||
|
||||
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']);
|
||||
$this->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';
|
||||
|
@ -122,4 +121,5 @@ class getid3_avr extends getid3_handler
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,20 +17,22 @@
|
|||
|
||||
class getid3_bonk extends getid3_handler
|
||||
{
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// shortcut
|
||||
$info['bonk'] = [];
|
||||
$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';
|
||||
|
||||
$this->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
|
||||
$this->fseek($thisfile_bonk['dataend'] - 8);
|
||||
$PossibleBonkTag = $this->fread(8);
|
||||
|
@ -40,7 +42,7 @@ class getid3_bonk extends getid3_handler
|
|||
$BonkTagOffset = $this->ftell();
|
||||
$TagHeaderTest = $this->fread(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).'"';
|
||||
$this->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);
|
||||
|
@ -58,6 +60,7 @@ class getid3_bonk extends getid3_handler
|
|||
$this->fseek($NextTagEndOffset);
|
||||
$PossibleBonkTag = $this->fread(8);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// seek-from-beginning method for v0.4 and v0.5
|
||||
|
@ -83,6 +86,7 @@ class getid3_bonk extends getid3_handler
|
|||
$thisfile_bonk[$BonkTagName]['size'] = $thisfile_bonk['dataend'] - $thisfile_bonk['dataoffset'];
|
||||
$thisfile_bonk[$BonkTagName]['offset'] = $thisfile_bonk['dataoffset'];
|
||||
$this->HandleBonkTags($BonkTagName);
|
||||
|
||||
} while (true);
|
||||
}
|
||||
|
||||
|
@ -107,10 +111,10 @@ class getid3_bonk extends getid3_handler
|
|||
unset($info['bonk']);
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function HandleBonkTags($BonkTagName)
|
||||
{
|
||||
public function HandleBonkTags($BonkTagName) {
|
||||
$info = &$this->getid3->info;
|
||||
switch ($BonkTagName) {
|
||||
case 'BONK':
|
||||
|
@ -203,14 +207,14 @@ class getid3_bonk extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unexpected Bonk tag "'.$BonkTagName.'" at offset '.$info['bonk'][$BonkTagName]['offset'];
|
||||
$this->warning('Unexpected Bonk tag "'.$BonkTagName.'" at offset '.$info['bonk'][$BonkTagName]['offset']);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static function BonkIsValidTagName($PossibleBonkTag, $ignorecase = false)
|
||||
{
|
||||
static $BonkIsValidTagName = ['BONK', 'INFO', ' ID3', 'META'];
|
||||
public static function BonkIsValidTagName($PossibleBonkTag, $ignorecase=false) {
|
||||
static $BonkIsValidTagName = array('BONK', 'INFO', ' ID3', 'META');
|
||||
foreach ($BonkIsValidTagName as $validtagname) {
|
||||
if ($validtagname == $PossibleBonkTag) {
|
||||
return true;
|
||||
|
@ -220,4 +224,5 @@ class getid3_bonk extends getid3_handler
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
133
app/Library/getid3/getid3/module.audio.dsf.php
Normal file
133
app/Library/getid3/getid3/module.audio.dsf.php
Normal file
|
@ -0,0 +1,133 @@
|
|||
<?php
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/// getID3() by James Heinrich <info@getid3.org> //
|
||||
// available at http://getid3.sourceforge.net //
|
||||
// or http://www.getid3.org //
|
||||
// also https://github.com/JamesHeinrich/getID3 //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// See readme.txt for more details //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// module.audio.dsf.php //
|
||||
// module for analyzing dsf/DSF Audio files //
|
||||
// dependencies: module.tag.id3v2.php //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
|
||||
|
||||
class getid3_dsf extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'dsf';
|
||||
$info['audio']['dataformat'] = 'dsf';
|
||||
$info['audio']['lossless'] = true;
|
||||
$info['audio']['bitrate_mode'] = 'cbr';
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$dsfheader = $this->fread(28 + 12);
|
||||
|
||||
$headeroffset = 0;
|
||||
$info['dsf']['dsd']['magic'] = substr($dsfheader, $headeroffset, 4);
|
||||
$headeroffset += 4;
|
||||
$magic = 'DSD ';
|
||||
if ($info['dsf']['dsd']['magic'] != $magic) {
|
||||
$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['dsf']['dsd']['magic']).'"');
|
||||
unset($info['fileformat']);
|
||||
unset($info['audio']);
|
||||
unset($info['dsf']);
|
||||
return false;
|
||||
}
|
||||
$info['dsf']['dsd']['dsd_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); // should be 28
|
||||
$headeroffset += 8;
|
||||
$info['dsf']['dsd']['dsf_file_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
|
||||
$headeroffset += 8;
|
||||
$info['dsf']['dsd']['meta_chunk_offset'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
|
||||
$headeroffset += 8;
|
||||
|
||||
|
||||
$info['dsf']['fmt']['magic'] = substr($dsfheader, $headeroffset, 4);
|
||||
$headeroffset += 4;
|
||||
$magic = 'fmt ';
|
||||
if ($info['dsf']['fmt']['magic'] != $magic) {
|
||||
$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$headeroffset.', found "'.getid3_lib::PrintHexBytes($info['dsf']['fmt']['magic']).'"');
|
||||
return false;
|
||||
}
|
||||
$info['dsf']['fmt']['fmt_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); // usually 52 bytes
|
||||
$headeroffset += 8;
|
||||
$dsfheader .= $this->fread($info['dsf']['fmt']['fmt_chunk_size'] - 12 + 12); // we have already read the entire DSD chunk, plus 12 bytes of FMT. We now want to read the size of FMT, plus 12 bytes into the next chunk to get magic and size.
|
||||
if (strlen($dsfheader) != ($info['dsf']['dsd']['dsd_chunk_size'] + $info['dsf']['fmt']['fmt_chunk_size'] + 12)) {
|
||||
$this->error('Expecting '.($info['dsf']['dsd']['dsd_chunk_size'] + $info['dsf']['fmt']['fmt_chunk_size']).' bytes header, found '.strlen($dsfheader).' bytes');
|
||||
return false;
|
||||
}
|
||||
$info['dsf']['fmt']['format_version'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // usually "1"
|
||||
$headeroffset += 4;
|
||||
$info['dsf']['fmt']['format_id'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // usually "0" = "DSD Raw"
|
||||
$headeroffset += 4;
|
||||
$info['dsf']['fmt']['channel_type_id'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
|
||||
$headeroffset += 4;
|
||||
$info['dsf']['fmt']['channels'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
|
||||
$headeroffset += 4;
|
||||
$info['dsf']['fmt']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
|
||||
$headeroffset += 4;
|
||||
$info['dsf']['fmt']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
|
||||
$headeroffset += 4;
|
||||
$info['dsf']['fmt']['sample_count'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
|
||||
$headeroffset += 8;
|
||||
$info['dsf']['fmt']['channel_block_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
|
||||
$headeroffset += 4;
|
||||
$info['dsf']['fmt']['reserved'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // zero-filled
|
||||
$headeroffset += 4;
|
||||
|
||||
|
||||
$info['dsf']['data']['magic'] = substr($dsfheader, $headeroffset, 4);
|
||||
$headeroffset += 4;
|
||||
$magic = 'data';
|
||||
if ($info['dsf']['data']['magic'] != $magic) {
|
||||
$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$headeroffset.', found "'.getid3_lib::PrintHexBytes($info['dsf']['data']['magic']).'"');
|
||||
return false;
|
||||
}
|
||||
$info['dsf']['data']['data_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
|
||||
$headeroffset += 8;
|
||||
$info['avdataoffset'] = $headeroffset;
|
||||
$info['avdataend'] = $info['avdataoffset'] + $info['dsf']['data']['data_chunk_size'];
|
||||
|
||||
|
||||
if ($info['dsf']['dsd']['meta_chunk_offset'] > 0) {
|
||||
$getid3_id3v2 = new getid3_id3v2($this->getid3);
|
||||
$getid3_id3v2->StartingOffset = $info['dsf']['dsd']['meta_chunk_offset'];
|
||||
$getid3_id3v2->Analyze();
|
||||
unset($getid3_id3v2);
|
||||
}
|
||||
|
||||
|
||||
$info['dsf']['fmt']['channel_type'] = $this->DSFchannelTypeLookup($info['dsf']['fmt']['channel_type_id']);
|
||||
$info['audio']['channelmode'] = $info['dsf']['fmt']['channel_type'];
|
||||
$info['audio']['bits_per_sample'] = $info['dsf']['fmt']['bits_per_sample'];
|
||||
$info['audio']['sample_rate'] = $info['dsf']['fmt']['sample_rate'];
|
||||
$info['audio']['channels'] = $info['dsf']['fmt']['channels'];
|
||||
$info['audio']['bitrate'] = $info['audio']['bits_per_sample'] * $info['audio']['sample_rate'] * $info['audio']['channels'];
|
||||
$info['playtime_seconds'] = ($info['dsf']['data']['data_chunk_size'] * 8) / $info['audio']['bitrate'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static function DSFchannelTypeLookup($channel_type_id) {
|
||||
static $DSFchannelTypeLookup = array(
|
||||
// interleaving order:
|
||||
1 => 'mono', // 1: Mono
|
||||
2 => 'stereo', // 1: Front-Left; 2: Front-Right
|
||||
3 => '3-channel', // 1: Front-Left; 2: Front-Right; 3: Center
|
||||
4 => 'quad', // 1: Front-Left; 2: Front-Right; 3: Back-Left; 4: Back-Right
|
||||
5 => '4-channel', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Low-Frequency
|
||||
6 => '5-channel', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Back-Left 5: Back-Right
|
||||
7 => '5.1', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Low-Frequency; 5: Back-Left; 6: Back-Right
|
||||
);
|
||||
return (isset($DSFchannelTypeLookup[$channel_type_id]) ? $DSFchannelTypeLookup[$channel_type_id] : '');
|
||||
}
|
||||
|
||||
}
|
|
@ -18,21 +18,20 @@
|
|||
class getid3_dss extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$DSSheader = $this->fread(1540);
|
||||
|
||||
if (!preg_match('#^(\x02|\x03)ds[s2]#', $DSSheader)) {
|
||||
$info['error'][] = 'Expecting "[02-03] 64 73 [73|32]" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($DSSheader, 0, 4)).'"';
|
||||
if (!preg_match('#^[\\x02-\\x06]ds[s2]#', $DSSheader)) {
|
||||
$this->error('Expecting "[02-06] 64 73 [73|32]" 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
|
||||
$info['encoding'] = 'ISO-8859-1'; // not certain, but assumed
|
||||
$info['dss'] = [];
|
||||
$info['dss'] = array();
|
||||
|
||||
$info['fileformat'] = 'dss';
|
||||
$info['mime_type'] = 'audio/x-'.substr($DSSheader, 1, 3); // "audio/x-dss" or "audio/x-ds2"
|
||||
|
@ -43,31 +42,36 @@ class getid3_dss extends getid3_handler
|
|||
$info['dss']['hardware'] = trim(substr($DSSheader, 12, 16)); // identification string for hardware used to create the file, e.g. "DPM 9600", "DS2400"
|
||||
$info['dss']['unknown1'] = getid3_lib::LittleEndian2Int(substr($DSSheader, 28, 4));
|
||||
// 32-37 = "FE FF FE FF F7 FF" in all the sample files I've seen
|
||||
$info['dss']['date_create'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 38, 12));
|
||||
$info['dss']['date_complete'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 50, 12));
|
||||
$info['dss']['date_create_unix'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 38, 12));
|
||||
$info['dss']['date_complete_unix'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 50, 12));
|
||||
$info['dss']['playtime_sec'] = intval((substr($DSSheader, 62, 2) * 3600) + (substr($DSSheader, 64, 2) * 60) + substr($DSSheader, 66, 2)); // approximate file playtime in HHMMSS
|
||||
if ($info['dss']['version'] <= 3) {
|
||||
$info['dss']['playtime_ms'] = getid3_lib::LittleEndian2Int(substr($DSSheader, 512, 4)); // exact file playtime in milliseconds. Has also been observed at offset 530 in one sample file, with something else (unknown) at offset 512
|
||||
$info['dss']['priority'] = ord(substr($DSSheader, 793, 1));
|
||||
$info['dss']['comments'] = trim(substr($DSSheader, 798, 100));
|
||||
$info['dss']['sample_rate_index'] = ord(substr($DSSheader, 1538, 1)); // this isn't certain, this may or may not be where the sample rate info is stored, but it seems consistent on my small selection of sample files
|
||||
$info['audio']['sample_rate'] = $this->DSSsampleRateLookup($info['dss']['sample_rate_index']);
|
||||
} else {
|
||||
$this->getid3->warning('DSS above version 3 not fully supported in this version of getID3. Any additional documentation or format specifications would be welcome. This file is version '.$info['dss']['version']);
|
||||
}
|
||||
|
||||
$info['audio']['bits_per_sample'] = 16; // maybe, maybe not -- most compressed audio formats don't have a fixed bits-per-sample value, but this is a reasonable approximation
|
||||
$info['audio']['sample_rate'] = $this->DSSsampleRateLookup($info['dss']['sample_rate_index']);
|
||||
$info['audio']['channels'] = 1;
|
||||
|
||||
if (!empty($info['dss']['playtime_ms']) && (floor($info['dss']['playtime_ms'] / 1000) == $info['dss']['playtime_sec'])) { // *should* just be playtime_ms / 1000 but at least one sample file has playtime_ms at offset 530 instead of offset 512, so safety check
|
||||
$info['playtime_seconds'] = $info['dss']['playtime_ms'] / 1000;
|
||||
if (floor($info['dss']['playtime_ms'] / 1000) != $info['dss']['playtime_sec']) {
|
||||
// *should* just be playtime_ms / 1000 but at least one sample file has playtime_ms at offset 530 instead of offset 512, so safety check
|
||||
} else {
|
||||
$info['playtime_seconds'] = $info['dss']['playtime_sec'];
|
||||
if (!empty($info['dss']['playtime_ms'])) {
|
||||
$this->getid3->warning('playtime_ms ('.number_format($info['dss']['playtime_ms'] / 1000, 3).') does not match playtime_sec ('.number_format($info['dss']['playtime_sec']).') - using playtime_sec value');
|
||||
}
|
||||
}
|
||||
$info['audio']['bitrate'] = ($info['filesize'] * 8) / $info['playtime_seconds'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function DSSdateStringToUnixDate($datestring)
|
||||
{
|
||||
public function DSSdateStringToUnixDate($datestring) {
|
||||
$y = substr($datestring, 0, 2);
|
||||
$m = substr($datestring, 2, 2);
|
||||
$d = substr($datestring, 4, 2);
|
||||
|
@ -78,18 +82,18 @@ class getid3_dss extends getid3_handler
|
|||
return mktime($h, $i, $s, $m, $d, $y);
|
||||
}
|
||||
|
||||
public function DSSsampleRateLookup($sample_rate_index)
|
||||
{
|
||||
static $dssSampleRateLookup = [
|
||||
public function DSSsampleRateLookup($sample_rate_index) {
|
||||
static $dssSampleRateLookup = array(
|
||||
0x0A => 16000,
|
||||
0x0C => 11025,
|
||||
0x0D => 12000,
|
||||
0x15 => 8000,
|
||||
];
|
||||
);
|
||||
if (!array_key_exists($sample_rate_index, $dssSampleRateLookup)) {
|
||||
$this->getid3->warning('unknown sample_rate_index: '.$sample_rate_index);
|
||||
$this->getid3->warning('unknown sample_rate_index: 0x'.strtoupper(dechex($sample_rate_index)));
|
||||
return false;
|
||||
}
|
||||
return $dssSampleRateLookup[$sample_rate_index];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,14 +30,13 @@ class getid3_dts extends getid3_handler
|
|||
/**
|
||||
* Possible syncwords indicating bitstream encoding
|
||||
*/
|
||||
public static $syncwords = [
|
||||
public static $syncwords = array(
|
||||
0 => "\x7F\xFE\x80\x01", // raw big-endian
|
||||
1 => "\xFE\x7F\x01\x80", // raw little-endian
|
||||
2 => "\x1F\xFF\xE8\x00", // 14-bit big-endian
|
||||
3 => "\xFF\x1F\x00\xE8"]; // 14-bit little-endian
|
||||
3 => "\xFF\x1F\x00\xE8"); // 14-bit little-endian
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
$info['fileformat'] = 'dts';
|
||||
|
||||
|
@ -47,15 +46,21 @@ class getid3_dts extends getid3_handler
|
|||
// check syncword
|
||||
$sync = substr($DTSheader, 0, 4);
|
||||
if (($encoding = array_search($sync, self::$syncwords)) !== false) {
|
||||
|
||||
$info['dts']['raw']['magic'] = $sync;
|
||||
$this->readBinDataOffset = 32;
|
||||
|
||||
} elseif ($this->isDependencyFor('matroska')) {
|
||||
|
||||
// Matroska contains DTS without syncword encoded as raw big-endian format
|
||||
$encoding = 0;
|
||||
$this->readBinDataOffset = 0;
|
||||
|
||||
} else {
|
||||
|
||||
unset($info['fileformat']);
|
||||
return $this->error('Expecting "'.implode('| ', array_map('getid3_lib::PrintHexBytes', self::$syncwords)).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($sync).'"');
|
||||
|
||||
}
|
||||
|
||||
// decode header
|
||||
|
@ -134,17 +139,15 @@ class getid3_dts extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
private function readBinData($bin, $length)
|
||||
{
|
||||
private function readBinData($bin, $length) {
|
||||
$data = substr($bin, $this->readBinDataOffset, $length);
|
||||
$this->readBinDataOffset += $length;
|
||||
|
||||
return bindec($data);
|
||||
}
|
||||
|
||||
public static function bitrateLookup($index)
|
||||
{
|
||||
static $lookup = [
|
||||
public static function bitrateLookup($index) {
|
||||
static $lookup = array(
|
||||
0 => 32000,
|
||||
1 => 56000,
|
||||
2 => 64000,
|
||||
|
@ -177,13 +180,12 @@ class getid3_dts extends getid3_handler
|
|||
29 => 'open',
|
||||
30 => 'variable',
|
||||
31 => 'lossless',
|
||||
];
|
||||
);
|
||||
return (isset($lookup[$index]) ? $lookup[$index] : false);
|
||||
}
|
||||
|
||||
public static function sampleRateLookup($index)
|
||||
{
|
||||
static $lookup = [
|
||||
public static function sampleRateLookup($index) {
|
||||
static $lookup = array(
|
||||
0 => 'invalid',
|
||||
1 => 8000,
|
||||
2 => 16000,
|
||||
|
@ -200,23 +202,21 @@ class getid3_dts extends getid3_handler
|
|||
13 => 48000,
|
||||
14 => 'invalid',
|
||||
15 => 'invalid',
|
||||
];
|
||||
);
|
||||
return (isset($lookup[$index]) ? $lookup[$index] : false);
|
||||
}
|
||||
|
||||
public static function bitPerSampleLookup($index)
|
||||
{
|
||||
static $lookup = [
|
||||
public static function bitPerSampleLookup($index) {
|
||||
static $lookup = array(
|
||||
0 => 16,
|
||||
1 => 20,
|
||||
2 => 24,
|
||||
3 => 24,
|
||||
];
|
||||
);
|
||||
return (isset($lookup[$index]) ? $lookup[$index] : false);
|
||||
}
|
||||
|
||||
public static function numChannelsLookup($index)
|
||||
{
|
||||
public static function numChannelsLookup($index) {
|
||||
switch ($index) {
|
||||
case 0:
|
||||
return 1;
|
||||
|
@ -254,9 +254,8 @@ class getid3_dts extends getid3_handler
|
|||
return false;
|
||||
}
|
||||
|
||||
public static function channelArrangementLookup($index)
|
||||
{
|
||||
static $lookup = [
|
||||
public static function channelArrangementLookup($index) {
|
||||
static $lookup = array(
|
||||
0 => 'A',
|
||||
1 => 'A + B (dual mono)',
|
||||
2 => 'L + R (stereo)',
|
||||
|
@ -273,12 +272,11 @@ class getid3_dts extends getid3_handler
|
|||
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($lookup[$index]) ? $lookup[$index] : 'user-defined');
|
||||
}
|
||||
|
||||
public static function dialogNormalization($index, $version)
|
||||
{
|
||||
public static function dialogNormalization($index, $version) {
|
||||
switch ($version) {
|
||||
case 7:
|
||||
return 0 - $index;
|
||||
|
@ -289,4 +287,5 @@ class getid3_dts extends getid3_handler
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,8 +24,7 @@ class getid3_flac extends getid3_handler
|
|||
{
|
||||
const syncword = 'fLaC';
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
@ -42,8 +41,7 @@ class getid3_flac extends getid3_handler
|
|||
return $this->parseMETAdata();
|
||||
}
|
||||
|
||||
public function parseMETAdata()
|
||||
{
|
||||
public function parseMETAdata() {
|
||||
$info = &$this->getid3->info;
|
||||
do {
|
||||
$BlockOffset = $this->ftell();
|
||||
|
@ -63,7 +61,7 @@ class getid3_flac extends getid3_handler
|
|||
break;
|
||||
}
|
||||
|
||||
$info['flac'][$BlockTypeText]['raw'] = [];
|
||||
$info['flac'][$BlockTypeText]['raw'] = array();
|
||||
$BlockTypeText_raw = &$info['flac'][$BlockTypeText]['raw'];
|
||||
|
||||
$BlockTypeText_raw['offset'] = $BlockOffset;
|
||||
|
@ -122,7 +120,8 @@ class getid3_flac extends getid3_handler
|
|||
|
||||
unset($info['flac'][$BlockTypeText]['raw']);
|
||||
$info['avdataoffset'] = $this->ftell();
|
||||
} while ($LastBlockFlag === false);
|
||||
}
|
||||
while ($LastBlockFlag === false);
|
||||
|
||||
// handle tags
|
||||
if (!empty($info['flac']['VORBIS_COMMENT']['comments'])) {
|
||||
|
@ -137,10 +136,10 @@ class getid3_flac extends getid3_handler
|
|||
foreach ($info['flac']['PICTURE'] as $entry) {
|
||||
if (!empty($entry['data'])) {
|
||||
if (!isset($info['flac']['comments']['picture'])) {
|
||||
$info['flac']['comments']['picture'] = [];
|
||||
$info['flac']['comments']['picture'] = array();
|
||||
}
|
||||
$comments_picture_data = [];
|
||||
foreach (['data', 'image_mime', 'image_width', 'image_height', 'imagetype', 'picturetype', 'description', 'datalength'] as $picture_key) {
|
||||
$comments_picture_data = array();
|
||||
foreach (array('data', 'image_mime', 'image_width', 'image_height', 'imagetype', 'picturetype', 'description', 'datalength') as $picture_key) {
|
||||
if (isset($entry[$picture_key])) {
|
||||
$comments_picture_data[$picture_key] = $entry[$picture_key];
|
||||
}
|
||||
|
@ -166,9 +165,11 @@ class getid3_flac extends getid3_handler
|
|||
|
||||
// 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)) {
|
||||
$this->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)');
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$info['md5_data_source'] = '';
|
||||
$md5 = $info['flac']['STREAMINFO']['audio_signature'];
|
||||
for ($i = 0; $i < strlen($md5); $i++) {
|
||||
|
@ -193,11 +194,10 @@ class getid3_flac extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
private function parseSTREAMINFO($BlockData)
|
||||
{
|
||||
private function parseSTREAMINFO($BlockData) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['flac']['STREAMINFO'] = [];
|
||||
$info['flac']['STREAMINFO'] = array();
|
||||
$streaminfo = &$info['flac']['STREAMINFO'];
|
||||
|
||||
$streaminfo['min_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 0, 2));
|
||||
|
@ -214,6 +214,7 @@ class getid3_flac extends getid3_handler
|
|||
$streaminfo['audio_signature'] = substr($BlockData, 18, 16);
|
||||
|
||||
if (!empty($streaminfo['sample_rate'])) {
|
||||
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
$info['audio']['sample_rate'] = $streaminfo['sample_rate'];
|
||||
$info['audio']['channels'] = $streaminfo['channels'];
|
||||
|
@ -222,10 +223,12 @@ class getid3_flac extends getid3_handler
|
|||
if ($info['playtime_seconds'] > 0) {
|
||||
if (!$this->isDependencyFor('matroska')) {
|
||||
$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$this->warning('Cannot determine audio bitrate because total stream size is unknown');
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
return $this->error('Corrupt METAdata block: STREAMINFO');
|
||||
}
|
||||
|
@ -233,8 +236,7 @@ class getid3_flac extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
private function parseAPPLICATION($BlockData)
|
||||
{
|
||||
private function parseAPPLICATION($BlockData) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$ApplicationID = getid3_lib::BigEndian2Int(substr($BlockData, 0, 4));
|
||||
|
@ -244,8 +246,7 @@ class getid3_flac extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
private function parseSEEKTABLE($BlockData)
|
||||
{
|
||||
private function parseSEEKTABLE($BlockData) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$offset = 0;
|
||||
|
@ -255,23 +256,26 @@ class getid3_flac extends getid3_handler
|
|||
$SampleNumberString = substr($BlockData, $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($BlockData, $offset, 8));
|
||||
$offset += 8;
|
||||
$info['flac']['SEEKTABLE'][$SampleNumber]['samples'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 2));
|
||||
$offset += 2;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function parseVORBIS_COMMENT($BlockData)
|
||||
{
|
||||
private function parseVORBIS_COMMENT($BlockData) {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$getid3_ogg = new getid3_ogg($this->getid3);
|
||||
|
@ -290,8 +294,7 @@ class getid3_flac extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
private function parseCUESHEET($BlockData)
|
||||
{
|
||||
private function parseCUESHEET($BlockData) {
|
||||
$info = &$this->getid3->info;
|
||||
$offset = 0;
|
||||
$info['flac']['CUESHEET']['media_catalog_number'] = trim(substr($BlockData, $offset, 128), "\0");
|
||||
|
@ -346,8 +349,7 @@ class getid3_flac extends getid3_handler
|
|||
* Parse METADATA_BLOCK_PICTURE flac structure and extract attachment
|
||||
* External usage: audio.ogg
|
||||
*/
|
||||
public function parsePICTURE()
|
||||
{
|
||||
public function parsePICTURE() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$picture['typeid'] = getid3_lib::BigEndian2Int($this->fread(4));
|
||||
|
@ -370,8 +372,7 @@ class getid3_flac extends getid3_handler
|
|||
str_replace('/', '_', $picture['picturetype']).'_'.$this->ftell(),
|
||||
$this->ftell(),
|
||||
$picture['datalength'],
|
||||
$picture['image_mime']
|
||||
);
|
||||
$picture['image_mime']);
|
||||
}
|
||||
|
||||
$info['flac']['PICTURE'][] = $picture;
|
||||
|
@ -379,9 +380,8 @@ class getid3_flac extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public static function metaBlockTypeLookup($blocktype)
|
||||
{
|
||||
static $lookup = [
|
||||
public static function metaBlockTypeLookup($blocktype) {
|
||||
static $lookup = array(
|
||||
0 => 'STREAMINFO',
|
||||
1 => 'PADDING',
|
||||
2 => 'APPLICATION',
|
||||
|
@ -389,14 +389,13 @@ class getid3_flac extends getid3_handler
|
|||
4 => 'VORBIS_COMMENT',
|
||||
5 => 'CUESHEET',
|
||||
6 => 'PICTURE',
|
||||
];
|
||||
);
|
||||
return (isset($lookup[$blocktype]) ? $lookup[$blocktype] : 'reserved');
|
||||
}
|
||||
|
||||
public static function applicationIDLookup($applicationid)
|
||||
{
|
||||
public static function applicationIDLookup($applicationid) {
|
||||
// http://flac.sourceforge.net/id.html
|
||||
static $lookup = [
|
||||
static $lookup = array(
|
||||
0x41544348 => 'FlacFile', // "ATCH"
|
||||
0x42534F4C => 'beSolo', // "BSOL"
|
||||
0x42554753 => 'Bugs Player', // "BUGS"
|
||||
|
@ -420,13 +419,12 @@ class getid3_flac extends getid3_handler
|
|||
0x74756E65 => 'TagTuner', // "tune"
|
||||
0x78626174 => 'XBAT', // "xbat"
|
||||
0x786D6364 => 'xmcd', // "xmcd"
|
||||
];
|
||||
);
|
||||
return (isset($lookup[$applicationid]) ? $lookup[$applicationid] : 'reserved');
|
||||
}
|
||||
|
||||
public static function pictureTypeLookup($type_id)
|
||||
{
|
||||
static $lookup = [
|
||||
public static function pictureTypeLookup($type_id) {
|
||||
static $lookup = array (
|
||||
0 => 'Other',
|
||||
1 => '32x32 pixels \'file icon\' (PNG only)',
|
||||
2 => 'Other file icon',
|
||||
|
@ -448,7 +446,8 @@ class getid3_flac extends getid3_handler
|
|||
18 => 'Illustration',
|
||||
19 => 'Band/artist logotype',
|
||||
20 => 'Publisher/Studio logotype',
|
||||
];
|
||||
);
|
||||
return (isset($lookup[$type_id]) ? $lookup[$type_id] : 'reserved');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,8 +19,7 @@ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php',
|
|||
class getid3_la extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$offset = 0;
|
||||
|
@ -43,30 +42,34 @@ class getid3_la extends getid3_handler
|
|||
$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';
|
||||
$this->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.';
|
||||
$this->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.';
|
||||
$this->error('Expected "fmt " ('.getid3_lib::PrintHexBytes('fmt ').') at offset '.$offset.', found "'.$fmt_chunk.'" ('.getid3_lib::PrintHexBytes($fmt_chunk).') instead.');
|
||||
return false;
|
||||
}
|
||||
$offset += 4;
|
||||
|
@ -79,14 +82,14 @@ class getid3_la extends getid3_handler
|
|||
$info['la']['channels'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2));
|
||||
$offset += 2;
|
||||
if ($info['la']['channels'] == 0) {
|
||||
$info['error'][] = 'Corrupt LA file: channels == zero';
|
||||
$this->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';
|
||||
$this->error('Corrupt LA file: sample_rate == zero');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -135,6 +138,7 @@ class getid3_la extends getid3_handler
|
|||
}
|
||||
|
||||
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.
|
||||
|
@ -142,12 +146,15 @@ class getid3_la extends getid3_handler
|
|||
$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'].')';
|
||||
$this->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']) {
|
||||
|
@ -175,7 +182,7 @@ class getid3_la extends getid3_handler
|
|||
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']);
|
||||
$this->warning('Error parsing RIFF portion of La file: '.implode($getid3_temp->info['error']));
|
||||
}
|
||||
unset($getid3_temp, $getid3_riff);
|
||||
}
|
||||
|
@ -190,7 +197,7 @@ class getid3_la extends getid3_handler
|
|||
$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';
|
||||
$this->error('Corrupt LA file: playtime_seconds == zero');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -201,9 +208,9 @@ class getid3_la extends getid3_handler
|
|||
|
||||
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.';
|
||||
$this->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';
|
||||
$this->error('Not a LA (Lossless-Audio) file');
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
|
@ -215,4 +222,5 @@ class getid3_la extends getid3_handler
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,14 +19,13 @@ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php',
|
|||
class getid3_lpac extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$LPACheader = $this->fread(14);
|
||||
if (substr($LPACheader, 0, 4) != 'LPAC') {
|
||||
$info['error'][] = 'Expected "LPAC" at offset '.$info['avdataoffset'].', found "'.$StreamMarker.'"';
|
||||
$this->error('Expected "LPAC" at offset '.$info['avdataoffset'].', found "'.$StreamMarker.'"');
|
||||
return false;
|
||||
}
|
||||
$info['avdataoffset'] += 14;
|
||||
|
@ -47,7 +46,7 @@ class getid3_lpac extends getid3_handler
|
|||
$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';
|
||||
$this->warning('24-bit and 16-bit flags cannot both be set');
|
||||
}
|
||||
|
||||
$info['lpac']['flags']['fast_compress'] = (bool) ($flags['parameters'] & 0x40000000);
|
||||
|
@ -60,20 +59,20 @@ class getid3_lpac extends getid3_handler
|
|||
$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'].'"';
|
||||
$this->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';
|
||||
$this->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'];
|
||||
$this->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';
|
||||
//$this->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;
|
||||
}
|
||||
|
||||
|
@ -125,4 +124,5 @@ class getid3_lpac extends getid3_handler
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,12 +21,11 @@ class getid3_midi extends getid3_handler
|
|||
{
|
||||
public $scanwholefile = true;
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// shortcut
|
||||
$info['midi']['raw'] = [];
|
||||
$info['midi']['raw'] = array();
|
||||
$thisfile_midi = &$info['midi'];
|
||||
$thisfile_midi_raw = &$thisfile_midi['raw'];
|
||||
|
||||
|
@ -38,7 +37,7 @@ class getid3_midi extends getid3_handler
|
|||
$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).'"';
|
||||
$this->error('Expecting "'.getid3_lib::PrintHexBytes(GETID3_MIDI_MAGIC_MTHD).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($MIDIheaderID).'"');
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
|
@ -57,8 +56,8 @@ class getid3_midi extends getid3_handler
|
|||
if ($buffer = $this->fread($this->getid3->fread_buffer_size())) {
|
||||
$MIDIdata .= $buffer;
|
||||
} else {
|
||||
$info['warning'][] = 'only processed '.($i - 1).' of '.$thisfile_midi_raw['tracks'].' tracks';
|
||||
$info['error'][] = 'Unabled to read more file data at '.$this->ftell().' (trying to seek to : '.$offset.'), was expecting at least 8 more bytes';
|
||||
$this->warning('only processed '.($i - 1).' of '.$thisfile_midi_raw['tracks'].' tracks');
|
||||
$this->error('Unabled to read more file data at '.$this->ftell().' (trying to seek to : '.$offset.'), was expecting at least 8 more bytes');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -71,13 +70,13 @@ class getid3_midi extends getid3_handler
|
|||
$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';
|
||||
$this->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';
|
||||
$this->error('Cannot find MIDI track information');
|
||||
unset($thisfile_midi);
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
|
@ -88,9 +87,10 @@ class getid3_midi extends getid3_handler
|
|||
$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 = [];
|
||||
$MicroSecondsPerQuarterNoteAfter = array ();
|
||||
|
||||
foreach ($trackdataarray as $tracknumber => $trackdata) {
|
||||
|
||||
$eventsoffset = 0;
|
||||
$LastIssuedMIDIcommand = 0;
|
||||
$LastIssuedMIDIchannel = 0;
|
||||
|
@ -129,18 +129,22 @@ class getid3_midi extends getid3_handler
|
|||
|
||||
$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));
|
||||
|
@ -151,15 +155,19 @@ class getid3_midi extends getid3_handler
|
|||
} 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);
|
||||
|
@ -218,7 +226,7 @@ class getid3_midi extends getid3_handler
|
|||
case 0x51: // Tempo: microseconds / quarter note
|
||||
$CurrentMicroSecondsPerBeat = getid3_lib::BigEndian2Int(substr($METAeventData, 0, $METAeventLength));
|
||||
if ($CurrentMicroSecondsPerBeat == 0) {
|
||||
$info['error'][] = 'Corrupt MIDI file: CurrentMicroSecondsPerBeat == zero';
|
||||
$this->error('Corrupt MIDI file: CurrentMicroSecondsPerBeat == zero');
|
||||
return false;
|
||||
}
|
||||
$thisfile_midi_raw['events'][$tracknumber][$CumulativeDeltaTime]['us_qnote'] = $CurrentMicroSecondsPerBeat;
|
||||
|
@ -246,7 +254,7 @@ class getid3_midi extends getid3_handler
|
|||
}
|
||||
|
||||
$keysig_majorminor = getid3_lib::BigEndian2Int($METAeventData{1}); // 0 -> major, 1 -> minor
|
||||
$keysigs = [-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#'];
|
||||
$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;
|
||||
|
@ -261,11 +269,14 @@ class getid3_midi extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unhandled META Event Command: '.$METAeventCommand;
|
||||
$this->warning('Unhandled META Event Command: '.$METAeventCommand);
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
$info['warning'][] = 'Unhandled MIDI Event ID: '.$MIDIevents[$tracknumber][$eventid]['eventid'].' + Channel ID: '.$MIDIevents[$tracknumber][$eventid]['channel'];
|
||||
|
||||
$this->warning('Unhandled MIDI Event ID: '.$MIDIevents[$tracknumber][$eventid]['eventid'].' + Channel ID: '.$MIDIevents[$tracknumber][$eventid]['channel']);
|
||||
|
||||
}
|
||||
}
|
||||
if (($tracknumber > 0) || (count($trackdataarray) == 1)) {
|
||||
|
@ -282,8 +293,9 @@ class getid3_midi extends getid3_handler
|
|||
continue;
|
||||
}
|
||||
if ($thisfile_midi['totalticks'] > $tickoffset) {
|
||||
|
||||
if ($thisfile_midi_raw['ticksperqnote'] == 0) {
|
||||
$info['error'][] = 'Corrupt MIDI file: ticksperqnote == zero';
|
||||
$this->error('Corrupt MIDI file: ticksperqnote == zero');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -294,12 +306,14 @@ class getid3_midi extends getid3_handler
|
|||
}
|
||||
}
|
||||
if ($thisfile_midi['totalticks'] > $previoustickoffset) {
|
||||
|
||||
if ($thisfile_midi_raw['ticksperqnote'] == 0) {
|
||||
$info['error'][] = 'Corrupt MIDI file: ticksperqnote == zero';
|
||||
$this->error('Corrupt MIDI file: ticksperqnote == zero');
|
||||
return false;
|
||||
}
|
||||
|
||||
$info['playtime_seconds'] += (($thisfile_midi['totalticks'] - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote']) * ($microsecondsperbeat / 1000000);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -315,8 +329,7 @@ class getid3_midi extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function GeneralMIDIinstrumentLookup($instrumentid)
|
||||
{
|
||||
public function GeneralMIDIinstrumentLookup($instrumentid) {
|
||||
|
||||
$begin = __LINE__;
|
||||
|
||||
|
@ -456,8 +469,7 @@ class getid3_midi extends getid3_handler
|
|||
return getid3_lib::EmbeddedLookup($instrumentid, $begin, __LINE__, __FILE__, 'GeneralMIDIinstrument');
|
||||
}
|
||||
|
||||
public function GeneralMIDIpercussionLookup($instrumentid)
|
||||
{
|
||||
public function GeneralMIDIpercussionLookup($instrumentid) {
|
||||
|
||||
$begin = __LINE__;
|
||||
|
||||
|
@ -514,4 +526,5 @@ class getid3_midi extends getid3_handler
|
|||
|
||||
return getid3_lib::EmbeddedLookup($instrumentid, $begin, __LINE__, __FILE__, 'GeneralMIDIpercussion');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
class getid3_mod extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$fileheader = $this->fread(1088);
|
||||
|
@ -32,72 +31,69 @@ class getid3_mod extends getid3_handler
|
|||
} 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';
|
||||
$this->error('This is not a known type of MOD file');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public function getMODheaderFilepointer()
|
||||
{
|
||||
public function getMODheaderFilepointer() {
|
||||
$info = &$this->getid3->info;
|
||||
$this->fseek($info['avdataoffset'] + 1080);
|
||||
$FormatID = $this->fread(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';
|
||||
$this->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().']';
|
||||
$this->error('MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getXMheaderFilepointer()
|
||||
{
|
||||
public function getXMheaderFilepointer() {
|
||||
$info = &$this->getid3->info;
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$FormatID = $this->fread(15);
|
||||
if (!preg_match('#^Extended Module$#', $FormatID)) {
|
||||
$info['error'][] = 'This is not a known type of XM-MOD file';
|
||||
$this->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().']';
|
||||
$this->error('XM-MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getS3MheaderFilepointer()
|
||||
{
|
||||
public function getS3MheaderFilepointer() {
|
||||
$info = &$this->getid3->info;
|
||||
$this->fseek($info['avdataoffset'] + 44);
|
||||
$FormatID = $this->fread(4);
|
||||
if (!preg_match('#^SCRM$#', $FormatID)) {
|
||||
$info['error'][] = 'This is not a ScreamTracker MOD file';
|
||||
$this->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().']';
|
||||
$this->error('ScreamTracker parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getITheaderFilepointer()
|
||||
{
|
||||
public function getITheaderFilepointer() {
|
||||
$info = &$this->getid3->info;
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$FormatID = $this->fread(4);
|
||||
if (!preg_match('#^IMPM$#', $FormatID)) {
|
||||
$info['error'][] = 'This is not an ImpulseTracker MOD file';
|
||||
$this->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().']';
|
||||
$this->error('ImpulseTracker parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
class getid3_monkey extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// based loosely on code from TMonkey by Jurgen Faul <jfaulØgmx*de>
|
||||
|
@ -30,7 +29,7 @@ class getid3_monkey extends getid3_handler
|
|||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
$info['audio']['lossless'] = true;
|
||||
|
||||
$info['monkeys_audio']['raw'] = [];
|
||||
$info['monkeys_audio']['raw'] = array();
|
||||
$thisfile_monkeysaudio = &$info['monkeys_audio'];
|
||||
$thisfile_monkeysaudio_raw = &$thisfile_monkeysaudio['raw'];
|
||||
|
||||
|
@ -40,7 +39,7 @@ class getid3_monkey extends getid3_handler
|
|||
$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']).'"';
|
||||
$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_monkeysaudio_raw['magic']).'"');
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
|
@ -113,7 +112,7 @@ class getid3_monkey extends getid3_handler
|
|||
$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';
|
||||
$this->error('Corrupt MAC file: frequency == zero');
|
||||
return false;
|
||||
}
|
||||
$info['audio']['sample_rate'] = $thisfile_monkeysaudio['sample_rate'];
|
||||
|
@ -128,14 +127,14 @@ class getid3_monkey extends getid3_handler
|
|||
}
|
||||
$thisfile_monkeysaudio['playtime'] = $thisfile_monkeysaudio['samples'] / $thisfile_monkeysaudio['sample_rate'];
|
||||
if ($thisfile_monkeysaudio['playtime'] == 0) {
|
||||
$info['error'][] = 'Corrupt MAC file: playtime == zero';
|
||||
$this->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';
|
||||
$this->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']);
|
||||
|
@ -156,7 +155,7 @@ class getid3_monkey extends getid3_handler
|
|||
|
||||
if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) {
|
||||
if ($thisfile_monkeysaudio_raw['cFileMD5'] === str_repeat("\x00", 16)) {
|
||||
//$info['warning'][] = 'cFileMD5 is null';
|
||||
//$this->warning('cFileMD5 is null');
|
||||
} else {
|
||||
$info['md5_data_source'] = '';
|
||||
$md5 = $thisfile_monkeysaudio_raw['cFileMD5'];
|
||||
|
@ -178,21 +177,19 @@ class getid3_monkey extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function MonkeyCompressionLevelNameLookup($compressionlevel)
|
||||
{
|
||||
static $MonkeyCompressionLevelNameLookup = [
|
||||
public 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');
|
||||
}
|
||||
|
||||
public function MonkeySamplesPerFrame($versionid, $compressionlevel)
|
||||
{
|
||||
public function MonkeySamplesPerFrame($versionid, $compressionlevel) {
|
||||
if ($versionid >= 3950) {
|
||||
return 73728 * 4;
|
||||
} elseif ($versionid >= 3900) {
|
||||
|
@ -203,4 +200,5 @@ class getid3_monkey extends getid3_handler
|
|||
return 9216;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,11 +18,10 @@
|
|||
class getid3_mpc extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['mpc']['header'] = [];
|
||||
$info['mpc']['header'] = array();
|
||||
$thisfile_mpc_header = &$info['mpc']['header'];
|
||||
|
||||
$info['fileformat'] = 'mpc';
|
||||
|
@ -35,26 +34,33 @@ class getid3_mpc extends getid3_handler
|
|||
$MPCheaderData = $this->fread(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)).'"';
|
||||
|
||||
$this->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;
|
||||
}
|
||||
|
||||
|
||||
public function ParseMPCsv8()
|
||||
{
|
||||
public function ParseMPCsv8() {
|
||||
// this is SV8
|
||||
// http://trac.musepack.net/trac/wiki/SV8Specification
|
||||
|
||||
|
@ -66,7 +72,7 @@ class getid3_mpc extends getid3_handler
|
|||
|
||||
$offset = $this->ftell();
|
||||
while ($offset < $info['avdataend']) {
|
||||
$thisPacket = [];
|
||||
$thisPacket = array();
|
||||
$thisPacket['offset'] = $offset;
|
||||
$packet_offset = 0;
|
||||
|
||||
|
@ -77,13 +83,13 @@ class getid3_mpc extends getid3_handler
|
|||
$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'];
|
||||
$this->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);
|
||||
$this->error('Did not find expected packet length within '.$maxHandledPacketLength.' bytes at offset '.($thisPacket['offset'] + $keyNameSize));
|
||||
return false;
|
||||
}
|
||||
$packet_offset += $packetLength;
|
||||
|
@ -144,18 +150,10 @@ class getid3_mpc extends getid3_handler
|
|||
$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'];
|
||||
}
|
||||
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
|
||||
|
@ -193,11 +191,11 @@ class getid3_mpc extends getid3_handler
|
|||
case 'SE': // Stream End
|
||||
case 'AP': // Audio Data
|
||||
// nothing useful here, just skip this packet
|
||||
$thisPacket = [];
|
||||
$thisPacket = array();
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Found unhandled key type "'.$thisPacket['key'].'" at offset '.$thisPacket['offset'];
|
||||
$this->error('Found unhandled key type "'.$thisPacket['key'].'" at offset '.$thisPacket['offset']);
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
@ -210,8 +208,7 @@ class getid3_mpc extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function ParseMPCsv7()
|
||||
{
|
||||
public function ParseMPCsv7() {
|
||||
// this is SV7
|
||||
// http://www.uni-jena.de/~pfk/mpp/sv8/header.html
|
||||
|
||||
|
@ -232,7 +229,7 @@ class getid3_mpc extends getid3_handler
|
|||
$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'].')';
|
||||
$this->error('Only Musepack SV7 supported (this file claims to be v'.$thisfile_mpc_header['stream_version_major'].')');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -271,7 +268,7 @@ class getid3_mpc extends getid3_handler
|
|||
$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';
|
||||
$this->error('Corrupt MPC file: frequency == zero');
|
||||
return false;
|
||||
}
|
||||
$info['audio']['sample_rate'] = $thisfile_mpc_header['sample_rate'];
|
||||
|
@ -279,7 +276,7 @@ class getid3_mpc extends getid3_handler
|
|||
|
||||
$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';
|
||||
$this->error('Corrupt MPC file: playtime_seconds == zero');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -301,8 +298,7 @@ class getid3_mpc extends getid3_handler
|
|||
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['album_gain_db'] = (float) $thisfile_mpc_header['raw']['album_gain'] / 100;;
|
||||
}
|
||||
$thisfile_mpc_header['encoder_version'] = $this->MPCencoderVersionLookup($thisfile_mpc_header['raw']['encoder_version']);
|
||||
|
||||
|
@ -326,8 +322,7 @@ class getid3_mpc extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function ParseMPCsv6()
|
||||
{
|
||||
public function ParseMPCsv6() {
|
||||
// this is SV4 - SV6
|
||||
|
||||
$info = &$this->getid3->info;
|
||||
|
@ -382,7 +377,7 @@ class getid3_mpc extends getid3_handler
|
|||
}
|
||||
|
||||
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'];
|
||||
$this->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
|
||||
|
@ -403,9 +398,8 @@ class getid3_mpc extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function MPCprofileNameLookup($profileid)
|
||||
{
|
||||
static $MPCprofileNameLookup = [
|
||||
public function MPCprofileNameLookup($profileid) {
|
||||
static $MPCprofileNameLookup = array(
|
||||
0 => 'no profile',
|
||||
1 => 'Experimental',
|
||||
2 => 'unused',
|
||||
|
@ -422,31 +416,28 @@ class getid3_mpc extends getid3_handler
|
|||
13 => 'BrainDead (q = 8.0)',
|
||||
14 => 'above BrainDead (q = 9.0)',
|
||||
15 => 'above BrainDead (q = 10.0)'
|
||||
];
|
||||
);
|
||||
return (isset($MPCprofileNameLookup[$profileid]) ? $MPCprofileNameLookup[$profileid] : 'invalid');
|
||||
}
|
||||
|
||||
public function MPCfrequencyLookup($frequencyid)
|
||||
{
|
||||
static $MPCfrequencyLookup = [
|
||||
public function MPCfrequencyLookup($frequencyid) {
|
||||
static $MPCfrequencyLookup = array(
|
||||
0 => 44100,
|
||||
1 => 48000,
|
||||
2 => 37800,
|
||||
3 => 32000
|
||||
];
|
||||
);
|
||||
return (isset($MPCfrequencyLookup[$frequencyid]) ? $MPCfrequencyLookup[$frequencyid] : 'invalid');
|
||||
}
|
||||
|
||||
public function MPCpeakDBLookup($intvalue)
|
||||
{
|
||||
public function MPCpeakDBLookup($intvalue) {
|
||||
if ($intvalue > 0) {
|
||||
return ((log10($intvalue) / log10(2)) - 15) * 6;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function MPCencoderVersionLookup($encoderversion)
|
||||
{
|
||||
public function MPCencoderVersionLookup($encoderversion) {
|
||||
//Encoder version * 100 (106 = 1.06)
|
||||
//EncoderVersion % 10 == 0 Release (1.0)
|
||||
//EncoderVersion % 2 == 0 Beta (1.06)
|
||||
|
@ -458,19 +449,22 @@ class getid3_mpc extends getid3_handler
|
|||
}
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
public function SV8variableLengthInteger($data, &$packetLength, $maxHandledPacketLength = 9)
|
||||
{
|
||||
public function SV8variableLengthInteger($data, &$packetLength, $maxHandledPacketLength=9) {
|
||||
$packet_size = 0;
|
||||
for ($packetLength = 1; $packetLength <= $maxHandledPacketLength; $packetLength++) {
|
||||
// variable-length size field:
|
||||
|
@ -494,11 +488,10 @@ class getid3_mpc extends getid3_handler
|
|||
return $packet_size;
|
||||
}
|
||||
|
||||
public function MPCsv8PacketName($packetKey)
|
||||
{
|
||||
static $MPCsv8PacketName = [];
|
||||
public function MPCsv8PacketName($packetKey) {
|
||||
static $MPCsv8PacketName = array();
|
||||
if (empty($MPCsv8PacketName)) {
|
||||
$MPCsv8PacketName = [
|
||||
$MPCsv8PacketName = array(
|
||||
'AP' => 'Audio Packet',
|
||||
'CT' => 'Chapter Tag',
|
||||
'EI' => 'Encoder Info',
|
||||
|
@ -507,7 +500,7 @@ class getid3_mpc extends getid3_handler
|
|||
'SH' => 'Stream Header',
|
||||
'SO' => 'Seek Table Offset',
|
||||
'ST' => 'Seek Table',
|
||||
];
|
||||
);
|
||||
}
|
||||
return (isset($MPCsv8PacketName[$packetKey]) ? $MPCsv8PacketName[$packetKey] : $packetKey);
|
||||
}
|
||||
|
|
|
@ -19,21 +19,20 @@ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.flac.php', __FILE
|
|||
class getid3_ogg extends getid3_handler
|
||||
{
|
||||
// http://xiph.org/vorbis/doc/Vorbis_I_spec.html
|
||||
public function Analyze()
|
||||
{
|
||||
public 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.';
|
||||
$this->warning('Illegal ID3v2 tag present.');
|
||||
}
|
||||
if (isset($info['id3v1'])) {
|
||||
$info['warning'][] = 'Illegal ID3v1 tag present.';
|
||||
$this->warning('Illegal ID3v1 tag present.');
|
||||
}
|
||||
if (isset($info['ape'])) {
|
||||
$info['warning'][] = 'Illegal APE tag present.';
|
||||
$this->warning('Illegal APE tag present.');
|
||||
}
|
||||
|
||||
|
||||
|
@ -45,7 +44,7 @@ class getid3_ogg extends getid3_handler
|
|||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
|
||||
|
||||
if ($this->ftell() >= $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?)';
|
||||
$this->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;
|
||||
|
@ -55,16 +54,23 @@ class getid3_ogg extends getid3_handler
|
|||
$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) == 'OpusHead') {
|
||||
|
||||
if( $this->ParseOpusPageHeader($filedata, $filedataoffset, $oggpageinfo) == false ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} elseif (substr($filedata, 0, 8) == 'Speex ') {
|
||||
|
||||
// http://www.speex.org/manual/node10.html
|
||||
|
||||
$info['audio']['dataformat'] = 'speex';
|
||||
|
@ -114,7 +120,9 @@ class getid3_ogg extends getid3_handler
|
|||
if ($info['speex']['vbr']) {
|
||||
$info['audio']['bitrate_mode'] = 'vbr';
|
||||
}
|
||||
|
||||
} elseif (substr($filedata, 0, 7) == "\x80".'theora') {
|
||||
|
||||
// http://www.theora.org/doc/Theora.pdf (section 6.2)
|
||||
|
||||
$info['ogg']['pageheader']['theora']['theora_magic'] = substr($filedata, $filedataoffset, 7); // hard-coded to "\x80.'theora'
|
||||
|
@ -171,8 +179,11 @@ class getid3_ogg extends getid3_handler
|
|||
if ($info['ogg']['pageheader']['theora']['pixel_aspect_denominator'] > 0) {
|
||||
$info['video']['pixel_aspect_ratio'] = (float) $info['ogg']['pageheader']['theora']['pixel_aspect_numerator'] / $info['ogg']['pageheader']['theora']['pixel_aspect_denominator'];
|
||||
}
|
||||
$info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of getID3 ['.$this->getid3->version().'] -- bitrate, playtime and all audio data are currently unavailable';
|
||||
$this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['.$this->getid3->version().'] -- bitrate, playtime and all audio data are currently unavailable');
|
||||
|
||||
|
||||
} elseif (substr($filedata, 0, 8) == "fishead\x00") {
|
||||
|
||||
// Ogg Skeleton version 3.0 Format Specification
|
||||
// http://xiph.org/ogg/doc/skeleton.html
|
||||
$filedataoffset += 8;
|
||||
|
@ -205,6 +216,7 @@ class getid3_ogg extends getid3_handler
|
|||
$this->fseek($oggpageinfo['page_end_offset']);
|
||||
|
||||
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;
|
||||
|
@ -224,14 +236,19 @@ class getid3_ogg extends getid3_handler
|
|||
$filedataoffset += 1;
|
||||
$info['ogg']['skeleton']['fisbone']['raw']['padding'] = substr($filedata, $filedataoffset, 3);
|
||||
$filedataoffset += 3;
|
||||
|
||||
} elseif (substr($filedata, 1, 6) == 'theora') {
|
||||
|
||||
$info['video']['dataformat'] = 'theora1';
|
||||
$info['error'][] = 'Ogg Theora (v1) not correctly handled in this version of getID3 ['.$this->getid3->version().']';
|
||||
$this->error('Ogg Theora (v1) 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';
|
||||
$this->error('unexpected');
|
||||
//break;
|
||||
}
|
||||
//} while ($oggpageinfo['page_seqno'] == 0);
|
||||
|
@ -239,13 +256,16 @@ class getid3_ogg extends getid3_handler
|
|||
|
||||
$this->fseek($oggpageinfo['page_start_offset']);
|
||||
|
||||
$info['error'][] = 'Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().']';
|
||||
$this->error('Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().']');
|
||||
//return false;
|
||||
|
||||
} else {
|
||||
$info['error'][] = 'Expecting either "Speex ", "OpusHead" or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"';
|
||||
|
||||
$this->error('Expecting either "Speex ", "OpusHead" or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"');
|
||||
unset($info['ogg']);
|
||||
unset($info['mime_type']);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// Page 2 - Comment Header
|
||||
|
@ -264,7 +284,7 @@ class getid3_ogg extends getid3_handler
|
|||
case 'flac':
|
||||
$flac = new getid3_flac($this->getid3);
|
||||
if (!$flac->parseMETAdata()) {
|
||||
$info['error'][] = 'Failed to parse FLAC headers';
|
||||
$this->error('Failed to parse FLAC headers');
|
||||
return false;
|
||||
}
|
||||
unset($flac);
|
||||
|
@ -279,18 +299,22 @@ class getid3_ogg extends getid3_handler
|
|||
$filedata = $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
|
||||
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, 0, 8); // hard-coded to 'OpusTags'
|
||||
if(substr($filedata, 0, 8) != 'OpusTags') {
|
||||
$info['error'][] = 'Expected "OpusTags" as header but got "'.substr($filedata, 0, 8).'"';
|
||||
$this->error('Expected "OpusTags" as header but got "'.substr($filedata, 0, 8).'"');
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->ParseVorbisComments();
|
||||
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)';
|
||||
|
||||
$this->warning('Unable to parse Ogg end chunk file (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)');
|
||||
|
||||
} else {
|
||||
|
||||
$this->fseek(max($info['avdataend'] - $this->getid3->fread_buffer_size(), 0));
|
||||
$LastChunkOfOgg = strrev($this->fread($this->getid3->fread_buffer_size()));
|
||||
if ($LastOggSpostion = strpos($LastChunkOfOgg, 'SggO')) {
|
||||
|
@ -299,13 +323,14 @@ class getid3_ogg extends getid3_handler
|
|||
$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';
|
||||
$this->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'])) {
|
||||
|
@ -317,7 +342,7 @@ class getid3_ogg extends getid3_handler
|
|||
}
|
||||
if (isset($info['audio']['bitrate']) && !isset($info['playtime_seconds'])) {
|
||||
if ($info['audio']['bitrate'] == 0) {
|
||||
$info['error'][] = 'Corrupt Ogg file: bitrate_audio == zero';
|
||||
$this->error('Corrupt Ogg file: bitrate_audio == zero');
|
||||
return false;
|
||||
}
|
||||
$info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate']);
|
||||
|
@ -328,14 +353,19 @@ class getid3_ogg extends getid3_handler
|
|||
|
||||
// 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']);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -348,8 +378,7 @@ class getid3_ogg extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function ParseVorbisPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo)
|
||||
{
|
||||
public function ParseVorbisPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) {
|
||||
$info = &$this->getid3->info;
|
||||
$info['audio']['dataformat'] = 'vorbis';
|
||||
$info['audio']['lossless'] = false;
|
||||
|
@ -366,7 +395,7 @@ class getid3_ogg extends getid3_handler
|
|||
$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';
|
||||
$this->error('Corrupt Ogg file: sample rate == zero');
|
||||
return false;
|
||||
}
|
||||
$info['audio']['sample_rate'] = $info['ogg']['samplerate'];
|
||||
|
@ -398,8 +427,7 @@ class getid3_ogg extends getid3_handler
|
|||
}
|
||||
|
||||
// http://tools.ietf.org/html/draft-ietf-codec-oggopus-03
|
||||
public function ParseOpusPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo)
|
||||
{
|
||||
public function ParseOpusPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) {
|
||||
$info = &$this->getid3->info;
|
||||
$info['audio']['dataformat'] = 'opus';
|
||||
$info['mime_type'] = 'audio/ogg; codecs=opus';
|
||||
|
@ -415,7 +443,7 @@ class getid3_ogg extends getid3_handler
|
|||
$filedataoffset += 1;
|
||||
|
||||
if ($info['ogg']['pageheader']['opus']['version'] < 1 || $info['ogg']['pageheader']['opus']['version'] > 15) {
|
||||
$info['error'][] = 'Unknown opus version number (only accepting 1-15)';
|
||||
$this->error('Unknown opus version number (only accepting 1-15)');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -423,7 +451,7 @@ class getid3_ogg extends getid3_handler
|
|||
$filedataoffset += 1;
|
||||
|
||||
if ($info['ogg']['pageheader']['opus']['out_channel_count'] == 0) {
|
||||
$info['error'][] = 'Invalid channel count in opus header (must not be zero)';
|
||||
$this->error('Invalid channel count in opus header (must not be zero)');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -449,8 +477,7 @@ class getid3_ogg extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function ParseOggPageHeader()
|
||||
{
|
||||
public function ParseOggPageHeader() {
|
||||
// http://xiph.org/ogg/vorbis/doc/framing.html
|
||||
$oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file
|
||||
|
||||
|
@ -502,8 +529,7 @@ class getid3_ogg extends getid3_handler
|
|||
}
|
||||
|
||||
// http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810005
|
||||
public function ParseVorbisComments()
|
||||
{
|
||||
public function ParseVorbisComments() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$OriginalOffset = $this->ftell();
|
||||
|
@ -521,7 +547,8 @@ class getid3_ogg extends getid3_handler
|
|||
|
||||
if ($info['audio']['dataformat'] == 'vorbis') {
|
||||
$commentdataoffset += (strlen('vorbis') + 1);
|
||||
} else if ($info['audio']['dataformat'] == 'opus') {
|
||||
}
|
||||
else if ($info['audio']['dataformat'] == 'opus') {
|
||||
$commentdataoffset += strlen('OpusTags');
|
||||
}
|
||||
|
||||
|
@ -548,12 +575,13 @@ class getid3_ogg extends getid3_handler
|
|||
$commentdataoffset += 4;
|
||||
$info['avdataoffset'] = $CommentStartOffset + $commentdataoffset;
|
||||
|
||||
$basicfields = ['TITLE', 'ARTIST', 'ALBUM', 'TRACKNUMBER', 'GENRE', 'DATE', 'DESCRIPTION', 'COMMENT'];
|
||||
$basicfields = array('TITLE', 'ARTIST', 'ALBUM', 'TRACKNUMBER', 'GENRE', 'DATE', 'DESCRIPTION', 'COMMENT');
|
||||
$ThisFileInfo_ogg_comments_raw = &$info['ogg']['comments_raw'];
|
||||
for ($i = 0; $i < $CommentsCount; $i++) {
|
||||
|
||||
if ($i >= 10000) {
|
||||
// https://github.com/owncloud/music/issues/212#issuecomment-43082336
|
||||
$info['warning'][] = 'Unexpectedly large number ('.$CommentsCount.') of Ogg comments - breaking after reading '.$i.' comments';
|
||||
$this->warning('Unexpectedly large number ('.$CommentsCount.') of Ogg comments - breaking after reading '.$i.' comments');
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -581,6 +609,7 @@ class getid3_ogg extends getid3_handler
|
|||
//$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
|
||||
$commentdata .= $this->fread($this->OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1));
|
||||
}
|
||||
|
||||
}
|
||||
$ThisFileInfo_ogg_comments_raw[$i]['size'] = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
|
||||
|
||||
|
@ -590,7 +619,7 @@ class getid3_ogg extends getid3_handler
|
|||
$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';
|
||||
$this->warning('Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($ThisFileInfo_ogg_comments_raw[$i]['size']).' bytes) - aborting reading comments');
|
||||
break 2;
|
||||
}
|
||||
|
||||
|
@ -614,12 +643,12 @@ class getid3_ogg extends getid3_handler
|
|||
|
||||
//$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
|
||||
if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) {
|
||||
$info['warning'][] = 'undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell();
|
||||
$this->warning('undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell());
|
||||
break;
|
||||
}
|
||||
$readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1);
|
||||
if ($readlength <= 0) {
|
||||
$info['warning'][] = 'invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell();
|
||||
$this->warning('invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell());
|
||||
break;
|
||||
}
|
||||
$commentdata .= $this->fread($readlength);
|
||||
|
@ -631,14 +660,18 @@ class getid3_ogg extends getid3_handler
|
|||
$commentdataoffset += $ThisFileInfo_ogg_comments_raw[$i]['size'];
|
||||
|
||||
if (!$commentstring) {
|
||||
|
||||
// no comment?
|
||||
$info['warning'][] = 'Blank Ogg comment ['.$i.']';
|
||||
$this->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] : '');
|
||||
|
||||
if ($ThisFileInfo_ogg_comments_raw[$i]['key'] == 'METADATA_BLOCK_PICTURE') {
|
||||
|
||||
// http://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE
|
||||
// The unencoded format is that of the FLAC picture block. The fields are stored in big endian order as in FLAC, picture data is stored according to the relevant standard.
|
||||
// http://flac.sourceforge.net/format.html#metadata_block_picture
|
||||
|
@ -647,7 +680,9 @@ class getid3_ogg extends getid3_handler
|
|||
$flac->parsePICTURE();
|
||||
$info['ogg']['comments']['picture'][] = $flac->getid3->info['flac']['PICTURE'][0];
|
||||
unset($flac);
|
||||
|
||||
} elseif ($ThisFileInfo_ogg_comments_raw[$i]['key'] == 'COVERART') {
|
||||
|
||||
$data = base64_decode($ThisFileInfo_ogg_comments_raw[$i]['value']);
|
||||
$this->notice('Found deprecated COVERART tag, it should be replaced in honor of METADATA_BLOCK_PICTURE structure');
|
||||
/** @todo use 'coverartmime' where available */
|
||||
|
@ -659,20 +694,26 @@ class getid3_ogg extends getid3_handler
|
|||
|
||||
$ogg = new self($this->getid3);
|
||||
$ogg->setStringMode($data);
|
||||
$info['ogg']['comments']['picture'][] = [
|
||||
$info['ogg']['comments']['picture'][] = array(
|
||||
'image_mime' => $imageinfo['mime'],
|
||||
'datalength' => strlen($data),
|
||||
'picturetype' => 'cover art',
|
||||
'image_height' => $imageinfo['height'],
|
||||
'image_width' => $imageinfo['width'],
|
||||
'data' => $ogg->saveAttachment('coverart', 0, strlen($data), $imageinfo['mime']),
|
||||
];
|
||||
);
|
||||
unset($ogg);
|
||||
|
||||
} else {
|
||||
|
||||
$info['ogg']['comments'][strtolower($ThisFileInfo_ogg_comments_raw[$i]['key'])][] = $ThisFileInfo_ogg_comments_raw[$i]['value'];
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
$info['warning'][] = '[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring;
|
||||
|
||||
$this->warning('[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring);
|
||||
|
||||
}
|
||||
unset($ThisFileInfo_ogg_comments_raw[$i]);
|
||||
}
|
||||
|
@ -724,9 +765,8 @@ class getid3_ogg extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public static function SpeexBandModeLookup($mode)
|
||||
{
|
||||
static $SpeexBandModeLookup = [];
|
||||
public static function SpeexBandModeLookup($mode) {
|
||||
static $SpeexBandModeLookup = array();
|
||||
if (empty($SpeexBandModeLookup)) {
|
||||
$SpeexBandModeLookup[0] = 'narrow';
|
||||
$SpeexBandModeLookup[1] = 'wide';
|
||||
|
@ -736,8 +776,7 @@ class getid3_ogg extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public static function OggPageSegmentLength($OggInfoArray, $SegmentNumber = 1)
|
||||
{
|
||||
public static function OggPageSegmentLength($OggInfoArray, $SegmentNumber=1) {
|
||||
for ($i = 0; $i < $SegmentNumber; $i++) {
|
||||
$segmentlength = 0;
|
||||
foreach ($OggInfoArray['segment_table'] as $key => $value) {
|
||||
|
@ -751,8 +790,7 @@ class getid3_ogg extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public static function get_quality_from_nominal_bitrate($nominal_bitrate)
|
||||
{
|
||||
public static function get_quality_from_nominal_bitrate($nominal_bitrate) {
|
||||
|
||||
// decrease precision
|
||||
$nominal_bitrate = $nominal_bitrate / 1000;
|
||||
|
@ -775,10 +813,9 @@ class getid3_ogg extends getid3_handler
|
|||
return round($qval, 1); // 5 or 4.9
|
||||
}
|
||||
|
||||
public static function TheoraColorSpace($colorspace_id)
|
||||
{
|
||||
public static function TheoraColorSpace($colorspace_id) {
|
||||
// http://www.theora.org/doc/Theora.pdf (table 6.3)
|
||||
static $TheoraColorSpaceLookup = [];
|
||||
static $TheoraColorSpaceLookup = array();
|
||||
if (empty($TheoraColorSpaceLookup)) {
|
||||
$TheoraColorSpaceLookup[0] = 'Undefined';
|
||||
$TheoraColorSpaceLookup[1] = 'Rec. 470M';
|
||||
|
@ -788,10 +825,9 @@ class getid3_ogg extends getid3_handler
|
|||
return (isset($TheoraColorSpaceLookup[$colorspace_id]) ? $TheoraColorSpaceLookup[$colorspace_id] : null);
|
||||
}
|
||||
|
||||
public static function TheoraPixelFormat($pixelformat_id)
|
||||
{
|
||||
public static function TheoraPixelFormat($pixelformat_id) {
|
||||
// http://www.theora.org/doc/Theora.pdf (table 6.4)
|
||||
static $TheoraPixelFormatLookup = [];
|
||||
static $TheoraPixelFormatLookup = array();
|
||||
if (empty($TheoraPixelFormatLookup)) {
|
||||
$TheoraPixelFormatLookup[0] = '4:2:0';
|
||||
$TheoraPixelFormatLookup[1] = 'Reserved';
|
||||
|
@ -800,4 +836,5 @@ class getid3_ogg extends getid3_handler
|
|||
}
|
||||
return (isset($TheoraPixelFormatLookup[$pixelformat_id]) ? $TheoraPixelFormatLookup[$pixelformat_id] : null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,8 +19,7 @@ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php',
|
|||
class getid3_optimfrog extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'ofr';
|
||||
|
@ -31,19 +30,22 @@ class getid3_optimfrog extends getid3_handler
|
|||
$this->fseek($info['avdataoffset']);
|
||||
$OFRheader = $this->fread(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).'"';
|
||||
$this->error('Expecting "*RIFF" or "OFR " at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($OFRheader).'"');
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public function ParseOptimFROGheader42()
|
||||
{
|
||||
public function ParseOptimFROGheader42() {
|
||||
// for fileformat of v4.21 and older
|
||||
|
||||
$info = &$this->getid3->info;
|
||||
|
@ -90,8 +92,7 @@ class getid3_optimfrog extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function ParseOptimFROGheader45()
|
||||
{
|
||||
public function ParseOptimFROGheader45() {
|
||||
// for fileformat of v4.50a and higher
|
||||
|
||||
$info = &$this->getid3->info;
|
||||
|
@ -108,12 +109,13 @@ class getid3_optimfrog extends getid3_handler
|
|||
$BlockName = 'OFR ';
|
||||
}
|
||||
if (!isset($info['ofr'][$BlockName])) {
|
||||
$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;
|
||||
|
@ -126,7 +128,7 @@ class getid3_optimfrog extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = '"'.$BlockName.'" contains more data than expected (expected 12 or 15 bytes, found '.$BlockSize.' bytes)';
|
||||
$this->warning('"'.$BlockName.'" contains more data than expected (expected 12 or 15 bytes, found '.$BlockSize.' bytes)');
|
||||
break;
|
||||
}
|
||||
$BlockData .= $this->fread($BlockSize);
|
||||
|
@ -143,6 +145,7 @@ class getid3_optimfrog extends getid3_handler
|
|||
$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));
|
||||
|
@ -164,6 +167,7 @@ class getid3_optimfrog extends getid3_handler
|
|||
$info['audio']['lossless'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$info['audio']['channels'] = $thisfile_ofr_thisblock['channels'];
|
||||
|
@ -201,10 +205,12 @@ class getid3_optimfrog extends getid3_handler
|
|||
$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) {
|
||||
|
@ -246,7 +252,7 @@ class getid3_optimfrog extends getid3_handler
|
|||
|
||||
$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()';
|
||||
$this->warning('APEtag processing inside OptimFROG not supported in this version ('.$this->getid3->version().') of getID3()');
|
||||
|
||||
$this->fseek($BlockSize, SEEK_CUR);
|
||||
break;
|
||||
|
@ -259,12 +265,16 @@ class getid3_optimfrog extends getid3_handler
|
|||
$thisfile_ofr_thisblock['size'] = $BlockSize;
|
||||
|
||||
if ($BlockSize == 16) {
|
||||
|
||||
$thisfile_ofr_thisblock['md5_binary'] = $this->fread($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';
|
||||
|
||||
$this->warning('Expecting block size of 16 in "MD5 " chunk, found '.$BlockSize.' instead');
|
||||
$this->fseek($BlockSize, SEEK_CUR);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -273,7 +283,7 @@ class getid3_optimfrog extends getid3_handler
|
|||
$thisfile_ofr_thisblock['offset'] = $BlockOffset;
|
||||
$thisfile_ofr_thisblock['size'] = $BlockSize;
|
||||
|
||||
$info['warning'][] = 'Unhandled OptimFROG block type "'.$BlockName.'" at offset '.$thisfile_ofr_thisblock['offset'];
|
||||
$this->warning('Unhandled OptimFROG block type "'.$BlockName.'" at offset '.$thisfile_ofr_thisblock['offset']);
|
||||
$this->fseek($BlockSize, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
|
@ -304,9 +314,8 @@ class getid3_optimfrog extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public static function OptimFROGsampleTypeLookup($SampleType)
|
||||
{
|
||||
static $OptimFROGsampleTypeLookup = [
|
||||
public static function OptimFROGsampleTypeLookup($SampleType) {
|
||||
static $OptimFROGsampleTypeLookup = array(
|
||||
0 => 'unsigned int (8-bit)',
|
||||
1 => 'signed int (8-bit)',
|
||||
2 => 'unsigned int (16-bit)',
|
||||
|
@ -318,13 +327,12 @@ class getid3_optimfrog extends getid3_handler
|
|||
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);
|
||||
}
|
||||
|
||||
public static function OptimFROGbitsPerSampleTypeLookup($SampleType)
|
||||
{
|
||||
static $OptimFROGbitsPerSampleTypeLookup = [
|
||||
public static function OptimFROGbitsPerSampleTypeLookup($SampleType) {
|
||||
static $OptimFROGbitsPerSampleTypeLookup = array(
|
||||
0 => 8,
|
||||
1 => 8,
|
||||
2 => 16,
|
||||
|
@ -336,25 +344,23 @@ class getid3_optimfrog extends getid3_handler
|
|||
8 => 32,
|
||||
9 => 32,
|
||||
10 => 32
|
||||
];
|
||||
);
|
||||
return (isset($OptimFROGbitsPerSampleTypeLookup[$SampleType]) ? $OptimFROGbitsPerSampleTypeLookup[$SampleType] : false);
|
||||
}
|
||||
|
||||
public static function OptimFROGchannelConfigurationLookup($ChannelConfiguration)
|
||||
{
|
||||
static $OptimFROGchannelConfigurationLookup = [
|
||||
public static function OptimFROGchannelConfigurationLookup($ChannelConfiguration) {
|
||||
static $OptimFROGchannelConfigurationLookup = array(
|
||||
0 => 'mono',
|
||||
1 => 'stereo'
|
||||
];
|
||||
);
|
||||
return (isset($OptimFROGchannelConfigurationLookup[$ChannelConfiguration]) ? $OptimFROGchannelConfigurationLookup[$ChannelConfiguration] : false);
|
||||
}
|
||||
|
||||
public static function OptimFROGchannelConfigNumChannelsLookup($ChannelConfiguration)
|
||||
{
|
||||
static $OptimFROGchannelConfigNumChannelsLookup = [
|
||||
public static function OptimFROGchannelConfigNumChannelsLookup($ChannelConfiguration) {
|
||||
static $OptimFROGchannelConfigNumChannelsLookup = array(
|
||||
0 => 1,
|
||||
1 => 2
|
||||
];
|
||||
);
|
||||
return (isset($OptimFROGchannelConfigNumChannelsLookup[$ChannelConfiguration]) ? $OptimFROGchannelConfigNumChannelsLookup[$ChannelConfiguration] : false);
|
||||
}
|
||||
|
||||
|
@ -366,31 +372,29 @@ class getid3_optimfrog extends getid3_handler
|
|||
// }
|
||||
|
||||
|
||||
public static function OptimFROGencoderNameLookup($EncoderID)
|
||||
{
|
||||
public 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 = [
|
||||
static $OptimFROGencoderSystemLookup = array(
|
||||
0x00 => 'Windows console',
|
||||
0x01 => 'Linux console',
|
||||
0x0F => 'unknown'
|
||||
];
|
||||
);
|
||||
return $EncoderVersion.' ('.(isset($OptimFROGencoderSystemLookup[$EncoderSystemID]) ? $OptimFROGencoderSystemLookup[$EncoderSystemID] : 'undefined encoder type (0x'.dechex($EncoderSystemID).')').')';
|
||||
}
|
||||
|
||||
public static function OptimFROGcompressionLookup($CompressionID)
|
||||
{
|
||||
public static function OptimFROGcompressionLookup($CompressionID) {
|
||||
// mode = compression >> 3
|
||||
// speedup = compression & 0x07
|
||||
|
||||
$CompressionModeID = ($CompressionID & 0xF8) >> 3;
|
||||
//$CompressionSpeedupID = ($CompressionID & 0x07);
|
||||
|
||||
static $OptimFROGencoderModeLookup = [
|
||||
static $OptimFROGencoderModeLookup = array(
|
||||
0x00 => 'fast',
|
||||
0x01 => 'normal',
|
||||
0x02 => 'high',
|
||||
|
@ -401,23 +405,23 @@ class getid3_optimfrog extends getid3_handler
|
|||
0x07 => 'highnew',
|
||||
0x08 => 'extranew',
|
||||
0x09 => 'bestnew'
|
||||
];
|
||||
);
|
||||
return (isset($OptimFROGencoderModeLookup[$CompressionModeID]) ? $OptimFROGencoderModeLookup[$CompressionModeID] : 'undefined mode (0x'.str_pad(dechex($CompressionModeID), 2, '0', STR_PAD_LEFT).')');
|
||||
}
|
||||
|
||||
public static function OptimFROGspeedupLookup($CompressionID)
|
||||
{
|
||||
public static function OptimFROGspeedupLookup($CompressionID) {
|
||||
// mode = compression >> 3
|
||||
// speedup = compression & 0x07
|
||||
|
||||
//$CompressionModeID = ($CompressionID & 0xF8) >> 3;
|
||||
$CompressionSpeedupID = ($CompressionID & 0x07);
|
||||
|
||||
static $OptimFROGencoderSpeedupLookup = [
|
||||
static $OptimFROGencoderSpeedupLookup = array(
|
||||
0x00 => '1x',
|
||||
0x01 => '2x',
|
||||
0x02 => '4x'
|
||||
];
|
||||
);
|
||||
return (isset($OptimFROGencoderSpeedupLookup[$CompressionSpeedupID]) ? $OptimFROGencoderSpeedupLookup[$CompressionSpeedupID] : 'undefined mode (0x'.dechex($CompressionSpeedupID));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,15 +18,14 @@
|
|||
class getid3_rkau extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$RKAUHeader = $this->fread(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)).'"';
|
||||
$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($RKAUHeader, 0, 3)).'"');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -37,7 +36,7 @@ class getid3_rkau extends getid3_handler
|
|||
$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'].')';
|
||||
$this->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;
|
||||
}
|
||||
|
@ -74,11 +73,11 @@ class getid3_rkau extends getid3_handler
|
|||
$info['audio']['bitrate'] = ($info['rkau']['compressed_bytes'] * 8) / $info['playtime_seconds'];
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function RKAUqualityLookup(&$RKAUdata)
|
||||
{
|
||||
public function RKAUqualityLookup(&$RKAUdata) {
|
||||
$level = ($RKAUdata['raw']['quality'] & 0xF0) >> 4;
|
||||
$quality = $RKAUdata['raw']['quality'] & 0x0F;
|
||||
|
||||
|
@ -90,4 +89,5 @@ class getid3_rkau extends getid3_handler
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
class getid3_shorten extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
@ -27,7 +26,7 @@ class getid3_shorten extends getid3_handler
|
|||
$ShortenHeader = $this->fread(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)).'"';
|
||||
$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($ShortenHeader, 0, 4)).'"');
|
||||
return false;
|
||||
}
|
||||
$info['fileformat'] = 'shn';
|
||||
|
@ -47,9 +46,12 @@ class getid3_shorten extends getid3_handler
|
|||
$SeekTableMagic = $this->fread(4);
|
||||
$magic = 'SEEK';
|
||||
if ($SeekTableMagic != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['shn']['seektable']['offset'].', found "'.getid3_lib::PrintHexBytes($SeekTableMagic).'"';
|
||||
|
||||
$this->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;
|
||||
|
@ -106,39 +108,46 @@ class getid3_shorten extends getid3_handler
|
|||
//
|
||||
// $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';
|
||||
$this->error('PHP running in Safe Mode - backtick operator not available, cannot run shntool to analyze Shorten files');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GETID3_OS_ISWINDOWS) {
|
||||
$RequiredFiles = ['shorten.exe', 'cygwin1.dll', 'head.exe'];
|
||||
|
||||
$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';
|
||||
$this->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';
|
||||
$this->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));
|
||||
|
@ -148,18 +157,26 @@ class getid3_shorten extends getid3_handler
|
|||
$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';
|
||||
|
||||
$this->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';
|
||||
|
||||
$this->error('shorten failed to decode file to WAV for parsing');
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
class getid3_tta extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'tta';
|
||||
|
@ -33,7 +32,7 @@ class getid3_tta extends getid3_handler
|
|||
$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']).'"';
|
||||
$this->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']);
|
||||
|
@ -91,7 +90,7 @@ class getid3_tta extends getid3_handler
|
|||
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};
|
||||
$this->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;
|
||||
}
|
||||
|
@ -104,4 +103,5 @@ class getid3_tta extends getid3_handler
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
class getid3_voc extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$OriginalAVdataOffset = $info['avdataoffset'];
|
||||
|
@ -28,13 +27,13 @@ class getid3_voc extends getid3_handler
|
|||
|
||||
$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)).'"';
|
||||
$this->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'] = [];
|
||||
$info['voc'] = array();
|
||||
$thisfile_voc = &$info['voc'];
|
||||
|
||||
$info['fileformat'] = 'voc';
|
||||
|
@ -57,11 +56,12 @@ class getid3_voc extends getid3_handler
|
|||
$thisfile_voc['header']['major_version'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 23, 1));
|
||||
|
||||
do {
|
||||
|
||||
$BlockOffset = $this->ftell();
|
||||
$BlockData = $this->fread(4);
|
||||
$BlockType = ord($BlockData{0});
|
||||
$BlockSize = getid3_lib::LittleEndian2Int(substr($BlockData, 1, 3));
|
||||
$ThisBlock = [];
|
||||
$ThisBlock = array();
|
||||
|
||||
getid3_lib::safe_inc($thisfile_voc['blocktypes'][$BlockType], 1);
|
||||
switch ($BlockType) {
|
||||
|
@ -137,7 +137,7 @@ class getid3_voc extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unhandled block type "'.$BlockType.'" at offset '.$BlockOffset;
|
||||
$this->warning('Unhandled block type "'.$BlockType.'" at offset '.$BlockOffset);
|
||||
$this->fseek($BlockSize, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
|
@ -148,6 +148,7 @@ class getid3_voc extends getid3_handler
|
|||
$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
|
||||
|
@ -163,20 +164,18 @@ class getid3_voc extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function VOCcompressionTypeLookup($index)
|
||||
{
|
||||
static $VOCcompressionTypeLookup = [
|
||||
public 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');
|
||||
}
|
||||
|
||||
public function VOCwFormatLookup($index)
|
||||
{
|
||||
static $VOCwFormatLookup = [
|
||||
public 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',
|
||||
|
@ -185,13 +184,12 @@ class getid3_voc extends getid3_handler
|
|||
0x0006 => 'CCITT a-Law',
|
||||
0x0007 => 'CCITT u-Law',
|
||||
0x2000 => 'Creative 16-bit to 4-bit ADPCM'
|
||||
];
|
||||
);
|
||||
return (isset($VOCwFormatLookup[$index]) ? $VOCwFormatLookup[$index] : false);
|
||||
}
|
||||
|
||||
public function VOCwFormatActualBitsPerSampleLookup($index)
|
||||
{
|
||||
static $VOCwFormatLookup = [
|
||||
public function VOCwFormatActualBitsPerSampleLookup($index) {
|
||||
static $VOCwFormatLookup = array(
|
||||
0x0000 => 8,
|
||||
0x0001 => 4,
|
||||
0x0002 => 3,
|
||||
|
@ -200,7 +198,8 @@ class getid3_voc extends getid3_handler
|
|||
0x0006 => 8,
|
||||
0x0007 => 8,
|
||||
0x2000 => 4
|
||||
];
|
||||
);
|
||||
return (isset($VOCwFormatLookup[$index]) ? $VOCwFormatLookup[$index] : false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,8 +17,7 @@
|
|||
|
||||
class getid3_vqf extends getid3_handler
|
||||
{
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// based loosely on code from TTwinVQ by Jurgen Faul <jfaulØgmx*de>
|
||||
|
@ -30,7 +29,7 @@ class getid3_vqf extends getid3_handler
|
|||
$info['audio']['lossless'] = false;
|
||||
|
||||
// shortcut
|
||||
$info['vqf']['raw'] = [];
|
||||
$info['vqf']['raw'] = array();
|
||||
$thisfile_vqf = &$info['vqf'];
|
||||
$thisfile_vqf_raw = &$thisfile_vqf['raw'];
|
||||
|
||||
|
@ -41,7 +40,7 @@ class getid3_vqf extends getid3_handler
|
|||
$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']).'"';
|
||||
$this->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;
|
||||
|
@ -53,6 +52,7 @@ class getid3_vqf extends getid3_handler
|
|||
$offset += 4;
|
||||
|
||||
while ($this->ftell() < $info['avdataend']) {
|
||||
|
||||
$ChunkBaseOffset = $this->ftell();
|
||||
$chunkoffset = 0;
|
||||
$ChunkData = $this->fread(8);
|
||||
|
@ -65,7 +65,7 @@ class getid3_vqf extends getid3_handler
|
|||
$ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
|
||||
$chunkoffset += 4;
|
||||
if ($ChunkSize > ($info['avdataend'] - $this->ftell())) {
|
||||
$info['error'][] = 'Invalid chunk size ('.$ChunkSize.') for chunk "'.$ChunkName.'" at offset '.$ChunkBaseOffset;
|
||||
$this->error('Invalid chunk size ('.$ChunkSize.') for chunk "'.$ChunkName.'" at offset '.$ChunkBaseOffset);
|
||||
break;
|
||||
}
|
||||
if ($ChunkSize > 0) {
|
||||
|
@ -75,7 +75,7 @@ class getid3_vqf extends getid3_handler
|
|||
switch ($ChunkName) {
|
||||
case 'COMM':
|
||||
// shortcut
|
||||
$thisfile_vqf['COMM'] = [];
|
||||
$thisfile_vqf['COMM'] = array();
|
||||
$thisfile_vqf_COMM = &$thisfile_vqf['COMM'];
|
||||
|
||||
$thisfile_vqf_COMM['channel_mode'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
|
||||
|
@ -93,7 +93,7 @@ class getid3_vqf extends getid3_handler
|
|||
$info['audio']['encoder_options'] = 'CBR' . ceil($info['audio']['bitrate']/1000);
|
||||
|
||||
if ($info['audio']['bitrate'] == 0) {
|
||||
$info['error'][] = 'Corrupt VQF file: bitrate_audio == zero';
|
||||
$this->error('Corrupt VQF file: bitrate_audio == zero');
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
@ -112,7 +112,7 @@ class getid3_vqf extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unhandled chunk type "'.$ChunkName.'" at offset '.$ChunkBaseOffset;
|
||||
$this->warning('Unhandled chunk type "'.$ChunkName.'" at offset '.$ChunkBaseOffset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -123,12 +123,12 @@ class getid3_vqf extends getid3_handler
|
|||
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';
|
||||
$this->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'));
|
||||
$this->warning('Probable corrupted file - should be '.$thisfile_vqf['DSIZ'].' bytes, actually '.($info['avdataend'] - $info['avdataoffset'] - strlen('DATA')));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -136,26 +136,25 @@ class getid3_vqf extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function VQFchannelFrequencyLookup($frequencyid)
|
||||
{
|
||||
static $VQFchannelFrequencyLookup = [
|
||||
public function VQFchannelFrequencyLookup($frequencyid) {
|
||||
static $VQFchannelFrequencyLookup = array(
|
||||
11 => 11025,
|
||||
22 => 22050,
|
||||
44 => 44100
|
||||
];
|
||||
);
|
||||
return (isset($VQFchannelFrequencyLookup[$frequencyid]) ? $VQFchannelFrequencyLookup[$frequencyid] : $frequencyid * 1000);
|
||||
}
|
||||
|
||||
public function VQFcommentNiceNameLookup($shortname)
|
||||
{
|
||||
static $VQFcommentNiceNameLookup = [
|
||||
public 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,20 +18,21 @@
|
|||
class getid3_wavpack extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
||||
while (true) {
|
||||
|
||||
$wavpackheader = $this->fread(32);
|
||||
|
||||
if ($this->ftell() >= $info['avdataend']) {
|
||||
break;
|
||||
} elseif (feof($this->getid3->fp)) {
|
||||
break;
|
||||
} elseif (isset($info['wavpack']['blockheader']['total_samples']) &&
|
||||
} 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) &&
|
||||
|
@ -46,7 +47,7 @@ class getid3_wavpack extends getid3_handler
|
|||
|
||||
$magic = 'wvpk';
|
||||
if ($blockheader_magic != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$blockheader_offset.', found "'.getid3_lib::PrintHexBytes($blockheader_magic).'"';
|
||||
$this->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':
|
||||
|
@ -85,7 +86,7 @@ class getid3_wavpack extends getid3_handler
|
|||
$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'];
|
||||
$this->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':
|
||||
|
@ -105,7 +106,7 @@ class getid3_wavpack extends getid3_handler
|
|||
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'];
|
||||
$this->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':
|
||||
|
@ -144,7 +145,8 @@ class getid3_wavpack extends getid3_handler
|
|||
}
|
||||
|
||||
while (!feof($this->getid3->fp) && ($this->ftell() < ($blockheader_offset + $blockheader_size + 8))) {
|
||||
$metablock = ['offset'=>$this->ftell()];
|
||||
|
||||
$metablock = array('offset'=>$this->ftell());
|
||||
$metablockheader = $this->fread(2);
|
||||
if (feof($this->getid3->fp)) {
|
||||
break;
|
||||
|
@ -171,6 +173,7 @@ class getid3_wavpack extends getid3_handler
|
|||
$metablock['data'] = null;
|
||||
|
||||
if ($metablock['size'] > 0) {
|
||||
|
||||
switch ($metablock['function_id']) {
|
||||
case 0x21: // ID_RIFF_HEADER
|
||||
case 0x22: // ID_RIFF_TRAILER
|
||||
|
@ -205,7 +208,7 @@ class getid3_wavpack extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['warning'][] = 'Unexpected metablock type "0x'.str_pad(dechex($metablock['function_id']), 2, '0', STR_PAD_LEFT).'" at offset '.$metablock['offset'];
|
||||
$this->warning('Unexpected metablock type "0x'.str_pad(dechex($metablock['function_id']), 2, '0', STR_PAD_LEFT).'" at offset '.$metablock['offset']);
|
||||
$this->fseek($metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size']);
|
||||
break;
|
||||
}
|
||||
|
@ -253,12 +256,12 @@ class getid3_wavpack extends getid3_handler
|
|||
|
||||
|
||||
case 0x23: // ID_REPLAY_GAIN
|
||||
$info['warning'][] = 'WavPack "Replay Gain" contents not yet handled by getID3() in metablock at offset '.$metablock['offset'];
|
||||
$this->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'];
|
||||
$this->warning('WavPack "Cuesheet" contents not yet handled by getID3() in metablock at offset '.$metablock['offset']);
|
||||
break;
|
||||
|
||||
|
||||
|
@ -316,7 +319,7 @@ class getid3_wavpack extends getid3_handler
|
|||
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';
|
||||
$this->warning('Expecting 16 bytes of WavPack "MD5 Checksum" in metablock at offset '.$metablock['offset'].', but found '.strlen($metablock['data']).' bytes');
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -338,11 +341,14 @@ class getid3_wavpack extends getid3_handler
|
|||
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);
|
||||
|
@ -350,18 +356,21 @@ class getid3_wavpack extends getid3_handler
|
|||
$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;
|
||||
}
|
||||
|
||||
|
||||
public function WavPackMetablockNameLookup(&$id)
|
||||
{
|
||||
static $WavPackMetablockNameLookup = [
|
||||
public function WavPackMetablockNameLookup(&$id) {
|
||||
static $WavPackMetablockNameLookup = array(
|
||||
0x00 => 'Dummy',
|
||||
0x01 => 'Encoder Info',
|
||||
0x02 => 'Decorrelation Terms',
|
||||
|
@ -382,7 +391,8 @@ class getid3_wavpack extends getid3_handler
|
|||
0x24 => 'Cuesheet',
|
||||
0x25 => 'Config Block',
|
||||
0x26 => 'MD5 Checksum',
|
||||
];
|
||||
);
|
||||
return (isset($WavPackMetablockNameLookup[$id]) ? $WavPackMetablockNameLookup[$id] : '');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,12 +20,11 @@ class getid3_bmp extends getid3_handler
|
|||
public $ExtractPalette = false;
|
||||
public $ExtractData = false;
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// shortcuts
|
||||
$info['bmp']['header']['raw'] = [];
|
||||
$info['bmp']['header']['raw'] = array();
|
||||
$thisfile_bmp = &$info['bmp'];
|
||||
$thisfile_bmp_header = &$thisfile_bmp['header'];
|
||||
$thisfile_bmp_header_raw = &$thisfile_bmp_header['raw'];
|
||||
|
@ -47,7 +46,7 @@ class getid3_bmp extends getid3_handler
|
|||
|
||||
$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']).'"';
|
||||
$this->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;
|
||||
|
@ -87,7 +86,7 @@ class getid3_bmp extends getid3_handler
|
|||
$thisfile_bmp['type_os'] = 'Windows';
|
||||
$thisfile_bmp['type_version'] = 5;
|
||||
} else {
|
||||
$info['error'][] = 'Unknown BMP subtype (or not a BMP file)';
|
||||
$this->error('Unknown BMP subtype (or not a BMP file)');
|
||||
unset($info['fileformat']);
|
||||
unset($info['bmp']);
|
||||
return false;
|
||||
|
@ -99,6 +98,7 @@ class getid3_bmp extends getid3_handler
|
|||
$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
|
||||
|
||||
|
@ -171,7 +171,9 @@ class getid3_bmp extends getid3_handler
|
|||
|
||||
$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
|
||||
|
@ -278,9 +280,12 @@ class getid3_bmp extends getid3_handler
|
|||
$thisfile_bmp_header_raw['reserved3'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
|
||||
$offset += 4;
|
||||
}
|
||||
|
||||
} else {
|
||||
$info['error'][] = 'Unknown BMP format in header.';
|
||||
|
||||
$this->error('Unknown BMP format in header.');
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -320,6 +325,7 @@ class getid3_bmp extends getid3_handler
|
|||
$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:
|
||||
|
@ -400,7 +406,7 @@ class getid3_bmp extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
|
||||
$this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data');
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -414,6 +420,7 @@ class getid3_bmp extends getid3_handler
|
|||
$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.
|
||||
|
@ -457,7 +464,9 @@ class getid3_bmp extends getid3_handler
|
|||
}
|
||||
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++) {
|
||||
|
@ -466,12 +475,13 @@ class getid3_bmp extends getid3_handler
|
|||
$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';
|
||||
$this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data');
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -486,6 +496,7 @@ class getid3_bmp extends getid3_handler
|
|||
$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.
|
||||
|
@ -535,7 +546,9 @@ class getid3_bmp extends getid3_handler
|
|||
}
|
||||
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.
|
||||
|
@ -551,12 +564,13 @@ class getid3_bmp extends getid3_handler
|
|||
$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';
|
||||
$this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data');
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -596,14 +610,14 @@ class getid3_bmp extends getid3_handler
|
|||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
|
||||
$this->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';
|
||||
$this->error('Unknown/unhandled compression type value ('.$thisfile_bmp_header_raw['compression'].') - cannot decompress pixel data');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -612,8 +626,7 @@ class getid3_bmp extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function PlotBMP(&$BMPinfo)
|
||||
{
|
||||
public function PlotBMP(&$BMPinfo) {
|
||||
$starttime = time();
|
||||
if (!isset($BMPinfo['bmp']['data']) || !is_array($BMPinfo['bmp']['data'])) {
|
||||
echo 'ERROR: no pixel data<BR>';
|
||||
|
@ -649,28 +662,27 @@ class getid3_bmp extends getid3_handler
|
|||
return false;
|
||||
}
|
||||
|
||||
public function BMPcompressionWindowsLookup($compressionid)
|
||||
{
|
||||
static $BMPcompressionWindowsLookup = [
|
||||
public 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');
|
||||
}
|
||||
|
||||
public function BMPcompressionOS2Lookup($compressionid)
|
||||
{
|
||||
static $BMPcompressionOS2Lookup = [
|
||||
public 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');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
class getid3_efax extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
@ -27,14 +26,14 @@ class getid3_efax extends getid3_handler
|
|||
|
||||
$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'];
|
||||
$this->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';
|
||||
$this->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");
|
||||
|
@ -43,9 +42,10 @@ class getid3_efax extends getid3_handler
|
|||
$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().']';
|
||||
$this->error('eFax parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
class getid3_gif extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'gif';
|
||||
|
@ -36,7 +35,7 @@ class getid3_gif extends getid3_handler
|
|||
|
||||
$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']).'"';
|
||||
$this->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;
|
||||
|
@ -110,7 +109,7 @@ class getid3_gif extends getid3_handler
|
|||
//
|
||||
// if ($ImageDescriptor['flags']['use_local_color_map']) {
|
||||
//
|
||||
// $info['warning'][] = 'This version of getID3() cannot parse local color maps for GIFs';
|
||||
// $this->warning('This version of getID3() cannot parse local color maps for GIFs');
|
||||
// return true;
|
||||
//
|
||||
// }
|
||||
|
@ -169,8 +168,7 @@ class getid3_gif extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function GetLSBits($bits)
|
||||
{
|
||||
public function GetLSBits($bits) {
|
||||
static $bitbuffer = '';
|
||||
while (strlen($bitbuffer) < $bits) {
|
||||
$bitbuffer = str_pad(decbin(ord($this->fread(1))), 8, '0', STR_PAD_LEFT).$bitbuffer;
|
||||
|
@ -180,4 +178,5 @@ class getid3_gif extends getid3_handler
|
|||
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,8 +20,7 @@ class getid3_jpg extends getid3_handler
|
|||
{
|
||||
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'jpg';
|
||||
|
@ -32,7 +31,7 @@ class getid3_jpg extends getid3_handler
|
|||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
||||
$imageinfo = [];
|
||||
$imageinfo = array();
|
||||
//list($width, $height, $type) = getid3_lib::GetDataImageSize($this->fread($info['filesize']), $imageinfo);
|
||||
list($width, $height, $type) = getimagesize($info['filenamepath'], $imageinfo); // http://www.getid3.org/phpBB3/viewtopic.php?t=1474
|
||||
|
||||
|
@ -51,7 +50,7 @@ class getid3_jpg extends getid3_handler
|
|||
if (isset($info['iptc']['comments'][$IPTCrecordName][$IPTCrecordTagName])) {
|
||||
$info['iptc']['comments'][$IPTCrecordName][$IPTCrecordTagName][] = $value;
|
||||
} else {
|
||||
$info['iptc']['comments'][$IPTCrecordName][$IPTCrecordTagName] = [$value];
|
||||
$info['iptc']['comments'][$IPTCrecordName][$IPTCrecordTagName] = array($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,14 +66,25 @@ class getid3_jpg extends getid3_handler
|
|||
if (isset($imageinfo['APP1'])) {
|
||||
if (function_exists('exif_read_data')) {
|
||||
if (substr($imageinfo['APP1'], 0, 4) == 'Exif') {
|
||||
//$info['warning'][] = 'known issue: https://bugs.php.net/bug.php?id=62523';
|
||||
//$this->warning('known issue: https://bugs.php.net/bug.php?id=62523');
|
||||
//return false;
|
||||
set_error_handler(function($errno, $errstr, $errfile, $errline, array $errcontext) {
|
||||
if (!(error_reporting() & $errno)) {
|
||||
// error is not specified in the error_reporting setting, so we ignore it
|
||||
return false;
|
||||
}
|
||||
|
||||
$errcontext['info']['warning'][] = 'Error parsing EXIF data ('.$errstr.')';
|
||||
});
|
||||
|
||||
$info['jpg']['exif'] = exif_read_data($info['filenamepath'], null, true, false);
|
||||
|
||||
restore_error_handler();
|
||||
} else {
|
||||
$info['warning'][] = 'exif_read_data() cannot parse non-EXIF data in APP1 (expected "Exif", found "'.substr($imageinfo['APP1'], 0, 4).'")';
|
||||
$this->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');
|
||||
$this->warning('EXIF parsing only available when '.(GETID3_OS_ISWINDOWS ? 'php_exif.dll enabled' : 'compiled with --enable-exif'));
|
||||
}
|
||||
}
|
||||
$returnOK = true;
|
||||
|
@ -85,7 +95,7 @@ class getid3_jpg extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
$cast_as_appropriate_keys = ['EXIF', 'IFD0', 'THUMBNAIL'];
|
||||
$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) {
|
||||
|
@ -96,6 +106,7 @@ class getid3_jpg extends getid3_handler
|
|||
|
||||
|
||||
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));
|
||||
|
@ -109,7 +120,7 @@ class getid3_jpg extends getid3_handler
|
|||
$computed_time[3] = (isset($explodedGPSDateStamp[1]) ? $explodedGPSDateStamp[1] : '');
|
||||
$computed_time[4] = (isset($explodedGPSDateStamp[2]) ? $explodedGPSDateStamp[2] : '');
|
||||
|
||||
$computed_time = [0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0];
|
||||
$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);
|
||||
|
@ -140,6 +151,7 @@ class getid3_jpg extends getid3_handler
|
|||
$direction_multiplier = (!empty($info['jpg']['exif']['GPS']['GPSAltitudeRef']) ? -1 : 1); // 0 = above sea level; 1 = below sea level
|
||||
$info['jpg']['exif']['GPS']['computed']['altitude'] = $direction_multiplier * getid3_lib::DecimalizeFraction($info['jpg']['exif']['GPS']['GPSAltitude']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -152,7 +164,7 @@ class getid3_jpg extends getid3_handler
|
|||
list($subsection, $tagname) = explode(':', $key);
|
||||
$info['xmp'][$subsection][$tagname] = $this->CastAsAppropriate($value);
|
||||
} else {
|
||||
$info['warning'][] = 'XMP: expecting "<subsection>:<tagname>", found "'.$key.'"';
|
||||
$this->warning('XMP: expecting "<subsection>:<tagname>", found "'.$key.'"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,8 +177,7 @@ class getid3_jpg extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function CastAsAppropriate($value)
|
||||
{
|
||||
public function CastAsAppropriate($value) {
|
||||
if (is_array($value)) {
|
||||
return $value;
|
||||
} elseif (preg_match('#^[0-9]+/[0-9]+$#', $value)) {
|
||||
|
@ -180,31 +191,29 @@ class getid3_jpg extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function IPTCrecordName($iptc_record)
|
||||
{
|
||||
public function IPTCrecordName($iptc_record) {
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
|
||||
static $IPTCrecordName = [];
|
||||
static $IPTCrecordName = array();
|
||||
if (empty($IPTCrecordName)) {
|
||||
$IPTCrecordName = [
|
||||
$IPTCrecordName = array(
|
||||
1 => 'IPTCEnvelope',
|
||||
2 => 'IPTCApplication',
|
||||
3 => 'IPTCNewsPhoto',
|
||||
7 => 'IPTCPreObjectData',
|
||||
8 => 'IPTCObjectData',
|
||||
9 => 'IPTCPostObjectData',
|
||||
];
|
||||
);
|
||||
}
|
||||
return (isset($IPTCrecordName[$iptc_record]) ? $IPTCrecordName[$iptc_record] : '');
|
||||
}
|
||||
|
||||
|
||||
public function IPTCrecordTagName($iptc_record, $iptc_tagkey)
|
||||
{
|
||||
public function IPTCrecordTagName($iptc_record, $iptc_tagkey) {
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
|
||||
static $IPTCrecordTagName = [];
|
||||
static $IPTCrecordTagName = array();
|
||||
if (empty($IPTCrecordTagName)) {
|
||||
$IPTCrecordTagName = [
|
||||
1 => [ // IPTC EnvelopeRecord Tags
|
||||
$IPTCrecordTagName = array(
|
||||
1 => array( // IPTC EnvelopeRecord Tags
|
||||
0 => 'EnvelopeRecordVersion',
|
||||
5 => 'Destination',
|
||||
20 => 'FileFormat',
|
||||
|
@ -219,8 +228,8 @@ class getid3_jpg extends getid3_handler
|
|||
100 => 'UniqueObjectName',
|
||||
120 => 'ARMIdentifier',
|
||||
122 => 'ARMVersion',
|
||||
],
|
||||
2 => [ // IPTC ApplicationRecord Tags
|
||||
),
|
||||
2 => array( // IPTC ApplicationRecord Tags
|
||||
0 => 'ApplicationRecordVersion',
|
||||
3 => 'ObjectTypeReference',
|
||||
4 => 'ObjectAttributeReference',
|
||||
|
@ -290,8 +299,8 @@ class getid3_jpg extends getid3_handler
|
|||
230 => 'DocumentNotes',
|
||||
231 => 'DocumentHistory',
|
||||
232 => 'ExifCameraInfo',
|
||||
],
|
||||
3 => [ // IPTC NewsPhoto Tags
|
||||
),
|
||||
3 => array( // IPTC NewsPhoto Tags
|
||||
0 => 'NewsPhotoVersion',
|
||||
10 => 'IPTCPictureNumber',
|
||||
20 => 'IPTCImageWidth',
|
||||
|
@ -318,21 +327,23 @@ class getid3_jpg extends getid3_handler
|
|||
135 => 'BitsPerComponent',
|
||||
140 => 'MaximumDensityRange',
|
||||
145 => 'GammaCompensatedValue',
|
||||
],
|
||||
7 => [ // IPTC PreObjectData Tags
|
||||
),
|
||||
7 => array( // IPTC PreObjectData Tags
|
||||
10 => 'SizeMode',
|
||||
20 => 'MaxSubfileSize',
|
||||
90 => 'ObjectSizeAnnounced',
|
||||
95 => 'MaximumObjectSize',
|
||||
],
|
||||
8 => [ // IPTC ObjectData Tags
|
||||
),
|
||||
8 => array( // IPTC ObjectData Tags
|
||||
10 => 'SubFile',
|
||||
],
|
||||
9 => [ // IPTC PostObjectData Tags
|
||||
),
|
||||
9 => array( // IPTC PostObjectData Tags
|
||||
10 => 'ConfirmedObjectSize',
|
||||
],
|
||||
];
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
return (isset($IPTCrecordTagName[$iptc_record][$iptc_tagkey]) ? $IPTCrecordTagName[$iptc_record][$iptc_tagkey] : $iptc_tagkey);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,8 +19,7 @@ class getid3_pcd extends getid3_handler
|
|||
{
|
||||
public $ExtractData = 0;
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'pcd';
|
||||
|
@ -44,11 +43,14 @@ class getid3_pcd extends getid3_handler
|
|||
|
||||
|
||||
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.';
|
||||
|
||||
$this->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] = [ 192, 128, 0x02000]; // BASE/16
|
||||
$PCD_levels[2] = [ 384, 256, 0x0B800]; // BASE/4
|
||||
$PCD_levels[3] = [ 768, 512, 0x30000]; // BASE
|
||||
|
||||
$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
|
||||
|
@ -92,12 +94,13 @@ class getid3_pcd extends getid3_handler
|
|||
//$BMPinfo['bmp']['data'] = $info['pcd']['data'];
|
||||
//getid3_bmp::PlotBMP($BMPinfo);
|
||||
//exit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function YCbCr2RGB($Y, $Cb, $Cr)
|
||||
{
|
||||
static $YCbCr_constants = [];
|
||||
}
|
||||
|
||||
public 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;
|
||||
|
@ -110,12 +113,10 @@ class getid3_pcd extends getid3_handler
|
|||
$YCbCr_constants['blue']['Cr'] = 0.0000000 * 256;
|
||||
}
|
||||
|
||||
$RGBcolor = ['red'=>0, 'green'=>0, 'blue'=>0];
|
||||
$RGBcolor = array('red'=>0, 'green'=>0, 'blue'=>0);
|
||||
foreach ($RGBcolor as $rgbname => $dummy) {
|
||||
$RGBcolor[$rgbname] = max(
|
||||
0,
|
||||
min(
|
||||
255,
|
||||
$RGBcolor[$rgbname] = max(0,
|
||||
min(255,
|
||||
intval(
|
||||
round(
|
||||
($YCbCr_constants[$rgbname]['Y'] * $Y) +
|
||||
|
@ -128,4 +129,5 @@ class getid3_pcd extends getid3_handler
|
|||
}
|
||||
return (($RGBcolor['red'] * 65536) + ($RGBcolor['green'] * 256) + $RGBcolor['blue']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,13 +19,12 @@ class getid3_png extends getid3_handler
|
|||
{
|
||||
public $max_data_bytes = 10000000; // if data chunk is larger than this do not read it completely (getID3 only needs the first few dozen bytes for parsing)
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// shortcut
|
||||
$info['png'] = [];
|
||||
$info['png'] = array();
|
||||
$thisfile_png = &$info['png'];
|
||||
|
||||
$info['fileformat'] = 'png';
|
||||
|
@ -40,7 +39,7 @@ class getid3_png extends getid3_handler
|
|||
$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';
|
||||
$this->error('First 8 bytes of file ('.getid3_lib::PrintHexBytes($PNGidentifier).') did not match expected PNG identifier');
|
||||
unset($info['fileformat']);
|
||||
return false;
|
||||
}
|
||||
|
@ -48,7 +47,7 @@ class getid3_png extends getid3_handler
|
|||
while ((($this->ftell() - (strlen($PNGfiledata) - $offset)) < $info['filesize'])) {
|
||||
$chunk['data_length'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4));
|
||||
if ($chunk['data_length'] === false) {
|
||||
$info['error'][] = 'Failed to read data_length at offset '.$offset;
|
||||
$this->error('Failed to read data_length at offset '.$offset);
|
||||
return false;
|
||||
}
|
||||
$offset += 4;
|
||||
|
@ -57,7 +56,7 @@ class getid3_png extends getid3_handler
|
|||
if (strlen($PNGfiledata) < $this->max_data_bytes) {
|
||||
$PNGfiledata .= $this->fread($this->getid3->fread_buffer_size());
|
||||
} else {
|
||||
$info['warning'][] = 'At offset '.$offset.' chunk "'.substr($PNGfiledata, $offset, 4).'" exceeded max_data_bytes value of '.$this->max_data_bytes.', data chunk will be truncated at '.(strlen($PNGfiledata) - 8).' bytes';
|
||||
$this->warning('At offset '.$offset.' chunk "'.substr($PNGfiledata, $offset, 4).'" exceeded max_data_bytes value of '.$this->max_data_bytes.', data chunk will be truncated at '.(strlen($PNGfiledata) - 8).' bytes');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -75,10 +74,11 @@ class getid3_png extends getid3_handler
|
|||
$chunk['flags']['safe_to_copy'] = (bool) ($chunk['type_raw'] & 0x00000020);
|
||||
|
||||
// shortcut
|
||||
$thisfile_png[$chunk['type_text']] = [];
|
||||
$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));
|
||||
|
@ -137,10 +137,10 @@ class getid3_png extends getid3_handler
|
|||
|
||||
case 4:
|
||||
case 6:
|
||||
$info['error'][] = 'Invalid color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type'];
|
||||
$this->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'];
|
||||
$this->warning('Unhandled color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type']);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -228,6 +228,7 @@ class getid3_png extends getid3_handler
|
|||
$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);
|
||||
|
@ -237,8 +238,11 @@ class getid3_png extends getid3_handler
|
|||
// unknown compression method
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$thisfile_png_chunk_type_text['text'] = $text;
|
||||
|
||||
}
|
||||
|
||||
if (isset($thisfile_png_chunk_type_text['text'])) {
|
||||
|
@ -439,7 +443,7 @@ class getid3_png extends getid3_handler
|
|||
default:
|
||||
//unset($chunk['data']);
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
$info['warning'][] = 'Unhandled chunk type: '.$chunk['type_text'];
|
||||
$this->warning('Unhandled chunk type: '.$chunk['type_text']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -447,65 +451,58 @@ class getid3_png extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function PNGsRGBintentLookup($sRGB)
|
||||
{
|
||||
static $PNGsRGBintentLookup = [
|
||||
public function PNGsRGBintentLookup($sRGB) {
|
||||
static $PNGsRGBintentLookup = array(
|
||||
0 => 'Perceptual',
|
||||
1 => 'Relative colorimetric',
|
||||
2 => 'Saturation',
|
||||
3 => 'Absolute colorimetric'
|
||||
];
|
||||
);
|
||||
return (isset($PNGsRGBintentLookup[$sRGB]) ? $PNGsRGBintentLookup[$sRGB] : 'invalid');
|
||||
}
|
||||
|
||||
public function PNGcompressionMethodLookup($compressionmethod)
|
||||
{
|
||||
static $PNGcompressionMethodLookup = [
|
||||
public function PNGcompressionMethodLookup($compressionmethod) {
|
||||
static $PNGcompressionMethodLookup = array(
|
||||
0 => 'deflate/inflate'
|
||||
];
|
||||
);
|
||||
return (isset($PNGcompressionMethodLookup[$compressionmethod]) ? $PNGcompressionMethodLookup[$compressionmethod] : 'invalid');
|
||||
}
|
||||
|
||||
public function PNGpHYsUnitLookup($unitid)
|
||||
{
|
||||
static $PNGpHYsUnitLookup = [
|
||||
public function PNGpHYsUnitLookup($unitid) {
|
||||
static $PNGpHYsUnitLookup = array(
|
||||
0 => 'unknown',
|
||||
1 => 'meter'
|
||||
];
|
||||
);
|
||||
return (isset($PNGpHYsUnitLookup[$unitid]) ? $PNGpHYsUnitLookup[$unitid] : 'invalid');
|
||||
}
|
||||
|
||||
public function PNGoFFsUnitLookup($unitid)
|
||||
{
|
||||
static $PNGoFFsUnitLookup = [
|
||||
public function PNGoFFsUnitLookup($unitid) {
|
||||
static $PNGoFFsUnitLookup = array(
|
||||
0 => 'pixel',
|
||||
1 => 'micrometer'
|
||||
];
|
||||
);
|
||||
return (isset($PNGoFFsUnitLookup[$unitid]) ? $PNGoFFsUnitLookup[$unitid] : 'invalid');
|
||||
}
|
||||
|
||||
public function PNGpCALequationTypeLookup($equationtype)
|
||||
{
|
||||
static $PNGpCALequationTypeLookup = [
|
||||
public 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');
|
||||
}
|
||||
|
||||
public function PNGsCALUnitLookup($unitid)
|
||||
{
|
||||
static $PNGsCALUnitLookup = [
|
||||
public function PNGsCALUnitLookup($unitid) {
|
||||
static $PNGsCALUnitLookup = array(
|
||||
0 => 'meter',
|
||||
1 => 'radian'
|
||||
];
|
||||
);
|
||||
return (isset($PNGsCALUnitLookup[$unitid]) ? $PNGsCALUnitLookup[$unitid] : 'invalid');
|
||||
}
|
||||
|
||||
public function IHDRcalculateBitsPerSample($color_type, $bit_depth)
|
||||
{
|
||||
public function IHDRcalculateBitsPerSample($color_type, $bit_depth) {
|
||||
switch ($color_type) {
|
||||
case 0: // Each pixel is a grayscale sample.
|
||||
return $bit_depth;
|
||||
|
@ -529,4 +526,5 @@ class getid3_png extends getid3_handler
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,8 +19,7 @@ class getid3_svg extends getid3_handler
|
|||
{
|
||||
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
@ -36,12 +35,13 @@ class getid3_svg extends getid3_handler
|
|||
$info['svg']['svg']['raw'] = $matches;
|
||||
}
|
||||
if (isset($info['svg']['svg']['raw'])) {
|
||||
$sections_to_fix = ['xml', 'doctype', 'svg'];
|
||||
|
||||
$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 = [];
|
||||
$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]);
|
||||
|
@ -95,7 +95,8 @@ class getid3_svg extends getid3_handler
|
|||
|
||||
return true;
|
||||
}
|
||||
$info['error'][] = 'Did not find expected <svg> tag';
|
||||
$this->error('Did not find expected <svg> tag');
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
class getid3_tiff extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
@ -33,7 +32,7 @@ class getid3_tiff extends getid3_handler
|
|||
$info['tiff']['byte_order'] = 'Motorola';
|
||||
break;
|
||||
default:
|
||||
$info['error'][] = 'Invalid TIFF byte order identifier ('.substr($TIFFheader, 0, 2).') at offset '.$info['avdataoffset'];
|
||||
$this->error('Invalid TIFF byte order identifier ('.substr($TIFFheader, 0, 2).') at offset '.$info['avdataoffset']);
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
@ -41,14 +40,15 @@ class getid3_tiff extends getid3_handler
|
|||
$info['fileformat'] = 'tiff';
|
||||
$info['video']['dataformat'] = 'tiff';
|
||||
$info['video']['lossless'] = true;
|
||||
$info['tiff']['ifd'] = [];
|
||||
$CurrentIFD = [];
|
||||
$info['tiff']['ifd'] = array();
|
||||
$CurrentIFD = array();
|
||||
|
||||
$FieldTypeByteLength = [1=>1, 2=>1, 3=>2, 4=>4, 5=>8];
|
||||
$FieldTypeByteLength = array(1=>1, 2=>1, 3=>2, 4=>4, 5=>8);
|
||||
|
||||
$nextIFDoffset = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
|
||||
|
||||
while ($nextIFDoffset > 0) {
|
||||
|
||||
$CurrentIFD['offset'] = $nextIFDoffset;
|
||||
|
||||
$this->fseek($info['avdataoffset'] + $nextIFDoffset);
|
||||
|
@ -99,8 +99,9 @@ class getid3_tiff extends getid3_handler
|
|||
}
|
||||
|
||||
$info['tiff']['ifd'][] = $CurrentIFD;
|
||||
$CurrentIFD = [];
|
||||
$CurrentIFD = array();
|
||||
$nextIFDoffset = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
|
||||
|
||||
}
|
||||
|
||||
foreach ($info['tiff']['ifd'] as $IFDid => $IFDarray) {
|
||||
|
@ -113,6 +114,7 @@ class getid3_tiff extends getid3_handler
|
|||
if (!isset($fieldarray['value'])) {
|
||||
$this->fseek($fieldarray['offset']);
|
||||
$info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $this->fread($fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -128,6 +130,7 @@ class getid3_tiff extends getid3_handler
|
|||
} else {
|
||||
$this->fseek($fieldarray['offset']);
|
||||
$info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $this->fread($fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -166,7 +169,7 @@ class getid3_tiff extends getid3_handler
|
|||
if (isset($info['tiff']['comments'][$TIFFcommentName])) {
|
||||
$info['tiff']['comments'][$TIFFcommentName][] = $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'];
|
||||
} else {
|
||||
$info['tiff']['comments'][$TIFFcommentName] = [$info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data']];
|
||||
$info['tiff']['comments'][$TIFFcommentName] = array($info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data']);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -180,8 +183,7 @@ class getid3_tiff extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function TIFFendian2Int($bytestring, $byteorder)
|
||||
{
|
||||
public function TIFFendian2Int($bytestring, $byteorder) {
|
||||
if ($byteorder == 'Intel') {
|
||||
return getid3_lib::LittleEndian2Int($bytestring);
|
||||
} elseif ($byteorder == 'Motorola') {
|
||||
|
@ -190,26 +192,24 @@ class getid3_tiff extends getid3_handler
|
|||
return false;
|
||||
}
|
||||
|
||||
public function TIFFcompressionMethod($id)
|
||||
{
|
||||
static $TIFFcompressionMethod = [];
|
||||
public function TIFFcompressionMethod($id) {
|
||||
static $TIFFcompressionMethod = array();
|
||||
if (empty($TIFFcompressionMethod)) {
|
||||
$TIFFcompressionMethod = [
|
||||
$TIFFcompressionMethod = array(
|
||||
1 => 'Uncompressed',
|
||||
2 => 'Huffman',
|
||||
3 => 'Fax - CCITT 3',
|
||||
5 => 'LZW',
|
||||
32773 => 'PackBits',
|
||||
];
|
||||
);
|
||||
}
|
||||
return (isset($TIFFcompressionMethod[$id]) ? $TIFFcompressionMethod[$id] : 'unknown/invalid ('.$id.')');
|
||||
}
|
||||
|
||||
public function TIFFcommentName($id)
|
||||
{
|
||||
static $TIFFcommentName = [];
|
||||
public function TIFFcommentName($id) {
|
||||
static $TIFFcommentName = array();
|
||||
if (empty($TIFFcommentName)) {
|
||||
$TIFFcommentName = [
|
||||
$TIFFcommentName = array(
|
||||
270 => 'imagedescription',
|
||||
271 => 'make',
|
||||
272 => 'model',
|
||||
|
@ -217,8 +217,9 @@ class getid3_tiff extends getid3_handler
|
|||
306 => 'datetime',
|
||||
315 => 'artist',
|
||||
316 => 'hostcomputer',
|
||||
];
|
||||
);
|
||||
}
|
||||
return (isset($TIFFcommentName[$id]) ? $TIFFcommentName[$id] : 'unknown/invalid ('.$id.')');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,10 +33,9 @@
|
|||
*/
|
||||
class getid3_cue extends getid3_handler
|
||||
{
|
||||
public $cuesheet = [];
|
||||
public $cuesheet = array();
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'cue';
|
||||
|
@ -59,9 +58,11 @@ class getid3_cue extends getid3_handler
|
|||
*/
|
||||
public function readCueSheet(&$filedata)
|
||||
{
|
||||
$cue_lines = [];
|
||||
foreach (explode("\n", str_replace("\r", null, $filedata)) as $line) {
|
||||
if ((strlen($line) > 0) && ($line[0] != '#')) {
|
||||
$cue_lines = array();
|
||||
foreach (explode("\n", str_replace("\r", null, $filedata)) as $line)
|
||||
{
|
||||
if ( (strlen($line) > 0) && ($line[0] != '#'))
|
||||
{
|
||||
$cue_lines[] = trim($line);
|
||||
}
|
||||
}
|
||||
|
@ -80,9 +81,11 @@ class getid3_cue extends getid3_handler
|
|||
//-1 means still global, all others are track specific
|
||||
$track_on = -1;
|
||||
|
||||
for ($i=0; $i < count($file); $i++) {
|
||||
for ($i=0; $i < count($file); $i++)
|
||||
{
|
||||
list($key) = explode(' ', strtolower($file[$i]), 2);
|
||||
switch ($key) {
|
||||
switch ($key)
|
||||
{
|
||||
case 'catalog':
|
||||
case 'cdtextfile':
|
||||
case 'isrc':
|
||||
|
@ -108,7 +111,8 @@ class getid3_cue extends getid3_handler
|
|||
case 'track':
|
||||
$track_on++;
|
||||
$this->parseTrack($file[$i], $track_on);
|
||||
if (isset($currentFile)) { // if there's a file
|
||||
if (isset($currentFile)) // if there's a file
|
||||
{
|
||||
$this->cuesheet['tracks'][$track_on]['datafile'] = $currentFile;
|
||||
}
|
||||
break;
|
||||
|
@ -160,7 +164,7 @@ class getid3_cue extends getid3_handler
|
|||
//if quotes around it, remove them.
|
||||
$line = trim($line, '"');
|
||||
|
||||
return ['filename'=>$line, 'type'=>$type];
|
||||
return array('filename'=>$line, 'type'=>$type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -171,18 +175,21 @@ class getid3_cue extends getid3_handler
|
|||
*/
|
||||
public function parseFlags($line, $track_on)
|
||||
{
|
||||
if ($track_on != -1) {
|
||||
foreach (explode(' ', strtolower($line)) as $type) {
|
||||
switch ($type) {
|
||||
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'] = [
|
||||
$this->cuesheet['tracks'][$track_on]['flags'] = array(
|
||||
'4ch' => false,
|
||||
'data' => false,
|
||||
'dcp' => false,
|
||||
'pre' => false,
|
||||
'scms' => false,
|
||||
];
|
||||
);
|
||||
break;
|
||||
case 'data':
|
||||
case 'dcp':
|
||||
|
@ -206,10 +213,14 @@ class getid3_cue extends getid3_handler
|
|||
*/
|
||||
public function parseGarbage($line, $track_on)
|
||||
{
|
||||
if (strlen($line) > 0) {
|
||||
if ($track_on == -1) {
|
||||
if ( strlen($line) > 0 )
|
||||
{
|
||||
if ($track_on == -1)
|
||||
{
|
||||
$this->cuesheet['garbage'][] = $line;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->cuesheet['tracks'][$track_on]['garbage'][] = $line;
|
||||
}
|
||||
}
|
||||
|
@ -226,7 +237,8 @@ class getid3_cue extends getid3_handler
|
|||
$type = strtolower(substr($line, 0, strpos($line, ' ')));
|
||||
$line = substr($line, strpos($line, ' ') + 1);
|
||||
|
||||
if ($type == 'index') {
|
||||
if ($type == 'index')
|
||||
{
|
||||
//read the index number
|
||||
$number = intval(substr($line, 0, strpos($line, ' ')));
|
||||
$line = substr($line, strpos($line, ' ') + 1);
|
||||
|
@ -240,11 +252,11 @@ class getid3_cue extends getid3_handler
|
|||
|
||||
switch ($type) {
|
||||
case 'index':
|
||||
$this->cuesheet['tracks'][$track_on][$type][$number] = ['minutes'=>intval($minutes), 'seconds'=>intval($seconds), 'frames'=>intval($frames)];
|
||||
$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] = ['minutes'=>intval($minutes), 'seconds'=>intval($seconds), 'frames'=>intval($frames)];
|
||||
$this->cuesheet['tracks'][$track_on][$type] = array('minutes'=>intval($minutes), 'seconds'=>intval($seconds), 'frames'=>intval($frames));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -257,16 +269,20 @@ class getid3_cue extends getid3_handler
|
|||
//get rid of the quotes
|
||||
$line = trim($line, '"');
|
||||
|
||||
switch ($category) {
|
||||
switch ($category)
|
||||
{
|
||||
case 'catalog':
|
||||
case 'cdtextfile':
|
||||
case 'isrc':
|
||||
case 'performer':
|
||||
case 'songwriter':
|
||||
case 'title':
|
||||
if ($track_on == -1) {
|
||||
if ($track_on == -1)
|
||||
{
|
||||
$this->cuesheet[$category] = $line;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->cuesheet['tracks'][$track_on][$category] = $line;
|
||||
}
|
||||
break;
|
||||
|
@ -289,6 +305,8 @@ class getid3_cue extends getid3_handler
|
|||
//find the data type.
|
||||
$datatype = strtolower(substr($line, strpos($line, ' ') + 1));
|
||||
|
||||
$this->cuesheet['tracks'][$track_on] = ['track_number'=>$track, 'datatype'=>$datatype];
|
||||
$this->cuesheet['tracks'][$track_on] = array('track_number'=>$track, 'datatype'=>$datatype);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
class getid3_exe extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
|
@ -27,7 +26,7 @@ class getid3_exe extends getid3_handler
|
|||
|
||||
$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)).'"';
|
||||
$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($EXEheader, 0, 2)).'"');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -52,7 +51,9 @@ class getid3_exe extends getid3_handler
|
|||
$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().']';
|
||||
$this->error('EXE parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
class getid3_iso extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'iso';
|
||||
|
@ -48,7 +47,7 @@ class getid3_iso extends getid3_handler
|
|||
|
||||
$this->ParsePathTable();
|
||||
|
||||
$info['iso']['files'] = [];
|
||||
$info['iso']['files'] = array();
|
||||
foreach ($info['iso']['path_table']['directories'] as $directorynum => $directorydata) {
|
||||
$info['iso']['directories'][$directorynum] = $this->ParseDirectoryRecord($directorydata);
|
||||
}
|
||||
|
@ -57,21 +56,20 @@ class getid3_iso extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function ParsePrimaryVolumeDescriptor(&$ISOheader)
|
||||
{
|
||||
public 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'] = [];
|
||||
$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';
|
||||
$this->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;
|
||||
|
@ -125,28 +123,27 @@ class getid3_iso extends getid3_handler
|
|||
$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?)';
|
||||
$this->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;
|
||||
}
|
||||
|
||||
|
||||
public function ParseSupplementaryVolumeDescriptor(&$ISOheader)
|
||||
{
|
||||
public 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'] = [];
|
||||
$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';
|
||||
$this->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;
|
||||
|
@ -205,15 +202,14 @@ class getid3_iso extends getid3_handler
|
|||
$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?)';
|
||||
$this->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;
|
||||
}
|
||||
|
||||
|
||||
public function ParsePathTable()
|
||||
{
|
||||
public 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;
|
||||
|
@ -229,7 +225,7 @@ class getid3_iso extends getid3_handler
|
|||
}
|
||||
|
||||
if (($PathTableLocation * 2048) > $info['filesize']) {
|
||||
$info['error'][] = 'Path Table Location specifies an offset ('.($PathTableLocation * 2048).') beyond the end-of-file ('.$info['filesize'].')';
|
||||
$this->error('Path Table Location specifies an offset ('.($PathTableLocation * 2048).') beyond the end-of-file ('.$info['filesize'].')');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -241,7 +237,7 @@ class getid3_iso extends getid3_handler
|
|||
$pathcounter = 1;
|
||||
while ($offset < $PathTableSize) {
|
||||
// shortcut
|
||||
$info['iso']['path_table']['directories'][$pathcounter] = [];
|
||||
$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));
|
||||
|
@ -272,8 +268,7 @@ class getid3_iso extends getid3_handler
|
|||
}
|
||||
|
||||
|
||||
public function ParseDirectoryRecord($directorydata)
|
||||
{
|
||||
public function ParseDirectoryRecord($directorydata) {
|
||||
$info = &$this->getid3->info;
|
||||
if (isset($info['iso']['supplementary_volume_descriptor'])) {
|
||||
$TextEncoding = 'UTF-16BE'; // Big-Endian Unicode
|
||||
|
@ -285,6 +280,7 @@ class getid3_iso extends getid3_handler
|
|||
$DirectoryRecordData = $this->fread(1);
|
||||
|
||||
while (ord($DirectoryRecordData{0}) > 33) {
|
||||
|
||||
$DirectoryRecordData .= $this->fread(ord($DirectoryRecordData{0}) - 1);
|
||||
|
||||
$ThisDirectoryRecord['raw']['length'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 0, 1));
|
||||
|
@ -325,8 +321,7 @@ class getid3_iso extends getid3_handler
|
|||
return $DirectoryRecord;
|
||||
}
|
||||
|
||||
public function ISOstripFilenameVersion($ISOfilename)
|
||||
{
|
||||
public function ISOstripFilenameVersion($ISOfilename) {
|
||||
// convert 'filename.ext;1' to 'filename.ext'
|
||||
if (!strstr($ISOfilename, ';')) {
|
||||
return $ISOfilename;
|
||||
|
@ -335,8 +330,7 @@ class getid3_iso extends getid3_handler
|
|||
}
|
||||
}
|
||||
|
||||
public function ISOtimeText2UNIXtime($ISOtime)
|
||||
{
|
||||
public function ISOtimeText2UNIXtime($ISOtime) {
|
||||
|
||||
$UNIXyear = (int) substr($ISOtime, 0, 4);
|
||||
$UNIXmonth = (int) substr($ISOtime, 4, 2);
|
||||
|
@ -351,8 +345,7 @@ class getid3_iso extends getid3_handler
|
|||
return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
|
||||
}
|
||||
|
||||
public function ISOtime2UNIXtime($ISOtime)
|
||||
{
|
||||
public function ISOtime2UNIXtime($ISOtime) {
|
||||
// Represented by seven bytes:
|
||||
// 1: Number of years since 1900
|
||||
// 2: Month of the year from 1 to 12
|
||||
|
@ -373,8 +366,7 @@ class getid3_iso extends getid3_handler
|
|||
return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
|
||||
}
|
||||
|
||||
public function TwosCompliment2Decimal($BinaryValue)
|
||||
{
|
||||
public 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.
|
||||
|
@ -383,6 +375,7 @@ class getid3_iso extends getid3_handler
|
|||
// The negative of this number is the value of the original binary.
|
||||
|
||||
if ($BinaryValue & 0x80) {
|
||||
|
||||
// negative number
|
||||
return (0 - ((~$BinaryValue & 0xFF) + 1));
|
||||
} else {
|
||||
|
@ -390,4 +383,6 @@ class getid3_iso extends getid3_handler
|
|||
return $BinaryValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -18,20 +18,21 @@
|
|||
class getid3_msoffice extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$this->fseek($info['avdataoffset']);
|
||||
$DOCFILEheader = $this->fread(8);
|
||||
$magic = "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1";
|
||||
if (substr($DOCFILEheader, 0, 8) != $magic) {
|
||||
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($DOCFILEheader, 0, 8)).' instead.';
|
||||
$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($DOCFILEheader, 0, 8)).' instead.');
|
||||
return false;
|
||||
}
|
||||
$info['fileformat'] = 'msoffice';
|
||||
|
||||
$info['error'][] = 'MS Office (.doc, .xls, etc) parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
|
||||
$this->error('MS Office (.doc, .xls, etc) parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,13 +18,14 @@
|
|||
class getid3_par2 extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'par2';
|
||||
|
||||
$info['error'][] = 'PAR2 parsing not enabled in this version of getID3()';
|
||||
$this->error('PAR2 parsing not enabled in this version of getID3()');
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,13 +18,14 @@
|
|||
class getid3_pdf extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
$info['fileformat'] = 'pdf';
|
||||
|
||||
$info['error'][] = 'PDF parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
|
||||
$this->error('PDF parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,12 +19,11 @@ class getid3_apetag extends getid3_handler
|
|||
public $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
|
||||
public $overrideendoffset = 0;
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
if (!getid3_lib::intValueSupported($info['filesize'])) {
|
||||
$info['warning'][] = 'Unable to check for APEtags because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
|
||||
$this->warning('Unable to check for APEtags because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -33,29 +32,38 @@ class getid3_apetag extends getid3_handler
|
|||
$lyrics3tagsize = 10;
|
||||
|
||||
if ($this->overrideendoffset == 0) {
|
||||
|
||||
$this->fseek(0 - $id3v1tagsize - $apetagheadersize - $lyrics3tagsize, SEEK_END);
|
||||
$APEfooterID3v1 = $this->fread($id3v1tagsize + $apetagheadersize + $lyrics3tagsize);
|
||||
|
||||
//if (preg_match('/APETAGEX.{24}TAG.{125}$/i', $APEfooterID3v1)) {
|
||||
if (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $id3v1tagsize - $apetagheadersize, 8) == 'APETAGEX') {
|
||||
|
||||
// APE tag found before ID3v1
|
||||
$info['ape']['tag_offset_end'] = $info['filesize'] - $id3v1tagsize;
|
||||
|
||||
//} elseif (preg_match('/APETAGEX.{24}$/i', $APEfooterID3v1)) {
|
||||
} elseif (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $apetagheadersize, 8) == 'APETAGEX') {
|
||||
|
||||
// APE tag found, no ID3v1
|
||||
$info['ape']['tag_offset_end'] = $info['filesize'];
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$this->fseek($this->overrideendoffset - $apetagheadersize);
|
||||
if ($this->fread(8) == 'APETAGEX') {
|
||||
$info['ape']['tag_offset_end'] = $this->overrideendoffset;
|
||||
}
|
||||
|
||||
}
|
||||
if (!isset($info['ape']['tag_offset_end'])) {
|
||||
|
||||
// APE tag not found
|
||||
unset($info['ape']);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// shortcut
|
||||
|
@ -64,7 +72,7 @@ class getid3_apetag extends getid3_handler
|
|||
$this->fseek($thisfile_ape['tag_offset_end'] - $apetagheadersize);
|
||||
$APEfooterData = $this->fread(32);
|
||||
if (!($thisfile_ape['footer'] = $this->parseAPEheaderFooter($APEfooterData))) {
|
||||
$info['error'][] = 'Error parsing APE footer at offset '.$thisfile_ape['tag_offset_end'];
|
||||
$this->error('Error parsing APE footer at offset '.$thisfile_ape['tag_offset_end']);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -80,7 +88,7 @@ class getid3_apetag extends getid3_handler
|
|||
$info['avdataend'] = $thisfile_ape['tag_offset_start'];
|
||||
|
||||
if (isset($info['id3v1']['tag_offset_start']) && ($info['id3v1']['tag_offset_start'] < $thisfile_ape['tag_offset_end'])) {
|
||||
$info['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in APEtag data';
|
||||
$this->warning('ID3v1 tag information ignored since it appears to be a false synch in APEtag data');
|
||||
unset($info['id3v1']);
|
||||
foreach ($info['warning'] as $key => $value) {
|
||||
if ($value == 'Some ID3v1 fields do not use NULL characters for padding') {
|
||||
|
@ -96,13 +104,13 @@ class getid3_apetag extends getid3_handler
|
|||
if ($thisfile_ape['header'] = $this->parseAPEheaderFooter(substr($APEtagData, 0, $apetagheadersize))) {
|
||||
$offset += $apetagheadersize;
|
||||
} else {
|
||||
$info['error'][] = 'Error parsing APE header at offset '.$thisfile_ape['tag_offset_start'];
|
||||
$this->error('Error parsing APE header at offset '.$thisfile_ape['tag_offset_start']);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// shortcut
|
||||
$info['replay_gain'] = [];
|
||||
$info['replay_gain'] = array();
|
||||
$thisfile_replaygain = &$info['replay_gain'];
|
||||
|
||||
for ($i = 0; $i < $thisfile_ape['footer']['raw']['tag_items']; $i++) {
|
||||
|
@ -111,14 +119,14 @@ class getid3_apetag extends getid3_handler
|
|||
$item_flags = getid3_lib::LittleEndian2Int(substr($APEtagData, $offset, 4));
|
||||
$offset += 4;
|
||||
if (strstr(substr($APEtagData, $offset), "\x00") === false) {
|
||||
$info['error'][] = 'Cannot find null-byte (0x00) seperator between ItemKey #'.$i.' and value. ItemKey starts '.$offset.' bytes into the APE tag, at file offset '.($thisfile_ape['tag_offset_start'] + $offset);
|
||||
$this->error('Cannot find null-byte (0x00) separator between ItemKey #'.$i.' and value. ItemKey starts '.$offset.' bytes into the APE tag, at file offset '.($thisfile_ape['tag_offset_start'] + $offset));
|
||||
return false;
|
||||
}
|
||||
$ItemKeyLength = strpos($APEtagData, "\x00", $offset) - $offset;
|
||||
$item_key = strtolower(substr($APEtagData, $offset, $ItemKeyLength));
|
||||
|
||||
// shortcut
|
||||
$thisfile_ape['items'][$item_key] = [];
|
||||
$thisfile_ape['items'][$item_key] = array();
|
||||
$thisfile_ape_items_current = &$thisfile_ape['items'][$item_key];
|
||||
|
||||
$thisfile_ape_items_current['offset'] = $thisfile_ape['tag_offset_start'] + $offset;
|
||||
|
@ -146,7 +154,7 @@ class getid3_apetag extends getid3_handler
|
|||
$thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
|
||||
$thisfile_replaygain['track']['originator'] = 'unspecified';
|
||||
} else {
|
||||
$info['warning'][] = 'MP3gainTrackGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';
|
||||
$this->warning('MP3gainTrackGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"');
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -155,10 +163,10 @@ class getid3_apetag extends getid3_handler
|
|||
$thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
|
||||
$thisfile_replaygain['track']['originator'] = 'unspecified';
|
||||
if ($thisfile_replaygain['track']['peak'] <= 0) {
|
||||
$info['warning'][] = 'ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")';
|
||||
$this->warning('ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")');
|
||||
}
|
||||
} else {
|
||||
$info['warning'][] = 'MP3gainTrackPeak value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';
|
||||
$this->warning('MP3gainTrackPeak value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"');
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -167,7 +175,7 @@ class getid3_apetag extends getid3_handler
|
|||
$thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
|
||||
$thisfile_replaygain['album']['originator'] = 'unspecified';
|
||||
} else {
|
||||
$info['warning'][] = 'MP3gainAlbumGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';
|
||||
$this->warning('MP3gainAlbumGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"');
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -176,10 +184,10 @@ class getid3_apetag extends getid3_handler
|
|||
$thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
|
||||
$thisfile_replaygain['album']['originator'] = 'unspecified';
|
||||
if ($thisfile_replaygain['album']['peak'] <= 0) {
|
||||
$info['warning'][] = 'ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")';
|
||||
$this->warning('ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")');
|
||||
}
|
||||
} else {
|
||||
$info['warning'][] = 'MP3gainAlbumPeak value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';
|
||||
$this->warning('MP3gainAlbumPeak value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"');
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -190,7 +198,7 @@ class getid3_apetag extends getid3_handler
|
|||
$thisfile_replaygain['mp3gain']['undo_right'] = intval($mp3gain_undo_right);
|
||||
$thisfile_replaygain['mp3gain']['undo_wrap'] = (($mp3gain_undo_wrap == 'Y') ? true : false);
|
||||
} else {
|
||||
$info['warning'][] = 'MP3gainUndo value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';
|
||||
$this->warning('MP3gainUndo value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"');
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -200,7 +208,7 @@ class getid3_apetag extends getid3_handler
|
|||
$thisfile_replaygain['mp3gain']['globalgain_track_min'] = intval($mp3gain_globalgain_min);
|
||||
$thisfile_replaygain['mp3gain']['globalgain_track_max'] = intval($mp3gain_globalgain_max);
|
||||
} else {
|
||||
$info['warning'][] = 'MP3gainMinMax value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';
|
||||
$this->warning('MP3gainMinMax value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"');
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -210,7 +218,7 @@ class getid3_apetag extends getid3_handler
|
|||
$thisfile_replaygain['mp3gain']['globalgain_album_min'] = intval($mp3gain_globalgain_album_min);
|
||||
$thisfile_replaygain['mp3gain']['globalgain_album_max'] = intval($mp3gain_globalgain_album_max);
|
||||
} else {
|
||||
$info['warning'][] = 'MP3gainAlbumMinMax value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';
|
||||
$this->warning('MP3gainAlbumMinMax value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"');
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -245,7 +253,7 @@ class getid3_apetag extends getid3_handler
|
|||
case 'cover art (studio)':
|
||||
// list of possible cover arts from http://taglib-sharp.sourcearchive.com/documentation/2.0.3.0-2/Ape_2Tag_8cs-source.html
|
||||
if (is_array($thisfile_ape_items_current['data'])) {
|
||||
$info['warning'][] = 'APEtag "'.$item_key.'" should be flagged as Binary data, but was incorrectly flagged as UTF-8';
|
||||
$this->warning('APEtag "'.$item_key.'" should be flagged as Binary data, but was incorrectly flagged as UTF-8');
|
||||
$thisfile_ape_items_current['data'] = implode("\x00", $thisfile_ape_items_current['data']);
|
||||
}
|
||||
list($thisfile_ape_items_current['filename'], $thisfile_ape_items_current['data']) = explode("\x00", $thisfile_ape_items_current['data'], 2);
|
||||
|
@ -254,10 +262,10 @@ class getid3_apetag extends getid3_handler
|
|||
|
||||
do {
|
||||
$thisfile_ape_items_current['image_mime'] = '';
|
||||
$imageinfo = [];
|
||||
$imageinfo = array();
|
||||
$imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_ape_items_current['data'], $imageinfo);
|
||||
if (($imagechunkcheck === false) || !isset($imagechunkcheck[2])) {
|
||||
$info['warning'][] = 'APEtag "'.$item_key.'" contains invalid image data';
|
||||
$this->warning('APEtag "'.$item_key.'" contains invalid image data');
|
||||
break;
|
||||
}
|
||||
$thisfile_ape_items_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
|
||||
|
@ -272,15 +280,15 @@ class getid3_apetag extends getid3_handler
|
|||
} elseif (is_int($this->inline_attachments)) {
|
||||
if ($this->inline_attachments < $thisfile_ape_items_current['data_length']) {
|
||||
// too big, skip
|
||||
$info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' is too large to process inline ('.number_format($thisfile_ape_items_current['data_length']).' bytes)';
|
||||
$this->warning('attachment at '.$thisfile_ape_items_current['offset'].' is too large to process inline ('.number_format($thisfile_ape_items_current['data_length']).' bytes)');
|
||||
unset($thisfile_ape_items_current['data']);
|
||||
break;
|
||||
}
|
||||
} elseif (is_string($this->inline_attachments)) {
|
||||
$this->inline_attachments = rtrim(str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $this->inline_attachments), DIRECTORY_SEPARATOR);
|
||||
$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 '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$this->inline_attachments.'" (not writable)';
|
||||
$this->warning('attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$this->inline_attachments.'" (not writable)');
|
||||
unset($thisfile_ape_items_current['data']);
|
||||
break;
|
||||
}
|
||||
|
@ -291,16 +299,16 @@ class getid3_apetag extends getid3_handler
|
|||
if (!file_exists($destination_filename) || is_writable($destination_filename)) {
|
||||
file_put_contents($destination_filename, $thisfile_ape_items_current['data']);
|
||||
} else {
|
||||
$info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$destination_filename.'" (not writable)';
|
||||
$this->warning('attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$destination_filename.'" (not writable)');
|
||||
}
|
||||
$thisfile_ape_items_current['data_filename'] = $destination_filename;
|
||||
unset($thisfile_ape_items_current['data']);
|
||||
} else {
|
||||
if (!isset($info['ape']['comments']['picture'])) {
|
||||
$info['ape']['comments']['picture'] = [];
|
||||
$info['ape']['comments']['picture'] = array();
|
||||
}
|
||||
$comments_picture_data = [];
|
||||
foreach (['data', 'image_mime', 'image_width', 'image_height', 'imagetype', 'picturetype', 'description', 'datalength'] as $picture_key) {
|
||||
$comments_picture_data = array();
|
||||
foreach (array('data', 'image_mime', 'image_width', 'image_height', 'imagetype', 'picturetype', 'description', 'datalength') as $picture_key) {
|
||||
if (isset($thisfile_ape_items_current[$picture_key])) {
|
||||
$comments_picture_data[$picture_key] = $thisfile_ape_items_current[$picture_key];
|
||||
}
|
||||
|
@ -319,6 +327,7 @@ class getid3_apetag extends getid3_handler
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (empty($thisfile_replaygain)) {
|
||||
unset($info['replay_gain']);
|
||||
|
@ -326,12 +335,11 @@ class getid3_apetag extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function parseAPEheaderFooter($APEheaderFooterData)
|
||||
{
|
||||
public function parseAPEheaderFooter($APEheaderFooterData) {
|
||||
// http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html
|
||||
|
||||
// shortcut
|
||||
$headerfooterinfo['raw'] = [];
|
||||
$headerfooterinfo['raw'] = array();
|
||||
$headerfooterinfo_raw = &$headerfooterinfo['raw'];
|
||||
|
||||
$headerfooterinfo_raw['footer_tag'] = substr($APEheaderFooterData, 0, 8);
|
||||
|
@ -351,8 +359,7 @@ class getid3_apetag extends getid3_handler
|
|||
return $headerfooterinfo;
|
||||
}
|
||||
|
||||
public function parseAPEtagFlags($rawflagint)
|
||||
{
|
||||
public function parseAPEtagFlags($rawflagint) {
|
||||
// "Note: APE Tags 1.0 do not use any of the APE Tag flags.
|
||||
// All are set to zero on creation and ignored on reading."
|
||||
// http://wiki.hydrogenaud.io/index.php?title=Ape_Tags_Flags
|
||||
|
@ -367,20 +374,18 @@ class getid3_apetag extends getid3_handler
|
|||
return $flags;
|
||||
}
|
||||
|
||||
public function APEcontentTypeFlagLookup($contenttypeid)
|
||||
{
|
||||
static $APEcontentTypeFlagLookup = [
|
||||
public function APEcontentTypeFlagLookup($contenttypeid) {
|
||||
static $APEcontentTypeFlagLookup = array(
|
||||
0 => 'utf-8',
|
||||
1 => 'binary',
|
||||
2 => 'external',
|
||||
3 => 'reserved'
|
||||
];
|
||||
);
|
||||
return (isset($APEcontentTypeFlagLookup[$contenttypeid]) ? $APEcontentTypeFlagLookup[$contenttypeid] : 'invalid');
|
||||
}
|
||||
|
||||
public function APEtagItemIsUTF8Lookup($itemkey)
|
||||
{
|
||||
static $APEtagItemIsUTF8Lookup = [
|
||||
public function APEtagItemIsUTF8Lookup($itemkey) {
|
||||
static $APEtagItemIsUTF8Lookup = array(
|
||||
'title',
|
||||
'subtitle',
|
||||
'artist',
|
||||
|
@ -404,7 +409,8 @@ class getid3_apetag extends getid3_handler
|
|||
'abstract',
|
||||
'language',
|
||||
'bibliography'
|
||||
];
|
||||
);
|
||||
return in_array(strtolower($itemkey), $APEtagItemIsUTF8Lookup);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,12 +18,11 @@
|
|||
class getid3_id3v1 extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
if (!getid3_lib::intValueSupported($info['filesize'])) {
|
||||
$info['warning'][] = 'Unable to check for ID3v1 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
|
||||
$this->warning('Unable to check for ID3v1 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -32,6 +31,7 @@ class getid3_id3v1 extends getid3_handler
|
|||
$id3v1tag = $this->fread(128);
|
||||
|
||||
if (substr($id3v1tag, 0, 3) == 'TAG') {
|
||||
|
||||
$info['avdataend'] = $info['filesize'] - 128;
|
||||
|
||||
$ParsedID3v1['title'] = $this->cutfield(substr($id3v1tag, 3, 30));
|
||||
|
@ -60,6 +60,26 @@ class getid3_id3v1 extends getid3_handler
|
|||
foreach ($ParsedID3v1 as $key => $value) {
|
||||
$ParsedID3v1['comments'][$key][0] = $value;
|
||||
}
|
||||
// ID3v1 encoding detection hack START
|
||||
// ID3v1 is defined as always using ISO-8859-1 encoding, but it is not uncommon to find files tagged with ID3v1 using Windows-1251 or other character sets
|
||||
// Since ID3v1 has no concept of character sets there is no certain way to know we have the correct non-ISO-8859-1 character set, but we can guess
|
||||
$ID3v1encoding = 'ISO-8859-1';
|
||||
foreach ($ParsedID3v1['comments'] as $tag_key => $valuearray) {
|
||||
foreach ($valuearray as $key => $value) {
|
||||
if (preg_match('#^[\\x00-\\x40\\xA8\\B8\\x80-\\xFF]+$#', $value)) {
|
||||
foreach (array('Windows-1251', 'KOI8-R') as $id3v1_bad_encoding) {
|
||||
if (function_exists('mb_convert_encoding') && @mb_convert_encoding($value, $id3v1_bad_encoding, $id3v1_bad_encoding) === $value) {
|
||||
$ID3v1encoding = $id3v1_bad_encoding;
|
||||
break 3;
|
||||
} elseif (function_exists('iconv') && @iconv($id3v1_bad_encoding, $id3v1_bad_encoding, $value) === $value) {
|
||||
$ID3v1encoding = $id3v1_bad_encoding;
|
||||
break 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ID3v1 encoding detection hack END
|
||||
|
||||
// ID3v1 data is supposed to be padded with NULL characters, but some taggers pad with spaces
|
||||
$GoodFormatID3v1tag = $this->GenerateID3v1Tag(
|
||||
|
@ -69,18 +89,18 @@ class getid3_id3v1 extends getid3_handler
|
|||
$ParsedID3v1['year'],
|
||||
(isset($ParsedID3v1['genre']) ? $this->LookupGenreID($ParsedID3v1['genre']) : false),
|
||||
$ParsedID3v1['comment'],
|
||||
(!empty($ParsedID3v1['track']) ? $ParsedID3v1['track'] : '')
|
||||
);
|
||||
(!empty($ParsedID3v1['track']) ? $ParsedID3v1['track'] : ''));
|
||||
$ParsedID3v1['padding_valid'] = true;
|
||||
if ($id3v1tag !== $GoodFormatID3v1tag) {
|
||||
$ParsedID3v1['padding_valid'] = false;
|
||||
$info['warning'][] = 'Some ID3v1 fields do not use NULL characters for padding';
|
||||
$this->warning('Some ID3v1 fields do not use NULL characters for padding');
|
||||
}
|
||||
|
||||
$ParsedID3v1['tag_offset_end'] = $info['filesize'];
|
||||
$ParsedID3v1['tag_offset_start'] = $ParsedID3v1['tag_offset_end'] - 128;
|
||||
|
||||
$info['id3v1'] = $ParsedID3v1;
|
||||
$info['id3v1']['encoding'] = $ID3v1encoding;
|
||||
}
|
||||
|
||||
if (substr($preid3v1, 0, 3) == 'TAG') {
|
||||
|
@ -96,7 +116,7 @@ class getid3_id3v1 extends getid3_handler
|
|||
// a Lyrics3 tag footer was found before the last ID3v1, assume false "TAG" synch
|
||||
} else {
|
||||
// APE and Lyrics3 footers not found - assume double ID3v1
|
||||
$info['warning'][] = 'Duplicate ID3v1 tag detected - this has been known to happen with iTunes';
|
||||
$this->warning('Duplicate ID3v1 tag detected - this has been known to happen with iTunes');
|
||||
$info['avdataend'] -= 128;
|
||||
}
|
||||
}
|
||||
|
@ -104,14 +124,12 @@ class getid3_id3v1 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public static function cutfield($str)
|
||||
{
|
||||
public static function cutfield($str) {
|
||||
return trim(substr($str, 0, strcspn($str, "\x00")));
|
||||
}
|
||||
|
||||
public static function ArrayOfGenres($allowSCMPXextended = false)
|
||||
{
|
||||
static $GenreLookup = [
|
||||
public static function ArrayOfGenres($allowSCMPXextended=false) {
|
||||
static $GenreLookup = array(
|
||||
0 => 'Blues',
|
||||
1 => 'Classic Rock',
|
||||
2 => 'Country',
|
||||
|
@ -265,9 +283,9 @@ class getid3_id3v1 extends getid3_handler
|
|||
|
||||
'CR' => 'Cover',
|
||||
'RX' => 'Remix'
|
||||
];
|
||||
);
|
||||
|
||||
static $GenreLookupSCMPX = [];
|
||||
static $GenreLookupSCMPX = array();
|
||||
if ($allowSCMPXextended && empty($GenreLookupSCMPX)) {
|
||||
$GenreLookupSCMPX = $GenreLookup;
|
||||
// http://www.geocities.co.jp/SiliconValley-Oakland/3664/alittle.html#GenreExtended
|
||||
|
@ -294,8 +312,7 @@ class getid3_id3v1 extends getid3_handler
|
|||
return ($allowSCMPXextended ? $GenreLookupSCMPX : $GenreLookup);
|
||||
}
|
||||
|
||||
public static function LookupGenreName($genreid, $allowSCMPXextended = true)
|
||||
{
|
||||
public static function LookupGenreName($genreid, $allowSCMPXextended=true) {
|
||||
switch ($genreid) {
|
||||
case 'RX':
|
||||
case 'CR':
|
||||
|
@ -311,8 +328,7 @@ class getid3_id3v1 extends getid3_handler
|
|||
return (isset($GenreLookup[$genreid]) ? $GenreLookup[$genreid] : false);
|
||||
}
|
||||
|
||||
public static function LookupGenreID($genre, $allowSCMPXextended = false)
|
||||
{
|
||||
public static function LookupGenreID($genre, $allowSCMPXextended=false) {
|
||||
$GenreLookup = self::ArrayOfGenres($allowSCMPXextended);
|
||||
$LowerCaseNoSpaceSearchTerm = strtolower(str_replace(' ', '', $genre));
|
||||
foreach ($GenreLookup as $key => $value) {
|
||||
|
@ -323,16 +339,14 @@ class getid3_id3v1 extends getid3_handler
|
|||
return false;
|
||||
}
|
||||
|
||||
public static function StandardiseID3v1GenreName($OriginalGenre)
|
||||
{
|
||||
public static function StandardiseID3v1GenreName($OriginalGenre) {
|
||||
if (($GenreID = self::LookupGenreID($OriginalGenre)) !== false) {
|
||||
return self::LookupGenreName($GenreID);
|
||||
}
|
||||
return $OriginalGenre;
|
||||
}
|
||||
|
||||
public static function GenerateID3v1Tag($title, $artist, $album, $year, $genreid, $comment, $track = '')
|
||||
{
|
||||
public static function GenerateID3v1Tag($title, $artist, $album, $year, $genreid, $comment, $track='') {
|
||||
$ID3v1Tag = 'TAG';
|
||||
$ID3v1Tag .= str_pad(trim(substr($title, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
|
||||
$ID3v1Tag .= str_pad(trim(substr($artist, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
|
||||
|
@ -363,4 +377,5 @@ class getid3_id3v1 extends getid3_handler
|
|||
|
||||
return $ID3v1Tag;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,14 +18,13 @@
|
|||
class getid3_lyrics3 extends getid3_handler
|
||||
{
|
||||
|
||||
public function Analyze()
|
||||
{
|
||||
public function Analyze() {
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// http://www.volweb.cz/str/tags.htm
|
||||
|
||||
if (!getid3_lib::intValueSupported($info['filesize'])) {
|
||||
$info['warning'][] = 'Unable to check for Lyrics3 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
|
||||
$this->warning('Unable to check for Lyrics3 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -41,6 +40,7 @@ class getid3_lyrics3 extends getid3_handler
|
|||
$lyrics3size = 5100;
|
||||
$lyrics3offset = $info['filesize'] - 128 - $lyrics3size;
|
||||
$lyrics3version = 1;
|
||||
|
||||
} elseif ($lyrics3end == 'LYRICS200') {
|
||||
// Lyrics3v2, ID3v1, no APE
|
||||
|
||||
|
@ -48,6 +48,7 @@ class getid3_lyrics3 extends getid3_handler
|
|||
$lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200');
|
||||
$lyrics3offset = $info['filesize'] - 128 - $lyrics3size;
|
||||
$lyrics3version = 2;
|
||||
|
||||
} elseif (substr(strrev($lyrics3_id3v1), 0, 9) == strrev('LYRICSEND')) {
|
||||
// Lyrics3v1, no ID3v1, no APE
|
||||
|
||||
|
@ -55,14 +56,19 @@ class getid3_lyrics3 extends getid3_handler
|
|||
$lyrics3offset = $info['filesize'] - $lyrics3size;
|
||||
$lyrics3version = 1;
|
||||
$lyrics3offset = $info['filesize'] - $lyrics3size;
|
||||
|
||||
} elseif (substr(strrev($lyrics3_id3v1), 0, 9) == strrev('LYRICS200')) {
|
||||
|
||||
// Lyrics3v2, no ID3v1, no APE
|
||||
|
||||
$lyrics3size = strrev(substr(strrev($lyrics3_id3v1), 9, 6)) + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
|
||||
$lyrics3offset = $info['filesize'] - $lyrics3size;
|
||||
$lyrics3version = 2;
|
||||
|
||||
} else {
|
||||
|
||||
if (isset($info['ape']['tag_offset_start']) && ($info['ape']['tag_offset_start'] > 15)) {
|
||||
|
||||
$this->fseek($info['ape']['tag_offset_start'] - 15);
|
||||
$lyrics3lsz = $this->fread(6);
|
||||
$lyrics3end = $this->fread(9);
|
||||
|
@ -74,16 +80,20 @@ class getid3_lyrics3 extends getid3_handler
|
|||
$lyrics3offset = $info['ape']['tag_offset_start'] - $lyrics3size;
|
||||
$info['avdataend'] = $lyrics3offset;
|
||||
$lyrics3version = 1;
|
||||
$info['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability';
|
||||
$this->warning('APE tag located after Lyrics3, will probably break Lyrics3 compatability');
|
||||
|
||||
} elseif ($lyrics3end == 'LYRICS200') {
|
||||
// Lyrics3v2, APE, maybe ID3v1
|
||||
|
||||
$lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
|
||||
$lyrics3offset = $info['ape']['tag_offset_start'] - $lyrics3size;
|
||||
$lyrics3version = 2;
|
||||
$info['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability';
|
||||
$this->warning('APE tag located after Lyrics3, will probably break Lyrics3 compatability');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (isset($lyrics3offset)) {
|
||||
|
@ -107,22 +117,22 @@ class getid3_lyrics3 extends getid3_handler
|
|||
}
|
||||
unset($getid3_temp, $getid3_apetag);
|
||||
} else {
|
||||
$info['warning'][] = 'Lyrics3 and APE tags appear to have become entangled (most likely due to updating the APE tags with a non-Lyrics3-aware tagger)';
|
||||
$this->warning('Lyrics3 and APE tags appear to have become entangled (most likely due to updating the APE tags with a non-Lyrics3-aware tagger)');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getLyrics3Data($endoffset, $version, $length)
|
||||
{
|
||||
public function getLyrics3Data($endoffset, $version, $length) {
|
||||
// http://www.volweb.cz/str/tags.htm
|
||||
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
if (!getid3_lib::intValueSupported($endoffset)) {
|
||||
$info['warning'][] = 'Unable to check for Lyrics3 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
|
||||
$this->warning('Unable to check for Lyrics3 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -139,25 +149,31 @@ class getid3_lyrics3 extends getid3_handler
|
|||
|
||||
if (substr($rawdata, 0, 11) != 'LYRICSBEGIN') {
|
||||
if (strpos($rawdata, 'LYRICSBEGIN') !== false) {
|
||||
$info['warning'][] = '"LYRICSBEGIN" expected at '.$endoffset.' but actually found at '.($endoffset + strpos($rawdata, 'LYRICSBEGIN')).' - this is invalid for Lyrics3 v'.$version;
|
||||
|
||||
$this->warning('"LYRICSBEGIN" expected at '.$endoffset.' but actually found at '.($endoffset + strpos($rawdata, 'LYRICSBEGIN')).' - this is invalid for Lyrics3 v'.$version);
|
||||
$info['avdataend'] = $endoffset + strpos($rawdata, 'LYRICSBEGIN');
|
||||
$rawdata = substr($rawdata, strpos($rawdata, 'LYRICSBEGIN'));
|
||||
$length = strlen($rawdata);
|
||||
$ParsedLyrics3['tag_offset_start'] = $info['avdataend'];
|
||||
$ParsedLyrics3['raw']['lyrics3tagsize'] = $length;
|
||||
|
||||
} else {
|
||||
$info['error'][] = '"LYRICSBEGIN" expected at '.$endoffset.' but found "'.substr($rawdata, 0, 11).'" instead';
|
||||
|
||||
$this->error('"LYRICSBEGIN" expected at '.$endoffset.' but found "'.substr($rawdata, 0, 11).'" instead');
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
switch ($version) {
|
||||
|
||||
case 1:
|
||||
if (substr($rawdata, strlen($rawdata) - 9, 9) == 'LYRICSEND') {
|
||||
$ParsedLyrics3['raw']['LYR'] = trim(substr($rawdata, 11, strlen($rawdata) - 11 - 9));
|
||||
$this->Lyrics3LyricsTimestampParse($ParsedLyrics3);
|
||||
} else {
|
||||
$info['error'][] = '"LYRICSEND" expected at '.($this->ftell() - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead';
|
||||
$this->error('"LYRICSEND" expected at '.($this->ftell() - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead');
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
@ -175,7 +191,7 @@ class getid3_lyrics3 extends getid3_handler
|
|||
|
||||
if (isset($ParsedLyrics3['raw']['IND'])) {
|
||||
$i = 0;
|
||||
$flagnames = ['lyrics', 'timestamps', 'inhibitrandom'];
|
||||
$flagnames = array('lyrics', 'timestamps', 'inhibitrandom');
|
||||
foreach ($flagnames as $flagname) {
|
||||
if (strlen($ParsedLyrics3['raw']['IND']) > $i++) {
|
||||
$ParsedLyrics3['flags'][$flagname] = $this->IntString2Bool(substr($ParsedLyrics3['raw']['IND'], $i, 1 - 1));
|
||||
|
@ -183,7 +199,7 @@ class getid3_lyrics3 extends getid3_handler
|
|||
}
|
||||
}
|
||||
|
||||
$fieldnametranslation = ['ETT'=>'title', 'EAR'=>'artist', 'EAL'=>'album', 'INF'=>'comment', 'AUT'=>'author'];
|
||||
$fieldnametranslation = array('ETT'=>'title', 'EAR'=>'artist', 'EAL'=>'album', 'INF'=>'comment', 'AUT'=>'author');
|
||||
foreach ($fieldnametranslation as $key => $value) {
|
||||
if (isset($ParsedLyrics3['raw'][$key])) {
|
||||
$ParsedLyrics3['comments'][$value][] = trim($ParsedLyrics3['raw'][$key]);
|
||||
|
@ -205,20 +221,20 @@ class getid3_lyrics3 extends getid3_handler
|
|||
$this->Lyrics3LyricsTimestampParse($ParsedLyrics3);
|
||||
}
|
||||
} else {
|
||||
$info['error'][] = '"LYRICS200" expected at '.($this->ftell() - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead';
|
||||
$this->error('"LYRICS200" expected at '.($this->ftell() - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead');
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$info['error'][] = 'Cannot process Lyrics3 version '.$version.' (only v1 and v2)';
|
||||
$this->error('Cannot process Lyrics3 version '.$version.' (only v1 and v2)');
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (isset($info['id3v1']['tag_offset_start']) && ($info['id3v1']['tag_offset_start'] <= $ParsedLyrics3['tag_offset_end'])) {
|
||||
$info['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in Lyrics3 tag data';
|
||||
$this->warning('ID3v1 tag information ignored since it appears to be a false synch in Lyrics3 tag data');
|
||||
unset($info['id3v1']);
|
||||
foreach ($info['warning'] as $key => $value) {
|
||||
if ($value == 'Some ID3v1 fields do not use NULL characters for padding') {
|
||||
|
@ -234,19 +250,17 @@ class getid3_lyrics3 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function Lyrics3Timestamp2Seconds($rawtimestamp)
|
||||
{
|
||||
public function Lyrics3Timestamp2Seconds($rawtimestamp) {
|
||||
if (preg_match('#^\\[([0-9]{2}):([0-9]{2})\\]$#', $rawtimestamp, $regs)) {
|
||||
return (int) (($regs[1] * 60) + $regs[2]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function Lyrics3LyricsTimestampParse(&$Lyrics3data)
|
||||
{
|
||||
public function Lyrics3LyricsTimestampParse(&$Lyrics3data) {
|
||||
$lyricsarray = explode("\r\n", $Lyrics3data['raw']['LYR']);
|
||||
foreach ($lyricsarray as $key => $lyricline) {
|
||||
$regs = [];
|
||||
$regs = array();
|
||||
unset($thislinetimestamps);
|
||||
while (preg_match('#^(\\[[0-9]{2}:[0-9]{2}\\])#', $lyricline, $regs)) {
|
||||
$thislinetimestamps[] = $this->Lyrics3Timestamp2Seconds($regs[0]);
|
||||
|
@ -273,8 +287,7 @@ class getid3_lyrics3 extends getid3_handler
|
|||
return true;
|
||||
}
|
||||
|
||||
public function IntString2Bool($char)
|
||||
{
|
||||
public function IntString2Bool($char) {
|
||||
if ($char == '1') {
|
||||
return true;
|
||||
} elseif ($char == '0') {
|
||||
|
|
|
@ -45,7 +45,7 @@ class Image_XMP
|
|||
* The XMP fields that were extracted from the image or updated by this class.
|
||||
* @see getAllTags()
|
||||
*/
|
||||
public $_aXMP = [];
|
||||
public $_aXMP = array();
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
|
@ -102,7 +102,8 @@ class Image_XMP
|
|||
$data = fread($filehnd, 2);
|
||||
|
||||
// Check that the first two characters are 0xFF 0xD8 (SOI - Start of image)
|
||||
if ($data != "\xFF\xD8") {
|
||||
if ($data != "\xFF\xD8")
|
||||
{
|
||||
// No SOI (FF D8) at start of file - This probably isn't a JPEG file - close file and return;
|
||||
echo '<p>This probably is not a JPEG file</p>'."\n";
|
||||
fclose($filehnd);
|
||||
|
@ -113,7 +114,8 @@ class Image_XMP
|
|||
$data = fread($filehnd, 2);
|
||||
|
||||
// Check that the third character is 0xFF (Start of first segment header)
|
||||
if ($data{0} != "\xFF") {
|
||||
if ($data{0} != "\xFF")
|
||||
{
|
||||
// NO FF found - close file and return - JPEG is probably corrupted
|
||||
fclose($filehnd);
|
||||
return false;
|
||||
|
@ -126,10 +128,12 @@ class Image_XMP
|
|||
// 2) we have hit the compressed image data (no more headers are allowed after data)
|
||||
// 3) or end of file is hit
|
||||
|
||||
while (($data{1} != "\xD9") && (!$hit_compressed_image_data) && (!feof($filehnd))) {
|
||||
while (($data{1} != "\xD9") && (!$hit_compressed_image_data) && (!feof($filehnd)))
|
||||
{
|
||||
// Found a segment to look at.
|
||||
// Check that the segment marker is not a Restart marker - restart markers don't have size or data after them
|
||||
if ((ord($data{1}) < 0xD0) || (ord($data{1}) > 0xD7)) {
|
||||
if ((ord($data{1}) < 0xD0) || (ord($data{1}) > 0xD7))
|
||||
{
|
||||
// Segment isn't a Restart marker
|
||||
// Read the next two bytes (size)
|
||||
$sizestr = fread($filehnd, 2);
|
||||
|
@ -144,24 +148,28 @@ class Image_XMP
|
|||
$segdata = fread($filehnd, $decodedsize['size'] - 2);
|
||||
|
||||
// Store the segment information in the output array
|
||||
$headerdata[] = [
|
||||
$headerdata[] = array(
|
||||
'SegType' => ord($data{1}),
|
||||
'SegName' => $GLOBALS['JPEG_Segment_Names'][ord($data{1})],
|
||||
'SegDataStart' => $segdatastart,
|
||||
'SegData' => $segdata,
|
||||
];
|
||||
);
|
||||
}
|
||||
|
||||
// If this is a SOS (Start Of Scan) segment, then there is no more header data - the compressed image data follows
|
||||
if ($data{1} == "\xDA") {
|
||||
if ($data{1} == "\xDA")
|
||||
{
|
||||
// Flag that we have hit the compressed image data - exit loop as no more headers available.
|
||||
$hit_compressed_image_data = true;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not an SOS - Read the next two bytes - should be the segment marker for the next segment
|
||||
$data = fread($filehnd, 2);
|
||||
|
||||
// Check that the first byte of the two is 0xFF as it should be for a marker
|
||||
if ($data{0} != "\xFF") {
|
||||
if ($data{0} != "\xFF")
|
||||
{
|
||||
// NO FF found - close file and return - JPEG is probably corrupted
|
||||
fclose($filehnd);
|
||||
return false;
|
||||
|
@ -192,11 +200,14 @@ class Image_XMP
|
|||
$jpeg_header_data = $this->_get_jpeg_header_data($filename);
|
||||
|
||||
//Cycle through the header segments
|
||||
for ($i = 0; $i < count($jpeg_header_data); $i++) {
|
||||
for ($i = 0; $i < count($jpeg_header_data); $i++)
|
||||
{
|
||||
// If we find an APP1 header,
|
||||
if (strcmp($jpeg_header_data[$i]['SegName'], 'APP1') == 0) {
|
||||
if (strcmp($jpeg_header_data[$i]['SegName'], 'APP1') == 0)
|
||||
{
|
||||
// And if it has the Adobe XMP/RDF label (http://ns.adobe.com/xap/1.0/\x00) ,
|
||||
if (strncmp($jpeg_header_data[$i]['SegData'], 'http://ns.adobe.com/xap/1.0/'."\x00", 29) == 0) {
|
||||
if (strncmp($jpeg_header_data[$i]['SegData'], 'http://ns.adobe.com/xap/1.0/'."\x00", 29) == 0)
|
||||
{
|
||||
// Found a XMP/RDF block
|
||||
// Return the XMP text
|
||||
$xmp_data = substr($jpeg_header_data[$i]['SegData'], 29);
|
||||
|
@ -219,7 +230,8 @@ class Image_XMP
|
|||
public function read_XMP_array_from_text($xmltext)
|
||||
{
|
||||
// Check if there actually is any text to parse
|
||||
if (trim($xmltext) == '') {
|
||||
if (trim($xmltext) == '')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -231,7 +243,8 @@ class Image_XMP
|
|||
// We would like to remove unneccessary white space, but this will also
|
||||
// remove things like newlines (
) in the XML values, so white space
|
||||
// will have to be removed later
|
||||
if (xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 0) == false) {
|
||||
if (xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 0) == false)
|
||||
{
|
||||
// Error setting case folding - destroy the parser and return
|
||||
xml_parser_free($xml_parser);
|
||||
return false;
|
||||
|
@ -240,14 +253,16 @@ class Image_XMP
|
|||
// to use XML code correctly we have to turn case folding
|
||||
// (uppercasing) off. XML is case sensitive and upper
|
||||
// casing is in reality XML standards violation
|
||||
if (xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0) == false) {
|
||||
if (xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0) == false)
|
||||
{
|
||||
// Error setting case folding - destroy the parser and return
|
||||
xml_parser_free($xml_parser);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse the XML text into a array structure
|
||||
if (xml_parse_into_struct($xml_parser, $xmltext, $values, $tags) == 0) {
|
||||
if (xml_parse_into_struct($xml_parser, $xmltext, $values, $tags) == 0)
|
||||
{
|
||||
// Error Parsing XML - destroy the parser and return
|
||||
xml_parser_free($xml_parser);
|
||||
return false;
|
||||
|
@ -257,16 +272,18 @@ class Image_XMP
|
|||
xml_parser_free($xml_parser);
|
||||
|
||||
// Clear the output array
|
||||
$xmp_array = [];
|
||||
$xmp_array = array();
|
||||
|
||||
// The XMP data has now been parsed into an array ...
|
||||
|
||||
// Cycle through each of the array elements
|
||||
$current_property = ''; // current property being processed
|
||||
$container_index = -1; // -1 = no container open, otherwise index of container content
|
||||
foreach ($values as $xml_elem) {
|
||||
foreach ($values as $xml_elem)
|
||||
{
|
||||
// Syntax and Class names
|
||||
switch ($xml_elem['tag']) {
|
||||
switch ($xml_elem['tag'])
|
||||
{
|
||||
case 'x:xmpmeta':
|
||||
// only defined attribute is x:xmptk written by Adobe XMP Toolkit; value is the version of the toolkit
|
||||
break;
|
||||
|
@ -276,15 +293,19 @@ class Image_XMP
|
|||
break;
|
||||
|
||||
case 'rdf:Description':
|
||||
switch ($xml_elem['type']) {
|
||||
switch ($xml_elem['type'])
|
||||
{
|
||||
case 'open':
|
||||
case 'complete':
|
||||
if (array_key_exists('attributes', $xml_elem)) {
|
||||
if (array_key_exists('attributes', $xml_elem))
|
||||
{
|
||||
// rdf:Description may contain wanted attributes
|
||||
foreach (array_keys($xml_elem['attributes']) as $key) {
|
||||
foreach (array_keys($xml_elem['attributes']) as $key)
|
||||
{
|
||||
// Check whether we want this details from this attribute
|
||||
// if (in_array($key, $GLOBALS['XMP_tag_captions']))
|
||||
if (true) {
|
||||
if (true)
|
||||
{
|
||||
// Attribute wanted
|
||||
$xmp_array[$key] = $xml_elem['attributes'][$key];
|
||||
}
|
||||
|
@ -302,14 +323,18 @@ class Image_XMP
|
|||
|
||||
case 'rdf:li':
|
||||
// Property member
|
||||
if ($xml_elem['type'] == 'complete') {
|
||||
if (array_key_exists('attributes', $xml_elem)) {
|
||||
if ($xml_elem['type'] == 'complete')
|
||||
{
|
||||
if (array_key_exists('attributes', $xml_elem))
|
||||
{
|
||||
// If Lang Alt (language alternatives) then ensure we take the default language
|
||||
if (isset($xml_elem['attributes']['xml:lang']) && ($xml_elem['attributes']['xml:lang'] != 'x-default')) {
|
||||
if (isset($xml_elem['attributes']['xml:lang']) && ($xml_elem['attributes']['xml:lang'] != 'x-default'))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($current_property != '') {
|
||||
if ($current_property != '')
|
||||
{
|
||||
$xmp_array[$current_property][$container_index] = (isset($xml_elem['value']) ? $xml_elem['value'] : '');
|
||||
$container_index += 1;
|
||||
}
|
||||
|
@ -321,7 +346,8 @@ class Image_XMP
|
|||
case 'rdf:Bag':
|
||||
case 'rdf:Alt':
|
||||
// Container found
|
||||
switch ($xml_elem['type']) {
|
||||
switch ($xml_elem['type'])
|
||||
{
|
||||
case 'open':
|
||||
$container_index = 0;
|
||||
break;
|
||||
|
@ -336,8 +362,10 @@ class Image_XMP
|
|||
default:
|
||||
// Check whether we want the details from this attribute
|
||||
// if (in_array($xml_elem['tag'], $GLOBALS['XMP_tag_captions']))
|
||||
if (true) {
|
||||
switch ($xml_elem['type']) {
|
||||
if (true)
|
||||
{
|
||||
switch ($xml_elem['type'])
|
||||
{
|
||||
case 'open':
|
||||
// open current element
|
||||
$current_property = $xml_elem['tag'];
|
||||
|
@ -360,6 +388,7 @@ class Image_XMP
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return $xmp_array;
|
||||
}
|
||||
|
@ -374,15 +403,18 @@ class Image_XMP
|
|||
{
|
||||
$this->_sFilename = $sFilename;
|
||||
|
||||
if (is_file($this->_sFilename)) {
|
||||
if (is_file($this->_sFilename))
|
||||
{
|
||||
// Get XMP data
|
||||
$xmp_data = $this->_get_XMP_text($sFilename);
|
||||
if ($xmp_data) {
|
||||
if ($xmp_data)
|
||||
{
|
||||
$this->_aXMP = $this->read_XMP_array_from_text($xmp_data);
|
||||
$this->_bXMPParse = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -667,7 +699,7 @@ $GLOBALS['XMP_tag_captions'] = array(
|
|||
*
|
||||
* The names of the JPEG segment markers, indexed by their marker number
|
||||
*/
|
||||
$GLOBALS['JPEG_Segment_Names'] = [
|
||||
$GLOBALS['JPEG_Segment_Names'] = array(
|
||||
0x01 => 'TEM',
|
||||
0x02 => 'RES',
|
||||
0xC0 => 'SOF0',
|
||||
|
@ -733,4 +765,4 @@ $GLOBALS['JPEG_Segment_Names'] = [
|
|||
0xFC => 'JPG12',
|
||||
0xFD => 'JPG13',
|
||||
0xFE => 'COM',
|
||||
];
|
||||
);
|
||||
|
|
|
@ -23,16 +23,14 @@ class getid3_write_apetag
|
|||
public $filename;
|
||||
public $tag_data;
|
||||
public $always_preserve_replaygain = true; // ReplayGain / MP3gain tags will be copied from old tag even if not passed in data
|
||||
public $warnings = []; // any non-critical errors will be stored here
|
||||
public $errors = []; // any critical errors will be stored here
|
||||
public $warnings = array(); // any non-critical errors will be stored here
|
||||
public $errors = array(); // any critical errors will be stored here
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
public function __construct() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function WriteAPEtag()
|
||||
{
|
||||
public function WriteAPEtag() {
|
||||
// NOTE: All data passed to this function must be UTF-8 format
|
||||
|
||||
$getID3 = new getID3;
|
||||
|
@ -50,7 +48,7 @@ class getid3_write_apetag
|
|||
}
|
||||
|
||||
if ($this->always_preserve_replaygain) {
|
||||
$ReplayGainTagsToPreserve = ['mp3gain_minmax', 'mp3gain_album_minmax', 'mp3gain_undo', 'replaygain_track_peak', 'replaygain_track_gain', 'replaygain_album_peak', 'replaygain_album_gain'];
|
||||
$ReplayGainTagsToPreserve = array('mp3gain_minmax', 'mp3gain_album_minmax', 'mp3gain_undo', 'replaygain_track_peak', 'replaygain_track_gain', 'replaygain_album_peak', 'replaygain_album_gain');
|
||||
foreach ($ReplayGainTagsToPreserve as $rg_key) {
|
||||
if (isset($ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0]) && !isset($this->tag_data[strtoupper($rg_key)][0])) {
|
||||
$this->tag_data[strtoupper($rg_key)][0] = $ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0];
|
||||
|
@ -94,12 +92,12 @@ class getid3_write_apetag
|
|||
return false;
|
||||
}
|
||||
|
||||
public function DeleteAPEtag()
|
||||
{
|
||||
public function DeleteAPEtag() {
|
||||
$getID3 = new getID3;
|
||||
$ThisFileInfo = $getID3->analyze($this->filename);
|
||||
if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['ape']['tag_offset_end'])) {
|
||||
if (is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) {
|
||||
|
||||
flock($fp, LOCK_EX);
|
||||
$oldignoreuserabort = ignore_user_abort(true);
|
||||
|
||||
|
@ -128,11 +126,10 @@ class getid3_write_apetag
|
|||
}
|
||||
|
||||
|
||||
public function GenerateAPEtag()
|
||||
{
|
||||
public function GenerateAPEtag() {
|
||||
// NOTE: All data passed to this function must be UTF-8 format
|
||||
|
||||
$items = [];
|
||||
$items = array();
|
||||
if (!is_array($this->tag_data)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -157,13 +154,13 @@ class getid3_write_apetag
|
|||
$tagitem .= $valuestring;
|
||||
|
||||
$items[] = $tagitem;
|
||||
|
||||
}
|
||||
|
||||
return $this->GenerateAPEtagHeaderFooter($items, true).implode('', $items).$this->GenerateAPEtagHeaderFooter($items, false);
|
||||
}
|
||||
|
||||
public function GenerateAPEtagHeaderFooter(&$items, $isheader = false)
|
||||
{
|
||||
public function GenerateAPEtagHeaderFooter(&$items, $isheader=false) {
|
||||
$tagdatalength = 0;
|
||||
foreach ($items as $itemdata) {
|
||||
$tagdatalength += strlen($itemdata);
|
||||
|
@ -179,8 +176,7 @@ class getid3_write_apetag
|
|||
return $APEheader;
|
||||
}
|
||||
|
||||
public function GenerateAPEtagFlags($header = true, $footer = true, $isheader = false, $encodingid = 0, $readonly = false)
|
||||
{
|
||||
public function GenerateAPEtagFlags($header=true, $footer=true, $isheader=false, $encodingid=0, $readonly=false) {
|
||||
$APEtagFlags = array_fill(0, 4, 0);
|
||||
if ($header) {
|
||||
$APEtagFlags[0] |= 0x80; // Tag contains a header
|
||||
|
@ -205,8 +201,7 @@ class getid3_write_apetag
|
|||
return chr($APEtagFlags[3]).chr($APEtagFlags[2]).chr($APEtagFlags[1]).chr($APEtagFlags[0]);
|
||||
}
|
||||
|
||||
public function CleanAPEtagItemKey($itemkey)
|
||||
{
|
||||
public function CleanAPEtagItemKey($itemkey) {
|
||||
$itemkey = preg_replace("#[^\x20-\x7E]#i", '', $itemkey);
|
||||
|
||||
// http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html
|
||||
|
@ -223,5 +218,7 @@ class getid3_write_apetag
|
|||
break;
|
||||
}
|
||||
return $itemkey;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,16 +21,14 @@ class getid3_write_id3v1
|
|||
public $filename;
|
||||
public $filesize;
|
||||
public $tag_data;
|
||||
public $warnings = []; // any non-critical errors will be stored here
|
||||
public $errors = []; // any critical errors will be stored here
|
||||
public $warnings = array(); // any non-critical errors will be stored here
|
||||
public $errors = array(); // any critical errors will be stored here
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
public function __construct() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function WriteID3v1()
|
||||
{
|
||||
public function WriteID3v1() {
|
||||
// File MUST be writeable - CHMOD(646) at least
|
||||
if (!empty($this->filename) && is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename)) {
|
||||
$this->setRealFileSize();
|
||||
|
@ -54,11 +52,11 @@ class getid3_write_id3v1
|
|||
(isset($this->tag_data['year'] ) ? $this->tag_data['year'] : ''),
|
||||
(isset($this->tag_data['genreid']) ? $this->tag_data['genreid'] : ''),
|
||||
(isset($this->tag_data['comment']) ? $this->tag_data['comment'] : ''),
|
||||
(isset($this->tag_data['track']) ? $this->tag_data['track'] : '')
|
||||
);
|
||||
(isset($this->tag_data['track'] ) ? $this->tag_data['track'] : ''));
|
||||
fwrite($fp_source, $new_id3v1_tag_data, 128);
|
||||
fclose($fp_source);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
$this->errors[] = 'Could not fopen('.$this->filename.', "r+b")';
|
||||
return false;
|
||||
|
@ -68,8 +66,7 @@ class getid3_write_id3v1
|
|||
return false;
|
||||
}
|
||||
|
||||
public function FixID3v1Padding()
|
||||
{
|
||||
public function FixID3v1Padding() {
|
||||
// ID3v1 data is supposed to be padded with NULL characters, but some taggers incorrectly use spaces
|
||||
// This function rewrites the ID3v1 tag with correct padding
|
||||
|
||||
|
@ -91,8 +88,7 @@ class getid3_write_id3v1
|
|||
return false;
|
||||
}
|
||||
|
||||
public function RemoveID3v1()
|
||||
{
|
||||
public function RemoveID3v1() {
|
||||
// File MUST be writeable - CHMOD(646) at least
|
||||
if (!empty($this->filename) && is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename)) {
|
||||
$this->setRealFileSize();
|
||||
|
@ -101,6 +97,7 @@ class getid3_write_id3v1
|
|||
return false;
|
||||
}
|
||||
if ($fp_source = fopen($this->filename, 'r+b')) {
|
||||
|
||||
fseek($fp_source, -128, SEEK_END);
|
||||
if (fread($fp_source, 3) == 'TAG') {
|
||||
ftruncate($fp_source, $this->filesize - 128);
|
||||
|
@ -109,6 +106,7 @@ class getid3_write_id3v1
|
|||
}
|
||||
fclose($fp_source);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
$this->errors[] = 'Could not fopen('.$this->filename.', "r+b")';
|
||||
}
|
||||
|
@ -118,8 +116,7 @@ class getid3_write_id3v1
|
|||
return false;
|
||||
}
|
||||
|
||||
public function setRealFileSize()
|
||||
{
|
||||
public function setRealFileSize() {
|
||||
if (PHP_INT_MAX > 2147483647) {
|
||||
$this->filesize = filesize($this->filename);
|
||||
return true;
|
||||
|
@ -136,4 +133,5 @@ class getid3_write_id3v1
|
|||
$this->filesize = $ThisFileInfo['filesize'];
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,16 +27,14 @@ class getid3_write_id3v2
|
|||
public $merge_existing_data = false; // if true, merge new data with existing tags; if false, delete old tag data and only write new tags
|
||||
public $id3v2_default_encodingid = 0; // default text encoding (ISO-8859-1) if not explicitly passed
|
||||
public $id3v2_use_unsynchronisation = false; // the specs say it should be TRUE, but most other ID3v2-aware programs are broken if unsynchronization is used, so by default don't use it.
|
||||
public $warnings = []; // any non-critical errors will be stored here
|
||||
public $errors = []; // any critical errors will be stored here
|
||||
public $warnings = array(); // any non-critical errors will be stored here
|
||||
public $errors = array(); // any critical errors will be stored here
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
public function __construct() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function WriteID3v2()
|
||||
{
|
||||
public function WriteID3v2() {
|
||||
// File MUST be writeable - CHMOD(646) at least. It's best if the
|
||||
// directory is also writeable, because that method is both faster and less susceptible to errors.
|
||||
|
||||
|
@ -58,9 +56,12 @@ class getid3_write_id3v2
|
|||
$this->paddedlength = (isset($OldThisFileInfo['id3v2']['headerlength']) ? max($OldThisFileInfo['id3v2']['headerlength'], $this->paddedlength) : $this->paddedlength);
|
||||
|
||||
if ($NewID3v2Tag = $this->GenerateID3v2Tag()) {
|
||||
|
||||
if (file_exists($this->filename) && is_writeable($this->filename) && isset($OldThisFileInfo['id3v2']['headerlength']) && ($OldThisFileInfo['id3v2']['headerlength'] == strlen($NewID3v2Tag))) {
|
||||
|
||||
// best and fastest method - insert-overwrite existing tag (padded to length of old tag if neccesary)
|
||||
if (file_exists($this->filename)) {
|
||||
|
||||
if (is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'r+b'))) {
|
||||
rewind($fp);
|
||||
fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag));
|
||||
|
@ -68,7 +69,9 @@ class getid3_write_id3v2
|
|||
} else {
|
||||
$this->errors[] = 'Could not fopen("'.$this->filename.'", "r+b")';
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'wb'))) {
|
||||
rewind($fp);
|
||||
fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag));
|
||||
|
@ -76,11 +79,15 @@ class getid3_write_id3v2
|
|||
} else {
|
||||
$this->errors[] = 'Could not fopen("'.$this->filename.'", "wb")';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if ($tempfilename = tempnam(GETID3_TEMP_DIR, 'getID3')) {
|
||||
if (is_readable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'rb'))) {
|
||||
if (is_writable($tempfilename) && is_file($tempfilename) && ($fp_temp = fopen($tempfilename, 'wb'))) {
|
||||
|
||||
fwrite($fp_temp, $NewID3v2Tag, strlen($NewID3v2Tag));
|
||||
|
||||
rewind($fp_source);
|
||||
|
@ -97,18 +104,24 @@ class getid3_write_id3v2
|
|||
copy($tempfilename, $this->filename);
|
||||
unlink($tempfilename);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
$this->errors[] = 'Could not fopen("'.$tempfilename.'", "wb")';
|
||||
}
|
||||
fclose($fp_source);
|
||||
|
||||
} else {
|
||||
$this->errors[] = 'Could not fopen("'.$this->filename.'", "rb")';
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$this->errors[] = '$this->GenerateID3v2Tag() failed';
|
||||
|
||||
}
|
||||
|
||||
if (!empty($this->errors)) {
|
||||
|
@ -121,14 +134,15 @@ class getid3_write_id3v2
|
|||
return false;
|
||||
}
|
||||
|
||||
public function RemoveID3v2()
|
||||
{
|
||||
public function RemoveID3v2() {
|
||||
// File MUST be writeable - CHMOD(646) at least. It's best if the
|
||||
// directory is also writeable, because that method is both faster and less susceptible to errors.
|
||||
if (is_writeable(dirname($this->filename))) {
|
||||
|
||||
// preferred method - only one copying operation, minimal chance of corrupting
|
||||
// original file if script is interrupted, but required directory to be writeable
|
||||
if (is_readable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'rb'))) {
|
||||
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$OldThisFileInfo = $getID3->analyze($this->filename);
|
||||
|
@ -157,10 +171,13 @@ class getid3_write_id3v2
|
|||
unlink($this->filename);
|
||||
}
|
||||
rename($this->filename.'getid3tmp', $this->filename);
|
||||
|
||||
} elseif (is_writable($this->filename)) {
|
||||
|
||||
// less desirable alternate method - double-copies the file, overwrites original file
|
||||
// and could corrupt source file if the script is interrupted or an error occurs.
|
||||
if (is_readable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'rb'))) {
|
||||
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$OldThisFileInfo = $getID3->analyze($this->filename);
|
||||
|
@ -195,8 +212,11 @@ class getid3_write_id3v2
|
|||
} else {
|
||||
$this->errors[] = 'Could not fopen("'.$this->filename.'", "rb")';
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$this->errors[] = 'Directory and file both not writeable';
|
||||
|
||||
}
|
||||
|
||||
if (!empty($this->errors)) {
|
||||
|
@ -206,8 +226,7 @@ class getid3_write_id3v2
|
|||
}
|
||||
|
||||
|
||||
public function GenerateID3v2TagFlags($flags)
|
||||
{
|
||||
public function GenerateID3v2TagFlags($flags) {
|
||||
switch ($this->majorversion) {
|
||||
case 4:
|
||||
// %abcd0000
|
||||
|
@ -241,8 +260,7 @@ class getid3_write_id3v2
|
|||
}
|
||||
|
||||
|
||||
public function GenerateID3v2FrameFlags($TagAlter = false, $FileAlter = false, $ReadOnly = false, $Compression = false, $Encryption = false, $GroupingIdentity = false, $Unsynchronisation = false, $DataLengthIndicator = false)
|
||||
{
|
||||
public function GenerateID3v2FrameFlags($TagAlter=false, $FileAlter=false, $ReadOnly=false, $Compression=false, $Encryption=false, $GroupingIdentity=false, $Unsynchronisation=false, $DataLengthIndicator=false) {
|
||||
switch ($this->majorversion) {
|
||||
case 4:
|
||||
// %0abc0000 %0h00kmnp
|
||||
|
@ -277,19 +295,21 @@ class getid3_write_id3v2
|
|||
default:
|
||||
return false;
|
||||
break;
|
||||
|
||||
}
|
||||
return chr(bindec($flag1)).chr(bindec($flag2));
|
||||
}
|
||||
|
||||
public function GenerateID3v2FrameData($frame_name, $source_data_array)
|
||||
{
|
||||
public function GenerateID3v2FrameData($frame_name, $source_data_array) {
|
||||
if (!getid3_id3v2::IsValidID3v2FrameName($frame_name, $this->majorversion)) {
|
||||
return false;
|
||||
}
|
||||
$framedata = '';
|
||||
|
||||
if (($this->majorversion < 3) || ($this->majorversion > 4)) {
|
||||
|
||||
$this->errors[] = 'Only ID3v2.3 and ID3v2.4 are supported in GenerateID3v2FrameData()';
|
||||
|
||||
} else { // $this->majorversion 3 or 4
|
||||
|
||||
switch ($frame_name) {
|
||||
|
@ -795,7 +815,7 @@ class getid3_write_id3v2
|
|||
// Counter $xx xx xx xx (xx ...)
|
||||
if (!$this->IsWithinBitRange($source_data_array['rating'], 8, false)) {
|
||||
$this->errors[] = 'Invalid Rating byte in '.$frame_name.' ('.$source_data_array['rating'].') (range = 0 to 255)';
|
||||
} elseif (!IsValidEmail($source_data_array['email'])) {
|
||||
} elseif (!$this->IsValidEmail($source_data_array['email'])) {
|
||||
$this->errors[] = 'Invalid Email in '.$frame_name.' ('.$source_data_array['email'].')';
|
||||
} else {
|
||||
$framedata .= str_replace("\x00", '', $source_data_array['email'])."\x00";
|
||||
|
@ -1154,17 +1174,15 @@ class getid3_write_id3v2
|
|||
return $framedata;
|
||||
}
|
||||
|
||||
public function ID3v2FrameIsAllowed($frame_name, $source_data_array)
|
||||
{
|
||||
static $PreviousFrames = [];
|
||||
public function ID3v2FrameIsAllowed($frame_name, $source_data_array) {
|
||||
static $PreviousFrames = array();
|
||||
|
||||
if ($frame_name === null) {
|
||||
// if the writing functions are called multiple times, the static array needs to be
|
||||
// cleared - this can be done by calling $this->ID3v2FrameIsAllowed(null, '')
|
||||
$PreviousFrames = [];
|
||||
$PreviousFrames = array();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->majorversion == 4) {
|
||||
switch ($frame_name) {
|
||||
case 'UFID':
|
||||
|
@ -1289,7 +1307,9 @@ class getid3_write_id3v2
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} elseif ($this->majorversion == 3) {
|
||||
|
||||
switch ($frame_name) {
|
||||
case 'UFID':
|
||||
case 'AENC':
|
||||
|
@ -1410,7 +1430,9 @@ class getid3_write_id3v2
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} elseif ($this->majorversion == 2) {
|
||||
|
||||
switch ($frame_name) {
|
||||
case 'UFI':
|
||||
case 'CRM':
|
||||
|
@ -1508,8 +1530,7 @@ class getid3_write_id3v2
|
|||
return true;
|
||||
}
|
||||
|
||||
public function GenerateID3v2Tag($noerrorsonly = true)
|
||||
{
|
||||
public function GenerateID3v2Tag($noerrorsonly=true) {
|
||||
$this->ID3v2FrameIsAllowed(null, ''); // clear static array in case this isn't the first call to $this->GenerateID3v2Tag()
|
||||
|
||||
$tagstring = '';
|
||||
|
@ -1614,7 +1635,7 @@ class getid3_write_id3v2
|
|||
$tagheader = 'ID3';
|
||||
$tagheader .= chr($this->majorversion);
|
||||
$tagheader .= chr($this->minorversion);
|
||||
$tagheader .= $this->GenerateID3v2TagFlags(['unsynchronisation'=>$TagUnsynchronisation]);
|
||||
$tagheader .= $this->GenerateID3v2TagFlags(array('unsynchronisation'=>$TagUnsynchronisation));
|
||||
$tagheader .= getid3_lib::BigEndian2String(strlen($tagstring), 4, true);
|
||||
|
||||
return $tagheader.$tagstring;
|
||||
|
@ -1623,8 +1644,7 @@ class getid3_write_id3v2
|
|||
return false;
|
||||
}
|
||||
|
||||
public function ID3v2IsValidPriceString($pricestring)
|
||||
{
|
||||
public function ID3v2IsValidPriceString($pricestring) {
|
||||
if (getid3_id3v2::LanguageLookup(substr($pricestring, 0, 3), true) == '') {
|
||||
return false;
|
||||
} elseif (!$this->IsANumber(substr($pricestring, 3), true)) {
|
||||
|
@ -1633,8 +1653,7 @@ class getid3_write_id3v2
|
|||
return true;
|
||||
}
|
||||
|
||||
public function ID3v2FrameFlagsLookupTagAlter($framename)
|
||||
{
|
||||
public function ID3v2FrameFlagsLookupTagAlter($framename) {
|
||||
// unfinished
|
||||
switch ($framename) {
|
||||
case 'RGAD':
|
||||
|
@ -1646,8 +1665,7 @@ class getid3_write_id3v2
|
|||
return $allow;
|
||||
}
|
||||
|
||||
public function ID3v2FrameFlagsLookupFileAlter($framename)
|
||||
{
|
||||
public function ID3v2FrameFlagsLookupFileAlter($framename) {
|
||||
// unfinished
|
||||
switch ($framename) {
|
||||
case 'RGAD':
|
||||
|
@ -1660,8 +1678,7 @@ class getid3_write_id3v2
|
|||
}
|
||||
}
|
||||
|
||||
public function ID3v2IsValidETCOevent($eventid)
|
||||
{
|
||||
public function ID3v2IsValidETCOevent($eventid) {
|
||||
if (($eventid < 0) || ($eventid > 0xFF)) {
|
||||
// outside range of 1 byte
|
||||
return false;
|
||||
|
@ -1681,8 +1698,7 @@ class getid3_write_id3v2
|
|||
return true;
|
||||
}
|
||||
|
||||
public function ID3v2IsValidSYLTtype($contenttype)
|
||||
{
|
||||
public function ID3v2IsValidSYLTtype($contenttype) {
|
||||
if (($contenttype >= 0) && ($contenttype <= 8) && ($this->majorversion == 4)) {
|
||||
return true;
|
||||
} elseif (($contenttype >= 0) && ($contenttype <= 6) && ($this->majorversion == 3)) {
|
||||
|
@ -1691,24 +1707,21 @@ class getid3_write_id3v2
|
|||
return false;
|
||||
}
|
||||
|
||||
public function ID3v2IsValidRVA2channeltype($channeltype)
|
||||
{
|
||||
public function ID3v2IsValidRVA2channeltype($channeltype) {
|
||||
if (($channeltype >= 0) && ($channeltype <= 8) && ($this->majorversion == 4)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ID3v2IsValidAPICpicturetype($picturetype)
|
||||
{
|
||||
public function ID3v2IsValidAPICpicturetype($picturetype) {
|
||||
if (($picturetype >= 0) && ($picturetype <= 0x14) && ($this->majorversion >= 2) && ($this->majorversion <= 4)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ID3v2IsValidAPICimageformat($imageformat)
|
||||
{
|
||||
public function ID3v2IsValidAPICimageformat($imageformat) {
|
||||
if ($imageformat == '-->') {
|
||||
return true;
|
||||
} elseif ($this->majorversion == 2) {
|
||||
|
@ -1723,46 +1736,41 @@ class getid3_write_id3v2
|
|||
return false;
|
||||
}
|
||||
|
||||
public function ID3v2IsValidCOMRreceivedAs($receivedas)
|
||||
{
|
||||
public function ID3v2IsValidCOMRreceivedAs($receivedas) {
|
||||
if (($this->majorversion >= 3) && ($receivedas >= 0) && ($receivedas <= 8)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ID3v2IsValidRGADname($RGADname)
|
||||
{
|
||||
public static function ID3v2IsValidRGADname($RGADname) {
|
||||
if (($RGADname >= 0) && ($RGADname <= 2)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ID3v2IsValidRGADoriginator($RGADoriginator)
|
||||
{
|
||||
public static function ID3v2IsValidRGADoriginator($RGADoriginator) {
|
||||
if (($RGADoriginator >= 0) && ($RGADoriginator <= 3)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ID3v2IsValidTextEncoding($textencodingbyte)
|
||||
{
|
||||
public function ID3v2IsValidTextEncoding($textencodingbyte) {
|
||||
// 0 = ISO-8859-1
|
||||
// 1 = UTF-16 with BOM
|
||||
// 2 = UTF-16BE without BOM
|
||||
// 3 = UTF-8
|
||||
static $ID3v2IsValidTextEncoding_cache = [
|
||||
2 => [true, true], // ID3v2.2 - allow 0=ISO-8859-1, 1=UTF-16
|
||||
3 => [true, true], // ID3v2.3 - allow 0=ISO-8859-1, 1=UTF-16
|
||||
4 => [true, true, true, true], // ID3v2.4 - allow 0=ISO-8859-1, 1=UTF-16, 2=UTF-16BE, 3=UTF-8
|
||||
];
|
||||
static $ID3v2IsValidTextEncoding_cache = array(
|
||||
2 => array(true, true), // ID3v2.2 - allow 0=ISO-8859-1, 1=UTF-16
|
||||
3 => array(true, true), // ID3v2.3 - allow 0=ISO-8859-1, 1=UTF-16
|
||||
4 => array(true, true, true, true), // ID3v2.4 - allow 0=ISO-8859-1, 1=UTF-16, 2=UTF-16BE, 3=UTF-8
|
||||
);
|
||||
return isset($ID3v2IsValidTextEncoding_cache[$this->majorversion][$textencodingbyte]);
|
||||
}
|
||||
|
||||
public function Unsynchronise($data)
|
||||
{
|
||||
public static function Unsynchronise($data) {
|
||||
// Whenever a false synchronisation is found within the tag, one zeroed
|
||||
// byte is inserted after the first false synchronisation byte. The
|
||||
// format of a correct sync that should be altered by ID3 encoders is as
|
||||
|
@ -1792,8 +1800,7 @@ class getid3_write_id3v2
|
|||
return $unsyncheddata;
|
||||
}
|
||||
|
||||
public function is_hash($var)
|
||||
{
|
||||
public function is_hash($var) {
|
||||
// written by dev-nullØchristophe*vg
|
||||
// taken from http://www.php.net/manual/en/function.array-merge-recursive.php
|
||||
if (is_array($var)) {
|
||||
|
@ -1808,13 +1815,12 @@ class getid3_write_id3v2
|
|||
return false;
|
||||
}
|
||||
|
||||
public function array_join_merge($arr1, $arr2)
|
||||
{
|
||||
public function array_join_merge($arr1, $arr2) {
|
||||
// written by dev-nullØchristophe*vg
|
||||
// taken from http://www.php.net/manual/en/function.array-merge-recursive.php
|
||||
if (is_array($arr1) && is_array($arr2)) {
|
||||
// the same -> merge
|
||||
$new_array = [];
|
||||
$new_array = array();
|
||||
|
||||
if ($this->is_hash($arr1) && $this->is_hash($arr2)) {
|
||||
// hashes -> merge based on keys
|
||||
|
@ -1833,16 +1839,11 @@ class getid3_write_id3v2
|
|||
}
|
||||
}
|
||||
|
||||
public function IsValidMIMEstring($mimestring)
|
||||
{
|
||||
if ((strlen($mimestring) >= 3) && (strpos($mimestring, '/') > 0) && (strpos($mimestring, '/') < (strlen($mimestring) - 1))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
public static function IsValidMIMEstring($mimestring) {
|
||||
return preg_match('#^.+/.+$#', $mimestring);
|
||||
}
|
||||
|
||||
public function IsWithinBitRange($number, $maxbits, $signed = false)
|
||||
{
|
||||
public static function IsWithinBitRange($number, $maxbits, $signed=false) {
|
||||
if ($signed) {
|
||||
if (($number > (0 - pow(2, $maxbits - 1))) && ($number <= pow(2, $maxbits - 1))) {
|
||||
return true;
|
||||
|
@ -1855,20 +1856,15 @@ class getid3_write_id3v2
|
|||
return false;
|
||||
}
|
||||
|
||||
public function safe_parse_url($url)
|
||||
{
|
||||
$parts = @parse_url($url);
|
||||
$parts['scheme'] = (isset($parts['scheme']) ? $parts['scheme'] : '');
|
||||
$parts['host'] = (isset($parts['host']) ? $parts['host'] : '');
|
||||
$parts['user'] = (isset($parts['user']) ? $parts['user'] : '');
|
||||
$parts['pass'] = (isset($parts['pass']) ? $parts['pass'] : '');
|
||||
$parts['path'] = (isset($parts['path']) ? $parts['path'] : '');
|
||||
$parts['query'] = (isset($parts['query']) ? $parts['query'] : '');
|
||||
return $parts;
|
||||
public static function IsValidEmail($email) {
|
||||
if (function_exists('filter_var')) {
|
||||
return filter_var($email, FILTER_VALIDATE_EMAIL);
|
||||
}
|
||||
// VERY crude email validation
|
||||
return preg_match('#^[^ ]+@[a-z\\-\\.]+\\.[a-z]{2,}$#', $email);
|
||||
}
|
||||
|
||||
public function IsValidURL($url, $allowUserPass = false)
|
||||
{
|
||||
public static function IsValidURL($url, $allowUserPass=false) {
|
||||
if ($url == '') {
|
||||
return false;
|
||||
}
|
||||
|
@ -1879,6 +1875,10 @@ class getid3_write_id3v2
|
|||
return false;
|
||||
}
|
||||
}
|
||||
// 2016-06-08: relax URL checking to avoid falsely rejecting valid URLs, leave URL validation to the user
|
||||
// http://www.getid3.org/phpBB3/viewtopic.php?t=1926
|
||||
return true;
|
||||
/*
|
||||
if ($parts = $this->safe_parse_url($url)) {
|
||||
if (($parts['scheme'] != 'http') && ($parts['scheme'] != 'https') && ($parts['scheme'] != 'ftp') && ($parts['scheme'] != 'gopher')) {
|
||||
return false;
|
||||
|
@ -1897,51 +1897,94 @@ class getid3_write_id3v2
|
|||
}
|
||||
}
|
||||
return false;
|
||||
*/
|
||||
}
|
||||
|
||||
public static function ID3v2ShortFrameNameLookup($majorversion, $long_description)
|
||||
{
|
||||
public static function safe_parse_url($url) {
|
||||
$parts = @parse_url($url);
|
||||
$parts['scheme'] = (isset($parts['scheme']) ? $parts['scheme'] : '');
|
||||
$parts['host'] = (isset($parts['host']) ? $parts['host'] : '');
|
||||
$parts['user'] = (isset($parts['user']) ? $parts['user'] : '');
|
||||
$parts['pass'] = (isset($parts['pass']) ? $parts['pass'] : '');
|
||||
$parts['path'] = (isset($parts['path']) ? $parts['path'] : '');
|
||||
$parts['query'] = (isset($parts['query']) ? $parts['query'] : '');
|
||||
return $parts;
|
||||
}
|
||||
|
||||
public static function ID3v2ShortFrameNameLookup($majorversion, $long_description) {
|
||||
$long_description = str_replace(' ', '_', strtolower(trim($long_description)));
|
||||
static $ID3v2ShortFrameNameLookup = [];
|
||||
static $ID3v2ShortFrameNameLookup = array();
|
||||
if (empty($ID3v2ShortFrameNameLookup)) {
|
||||
|
||||
// The following are unique to ID3v2.2
|
||||
$ID3v2ShortFrameNameLookup[2]['recommended_buffer_size'] = 'BUF';
|
||||
$ID3v2ShortFrameNameLookup[2]['comment'] = 'COM';
|
||||
$ID3v2ShortFrameNameLookup[2]['audio_encryption'] = 'CRA';
|
||||
$ID3v2ShortFrameNameLookup[2]['encrypted_meta_frame'] = 'CRM';
|
||||
$ID3v2ShortFrameNameLookup[2]['equalisation'] = 'EQU';
|
||||
$ID3v2ShortFrameNameLookup[2]['event_timing_codes'] = 'ETC';
|
||||
$ID3v2ShortFrameNameLookup[2]['general_encapsulated_object'] = 'GEO';
|
||||
$ID3v2ShortFrameNameLookup[2]['involved_people_list'] = 'IPL';
|
||||
$ID3v2ShortFrameNameLookup[2]['linked_information'] = 'LNK';
|
||||
$ID3v2ShortFrameNameLookup[2]['music_cd_identifier'] = 'MCI';
|
||||
$ID3v2ShortFrameNameLookup[2]['mpeg_location_lookup_table'] = 'MLL';
|
||||
$ID3v2ShortFrameNameLookup[2]['attached_picture'] = 'PIC';
|
||||
$ID3v2ShortFrameNameLookup[2]['popularimeter'] = 'POP';
|
||||
$ID3v2ShortFrameNameLookup[2]['reverb'] = 'REV';
|
||||
$ID3v2ShortFrameNameLookup[2]['relative_volume_adjustment'] = 'RVA';
|
||||
$ID3v2ShortFrameNameLookup[2]['synchronised_lyric'] = 'SLT';
|
||||
$ID3v2ShortFrameNameLookup[2]['synchronised_tempo_codes'] = 'STC';
|
||||
$ID3v2ShortFrameNameLookup[2]['album'] = 'TAL';
|
||||
$ID3v2ShortFrameNameLookup[2]['beats_per_minute'] = 'TBP';
|
||||
$ID3v2ShortFrameNameLookup[2]['bpm'] = 'TBP';
|
||||
$ID3v2ShortFrameNameLookup[2]['composer'] = 'TCM';
|
||||
$ID3v2ShortFrameNameLookup[2]['genre'] = 'TCO';
|
||||
$ID3v2ShortFrameNameLookup[2]['itunescompilation'] = 'TCP';
|
||||
$ID3v2ShortFrameNameLookup[2]['copyright'] = 'TCR';
|
||||
$ID3v2ShortFrameNameLookup[2]['part_of_a_compilation'] = 'TCP';
|
||||
$ID3v2ShortFrameNameLookup[2]['copyright_message'] = 'TCR';
|
||||
$ID3v2ShortFrameNameLookup[2]['date'] = 'TDA';
|
||||
$ID3v2ShortFrameNameLookup[2]['playlist_delay'] = 'TDY';
|
||||
$ID3v2ShortFrameNameLookup[2]['encoded_by'] = 'TEN';
|
||||
$ID3v2ShortFrameNameLookup[2]['file_type'] = 'TFT';
|
||||
$ID3v2ShortFrameNameLookup[2]['time'] = 'TIM';
|
||||
$ID3v2ShortFrameNameLookup[2]['initial_key'] = 'TKE';
|
||||
$ID3v2ShortFrameNameLookup[2]['language'] = 'TLA';
|
||||
$ID3v2ShortFrameNameLookup[2]['length'] = 'TLE';
|
||||
$ID3v2ShortFrameNameLookup[2]['media_type'] = 'TMT';
|
||||
$ID3v2ShortFrameNameLookup[2]['original_artist'] = 'TOA';
|
||||
$ID3v2ShortFrameNameLookup[2]['original_filename'] = 'TOF';
|
||||
$ID3v2ShortFrameNameLookup[2]['original_lyricist'] = 'TOL';
|
||||
$ID3v2ShortFrameNameLookup[2]['original_album_title'] = 'TOT';
|
||||
$ID3v2ShortFrameNameLookup[2]['original_year'] = 'TOR';
|
||||
$ID3v2ShortFrameNameLookup[2]['original_album'] = 'TOT';
|
||||
$ID3v2ShortFrameNameLookup[2]['artist'] = 'TP1';
|
||||
$ID3v2ShortFrameNameLookup[2]['band'] = 'TP2';
|
||||
$ID3v2ShortFrameNameLookup[2]['conductor'] = 'TP3';
|
||||
$ID3v2ShortFrameNameLookup[2]['remixer'] = 'TP4';
|
||||
$ID3v2ShortFrameNameLookup[2]['part_of_a_set'] = 'TPA';
|
||||
$ID3v2ShortFrameNameLookup[2]['publisher'] = 'TPB';
|
||||
$ID3v2ShortFrameNameLookup[2]['isrc'] = 'TRC';
|
||||
$ID3v2ShortFrameNameLookup[2]['recording_dates'] = 'TRD';
|
||||
$ID3v2ShortFrameNameLookup[2]['tracknumber'] = 'TRK';
|
||||
$ID3v2ShortFrameNameLookup[2]['track_number'] = 'TRK';
|
||||
$ID3v2ShortFrameNameLookup[2]['album_artist_sort_order'] = 'TS2';
|
||||
$ID3v2ShortFrameNameLookup[2]['album_sort_order'] = 'TSA';
|
||||
$ID3v2ShortFrameNameLookup[2]['composer_sort_order'] = 'TSC';
|
||||
$ID3v2ShortFrameNameLookup[2]['size'] = 'TSI';
|
||||
$ID3v2ShortFrameNameLookup[2]['performer_sort_order'] = 'TSP';
|
||||
$ID3v2ShortFrameNameLookup[2]['encoder_settings'] = 'TSS';
|
||||
$ID3v2ShortFrameNameLookup[2]['description'] = 'TT1';
|
||||
$ID3v2ShortFrameNameLookup[2]['title_sort_order'] = 'TST';
|
||||
$ID3v2ShortFrameNameLookup[2]['content_group_description'] = 'TT1';
|
||||
$ID3v2ShortFrameNameLookup[2]['title'] = 'TT2';
|
||||
$ID3v2ShortFrameNameLookup[2]['subtitle'] = 'TT3';
|
||||
$ID3v2ShortFrameNameLookup[2]['lyricist'] = 'TXT';
|
||||
$ID3v2ShortFrameNameLookup[2]['user_text'] = 'TXX';
|
||||
$ID3v2ShortFrameNameLookup[2]['text'] = 'TXX';
|
||||
$ID3v2ShortFrameNameLookup[2]['year'] = 'TYE';
|
||||
$ID3v2ShortFrameNameLookup[2]['unique_file_identifier'] = 'UFI';
|
||||
$ID3v2ShortFrameNameLookup[2]['unsynchronised_lyrics'] = 'ULT';
|
||||
$ID3v2ShortFrameNameLookup[2]['unsychronised_lyric'] = 'ULT';
|
||||
$ID3v2ShortFrameNameLookup[2]['url_file'] = 'WAF';
|
||||
$ID3v2ShortFrameNameLookup[2]['url_artist'] = 'WAR';
|
||||
$ID3v2ShortFrameNameLookup[2]['url_source'] = 'WAS';
|
||||
$ID3v2ShortFrameNameLookup[2]['copyright_information'] = 'WCP';
|
||||
$ID3v2ShortFrameNameLookup[2]['commercial_information'] = 'WCM';
|
||||
$ID3v2ShortFrameNameLookup[2]['copyright'] = 'WCP';
|
||||
$ID3v2ShortFrameNameLookup[2]['url_publisher'] = 'WPB';
|
||||
$ID3v2ShortFrameNameLookup[2]['url_user'] = 'WXX';
|
||||
|
||||
|
@ -1950,7 +1993,7 @@ class getid3_write_id3v2
|
|||
$ID3v2ShortFrameNameLookup[3]['attached_picture'] = 'APIC';
|
||||
$ID3v2ShortFrameNameLookup[3]['picture'] = 'APIC';
|
||||
$ID3v2ShortFrameNameLookup[3]['comment'] = 'COMM';
|
||||
$ID3v2ShortFrameNameLookup[3]['commercial'] = 'COMR';
|
||||
$ID3v2ShortFrameNameLookup[3]['commercial_frame'] = 'COMR';
|
||||
$ID3v2ShortFrameNameLookup[3]['encryption_method_registration'] = 'ENCR';
|
||||
$ID3v2ShortFrameNameLookup[3]['event_timing_codes'] = 'ETCO';
|
||||
$ID3v2ShortFrameNameLookup[3]['general_encapsulated_object'] = 'GEOB';
|
||||
|
@ -1958,22 +2001,23 @@ class getid3_write_id3v2
|
|||
$ID3v2ShortFrameNameLookup[3]['linked_information'] = 'LINK';
|
||||
$ID3v2ShortFrameNameLookup[3]['music_cd_identifier'] = 'MCDI';
|
||||
$ID3v2ShortFrameNameLookup[3]['mpeg_location_lookup_table'] = 'MLLT';
|
||||
$ID3v2ShortFrameNameLookup[3]['ownership'] = 'OWNE';
|
||||
$ID3v2ShortFrameNameLookup[3]['ownership_frame'] = 'OWNE';
|
||||
$ID3v2ShortFrameNameLookup[3]['play_counter'] = 'PCNT';
|
||||
$ID3v2ShortFrameNameLookup[3]['popularimeter'] = 'POPM';
|
||||
$ID3v2ShortFrameNameLookup[3]['position_synchronisation'] = 'POSS';
|
||||
$ID3v2ShortFrameNameLookup[3]['private'] = 'PRIV';
|
||||
$ID3v2ShortFrameNameLookup[3]['position_synchronisation_frame'] = 'POSS';
|
||||
$ID3v2ShortFrameNameLookup[3]['private_frame'] = 'PRIV';
|
||||
$ID3v2ShortFrameNameLookup[3]['recommended_buffer_size'] = 'RBUF';
|
||||
$ID3v2ShortFrameNameLookup[3]['replay_gain_adjustment'] = 'RGAD';
|
||||
$ID3v2ShortFrameNameLookup[3]['reverb'] = 'RVRB';
|
||||
$ID3v2ShortFrameNameLookup[3]['synchronised_lyrics'] = 'SYLT';
|
||||
$ID3v2ShortFrameNameLookup[3]['synchronised_lyric'] = 'SYLT';
|
||||
$ID3v2ShortFrameNameLookup[3]['synchronised_tempo_codes'] = 'SYTC';
|
||||
$ID3v2ShortFrameNameLookup[3]['album'] = 'TALB';
|
||||
$ID3v2ShortFrameNameLookup[3]['beats_per_minute'] = 'TBPM';
|
||||
$ID3v2ShortFrameNameLookup[3]['bpm'] = 'TBPM';
|
||||
$ID3v2ShortFrameNameLookup[3]['itunescompilation'] = 'TCMP';
|
||||
$ID3v2ShortFrameNameLookup[3]['part_of_a_compilation'] = 'TCMP';
|
||||
$ID3v2ShortFrameNameLookup[3]['composer'] = 'TCOM';
|
||||
$ID3v2ShortFrameNameLookup[3]['genre'] = 'TCON';
|
||||
$ID3v2ShortFrameNameLookup[3]['copyright'] = 'TCOP';
|
||||
$ID3v2ShortFrameNameLookup[3]['copyright_message'] = 'TCOP';
|
||||
$ID3v2ShortFrameNameLookup[3]['playlist_delay'] = 'TDLY';
|
||||
$ID3v2ShortFrameNameLookup[3]['encoded_by'] = 'TENC';
|
||||
$ID3v2ShortFrameNameLookup[3]['lyricist'] = 'TEXT';
|
||||
|
@ -1985,7 +2029,7 @@ class getid3_write_id3v2
|
|||
$ID3v2ShortFrameNameLookup[3]['language'] = 'TLAN';
|
||||
$ID3v2ShortFrameNameLookup[3]['length'] = 'TLEN';
|
||||
$ID3v2ShortFrameNameLookup[3]['media_type'] = 'TMED';
|
||||
$ID3v2ShortFrameNameLookup[3]['original_album_title'] = 'TOAL';
|
||||
$ID3v2ShortFrameNameLookup[3]['original_album'] = 'TOAL';
|
||||
$ID3v2ShortFrameNameLookup[3]['original_filename'] = 'TOFN';
|
||||
$ID3v2ShortFrameNameLookup[3]['original_lyricist'] = 'TOLY';
|
||||
$ID3v2ShortFrameNameLookup[3]['original_artist'] = 'TOPE';
|
||||
|
@ -2000,19 +2044,24 @@ class getid3_write_id3v2
|
|||
$ID3v2ShortFrameNameLookup[3]['track_number'] = 'TRCK';
|
||||
$ID3v2ShortFrameNameLookup[3]['internet_radio_station_name'] = 'TRSN';
|
||||
$ID3v2ShortFrameNameLookup[3]['internet_radio_station_owner'] = 'TRSO';
|
||||
$ID3v2ShortFrameNameLookup[3]['album_artist_sort_order'] = 'TSO2';
|
||||
$ID3v2ShortFrameNameLookup[3]['album_sort_order'] = 'TSOA';
|
||||
$ID3v2ShortFrameNameLookup[3]['composer_sort_order'] = 'TSOC';
|
||||
$ID3v2ShortFrameNameLookup[3]['performer_sort_order'] = 'TSOP';
|
||||
$ID3v2ShortFrameNameLookup[3]['title_sort_order'] = 'TSOT';
|
||||
$ID3v2ShortFrameNameLookup[3]['isrc'] = 'TSRC';
|
||||
$ID3v2ShortFrameNameLookup[3]['encoder_settings'] = 'TSSE';
|
||||
$ID3v2ShortFrameNameLookup[3]['user_text'] = 'TXXX';
|
||||
$ID3v2ShortFrameNameLookup[3]['text'] = 'TXXX';
|
||||
$ID3v2ShortFrameNameLookup[3]['unique_file_identifier'] = 'UFID';
|
||||
$ID3v2ShortFrameNameLookup[3]['terms_of_use'] = 'USER';
|
||||
$ID3v2ShortFrameNameLookup[3]['unsynchronised_lyrics'] = 'USLT';
|
||||
$ID3v2ShortFrameNameLookup[3]['commercial'] = 'WCOM';
|
||||
$ID3v2ShortFrameNameLookup[3]['copyright_information'] = 'WCOP';
|
||||
$ID3v2ShortFrameNameLookup[3]['unsychronised_lyric'] = 'USLT';
|
||||
$ID3v2ShortFrameNameLookup[3]['commercial_information'] = 'WCOM';
|
||||
$ID3v2ShortFrameNameLookup[3]['copyright'] = 'WCOP';
|
||||
$ID3v2ShortFrameNameLookup[3]['url_file'] = 'WOAF';
|
||||
$ID3v2ShortFrameNameLookup[3]['url_artist'] = 'WOAR';
|
||||
$ID3v2ShortFrameNameLookup[3]['url_source'] = 'WOAS';
|
||||
$ID3v2ShortFrameNameLookup[3]['url_station'] = 'WORS';
|
||||
$ID3v2ShortFrameNameLookup[3]['payment'] = 'WPAY';
|
||||
$ID3v2ShortFrameNameLookup[3]['url_payment'] = 'WPAY';
|
||||
$ID3v2ShortFrameNameLookup[3]['url_publisher'] = 'WPUB';
|
||||
$ID3v2ShortFrameNameLookup[3]['url_user'] = 'WXXX';
|
||||
|
||||
|
@ -2026,7 +2075,7 @@ class getid3_write_id3v2
|
|||
$ID3v2ShortFrameNameLookup[3]['relative_volume_adjustment'] = 'RVAD';
|
||||
$ID3v2ShortFrameNameLookup[3]['date'] = 'TDAT';
|
||||
$ID3v2ShortFrameNameLookup[3]['time'] = 'TIME';
|
||||
$ID3v2ShortFrameNameLookup[3]['original_release_year'] = 'TORY';
|
||||
$ID3v2ShortFrameNameLookup[3]['original_year'] = 'TORY';
|
||||
$ID3v2ShortFrameNameLookup[3]['recording_dates'] = 'TRDA';
|
||||
$ID3v2ShortFrameNameLookup[3]['size'] = 'TSIZ';
|
||||
$ID3v2ShortFrameNameLookup[3]['year'] = 'TYER';
|
||||
|
@ -2036,8 +2085,8 @@ class getid3_write_id3v2
|
|||
$ID3v2ShortFrameNameLookup[4]['audio_seek_point_index'] = 'ASPI';
|
||||
$ID3v2ShortFrameNameLookup[4]['equalisation'] = 'EQU2';
|
||||
$ID3v2ShortFrameNameLookup[4]['relative_volume_adjustment'] = 'RVA2';
|
||||
$ID3v2ShortFrameNameLookup[4]['seek'] = 'SEEK';
|
||||
$ID3v2ShortFrameNameLookup[4]['signature'] = 'SIGN';
|
||||
$ID3v2ShortFrameNameLookup[4]['seek_frame'] = 'SEEK';
|
||||
$ID3v2ShortFrameNameLookup[4]['signature_frame'] = 'SIGN';
|
||||
$ID3v2ShortFrameNameLookup[4]['encoding_time'] = 'TDEN';
|
||||
$ID3v2ShortFrameNameLookup[4]['original_release_time'] = 'TDOR';
|
||||
$ID3v2ShortFrameNameLookup[4]['recording_time'] = 'TDRC';
|
||||
|
@ -2053,5 +2102,8 @@ class getid3_write_id3v2
|
|||
$ID3v2ShortFrameNameLookup[4]['set_subtitle'] = 'TSST';
|
||||
}
|
||||
return (isset($ID3v2ShortFrameNameLookup[$majorversion][strtolower($long_description)]) ? $ID3v2ShortFrameNameLookup[$majorversion][strtolower($long_description)] : '');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -20,26 +20,24 @@ class getid3_write_lyrics3
|
|||
public $filename;
|
||||
public $tag_data;
|
||||
//public $lyrics3_version = 2; // 1 or 2
|
||||
public $warnings = []; // any non-critical errors will be stored here
|
||||
public $errors = []; // any critical errors will be stored here
|
||||
public $warnings = array(); // any non-critical errors will be stored here
|
||||
public $errors = array(); // any critical errors will be stored here
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
public function __construct() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function WriteLyrics3()
|
||||
{
|
||||
public function WriteLyrics3() {
|
||||
$this->errors[] = 'WriteLyrics3() not yet functional - cannot write Lyrics3';
|
||||
return false;
|
||||
}
|
||||
public function DeleteLyrics3()
|
||||
{
|
||||
public function DeleteLyrics3() {
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$ThisFileInfo = $getID3->analyze($this->filename);
|
||||
if (isset($ThisFileInfo['lyrics3']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) {
|
||||
if (is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) {
|
||||
|
||||
flock($fp, LOCK_EX);
|
||||
$oldignoreuserabort = ignore_user_abort(true);
|
||||
|
||||
|
@ -61,6 +59,7 @@ class getid3_write_lyrics3
|
|||
ignore_user_abort($oldignoreuserabort);
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
$this->errors[] = 'Cannot fopen('.$this->filename.', "a+b")';
|
||||
return false;
|
||||
|
@ -69,4 +68,5 @@ class getid3_write_lyrics3
|
|||
// no Lyrics3 present
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,16 +20,14 @@ class getid3_write_metaflac
|
|||
|
||||
public $filename;
|
||||
public $tag_data;
|
||||
public $warnings = []; // any non-critical errors will be stored here
|
||||
public $errors = []; // any critical errors will be stored here
|
||||
public $warnings = array(); // any non-critical errors will be stored here
|
||||
public $errors = array(); // any critical errors will be stored here
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
public function __construct() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function WriteMetaFLAC()
|
||||
{
|
||||
public function WriteMetaFLAC() {
|
||||
|
||||
if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
|
||||
$this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not written';
|
||||
|
@ -45,6 +43,7 @@ class getid3_write_metaflac
|
|||
}
|
||||
}
|
||||
fclose($fpcomments);
|
||||
|
||||
} else {
|
||||
$this->errors[] = 'failed to open temporary tags file, tags not written - fopen("'.$tempcommentsfilename.'", "wb")';
|
||||
return false;
|
||||
|
@ -52,6 +51,7 @@ class getid3_write_metaflac
|
|||
|
||||
$oldignoreuserabort = ignore_user_abort(true);
|
||||
if (GETID3_OS_ISWINDOWS) {
|
||||
|
||||
if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) {
|
||||
//$commandline = '"'.GETID3_HELPERAPPSDIR.'metaflac.exe" --no-utf8-convert --remove-all-tags --import-tags-from="'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"';
|
||||
// metaflac works fine if you copy-paste the above commandline into a command prompt,
|
||||
|
@ -77,10 +77,13 @@ class getid3_write_metaflac
|
|||
} else {
|
||||
$metaflacError = 'metaflac.exe not found in '.GETID3_HELPERAPPSDIR;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// It's simpler on *nix
|
||||
$commandline = 'metaflac --no-utf8-convert --remove-all-tags --import-tags-from='.escapeshellarg($tempcommentsfilename).' '.escapeshellarg($this->filename).' 2>&1';
|
||||
$metaflacError = `$commandline`;
|
||||
|
||||
}
|
||||
|
||||
// Remove temporary comments file
|
||||
|
@ -88,16 +91,17 @@ class getid3_write_metaflac
|
|||
ignore_user_abort($oldignoreuserabort);
|
||||
|
||||
if (!empty($metaflacError)) {
|
||||
|
||||
$this->errors[] = 'System call to metaflac failed with this message returned: '."\n\n".$metaflacError;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function DeleteMetaFLAC()
|
||||
{
|
||||
public function DeleteMetaFLAC() {
|
||||
|
||||
if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
|
||||
$this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not deleted';
|
||||
|
@ -106,6 +110,7 @@ class getid3_write_metaflac
|
|||
|
||||
$oldignoreuserabort = ignore_user_abort(true);
|
||||
if (GETID3_OS_ISWINDOWS) {
|
||||
|
||||
if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) {
|
||||
// To at least see if there was a problem, compare file modification timestamps before and after writing
|
||||
clearstatcache();
|
||||
|
@ -123,10 +128,13 @@ class getid3_write_metaflac
|
|||
} else {
|
||||
$metaflacError = 'metaflac.exe not found in '.GETID3_HELPERAPPSDIR;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// It's simpler on *nix
|
||||
$commandline = 'metaflac --remove-all-tags "'.$this->filename.'" 2>&1';
|
||||
$metaflacError = `$commandline`;
|
||||
|
||||
}
|
||||
|
||||
ignore_user_abort($oldignoreuserabort);
|
||||
|
@ -139,8 +147,7 @@ class getid3_write_metaflac
|
|||
}
|
||||
|
||||
|
||||
public function CleanmetaflacName($originalcommentname)
|
||||
{
|
||||
public function CleanmetaflacName($originalcommentname) {
|
||||
// A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded.
|
||||
// ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through
|
||||
// 0x7A inclusive (a-z).
|
||||
|
@ -149,5 +156,7 @@ class getid3_write_metaflac
|
|||
// Thanks Chris Bolt <chris-getid3Øbolt*cx> for improving this function
|
||||
// note: *reg_replace() replaces nulls with empty string (not space)
|
||||
return strtoupper(preg_replace('#[^ -<>-}]#', ' ', str_replace("\x00", ' ', $originalcommentname)));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,8 +49,8 @@ class getid3_writetags
|
|||
{
|
||||
// public
|
||||
public $filename; // absolute filename of file to write tags to
|
||||
public $tagformats = []; // array of tag formats to write ('id3v1', 'id3v2.2', 'id2v2.3', 'id3v2.4', 'ape', 'vorbiscomment', 'metaflac', 'real')
|
||||
public $tag_data = [[]]; // 2-dimensional array of tag data (ex: $data['ARTIST'][0] = 'Elvis')
|
||||
public $tagformats = array(); // array of tag formats to write ('id3v1', 'id3v2.2', 'id2v2.3', 'id3v2.4', 'ape', 'vorbiscomment', 'metaflac', 'real')
|
||||
public $tag_data = array(array()); // 2-dimensional array of tag data (ex: $data['ARTIST'][0] = 'Elvis')
|
||||
public $tag_encoding = 'ISO-8859-1'; // text encoding used for tag data ('ISO-8859-1', 'UTF-8', 'UTF-16', 'UTF-16LE', 'UTF-16BE', )
|
||||
public $overwrite_tags = true; // if true will erase existing tag data and write only passed data; if false will merge passed data with existing tag data
|
||||
public $remove_other_tags = false; // if true will erase remove all existing tags and only write those passed in $tagformats; if false will ignore any tags not mentioned in $tagformats
|
||||
|
@ -58,20 +58,18 @@ class getid3_writetags
|
|||
public $id3v2_tag_language = 'eng'; // ISO-639-2 3-character language code needed for some ID3v2 frames (http://www.id3.org/iso639-2.html)
|
||||
public $id3v2_paddedlength = 4096; // minimum length of ID3v2 tags (will be padded to this length if tag data is shorter)
|
||||
|
||||
public $warnings = []; // any non-critical errors will be stored here
|
||||
public $errors = []; // any critical errors will be stored here
|
||||
public $warnings = array(); // any non-critical errors will be stored here
|
||||
public $errors = array(); // any critical errors will be stored here
|
||||
|
||||
// private
|
||||
private $ThisFileInfo; // analysis of file before writing
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
public function __construct() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function WriteTags()
|
||||
{
|
||||
public function WriteTags() {
|
||||
|
||||
if (empty($this->filename)) {
|
||||
$this->errors[] = 'filename is undefined in getid3_writetags';
|
||||
|
@ -86,13 +84,16 @@ class getid3_writetags
|
|||
return false;
|
||||
}
|
||||
|
||||
$TagFormatsToRemove = [];
|
||||
$TagFormatsToRemove = array();
|
||||
if (filesize($this->filename) == 0) {
|
||||
|
||||
// empty file special case - allow any tag format, don't check existing format
|
||||
// could be useful if you want to generate tag data for a non-existant file
|
||||
$this->ThisFileInfo = ['fileformat'=>''];
|
||||
$AllowedTagFormats = ['id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3'];
|
||||
$this->ThisFileInfo = array('fileformat'=>'');
|
||||
$AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3');
|
||||
|
||||
} else {
|
||||
|
||||
$getID3 = new getID3;
|
||||
$getID3->encoding = $this->tag_encoding;
|
||||
$this->ThisFileInfo = $getID3->analyze($this->filename);
|
||||
|
@ -103,19 +104,19 @@ class getid3_writetags
|
|||
case 'mp2':
|
||||
case 'mp1':
|
||||
case 'riff': // maybe not officially, but people do it anyway
|
||||
$AllowedTagFormats = ['id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3'];
|
||||
$AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3');
|
||||
break;
|
||||
|
||||
case 'mpc':
|
||||
$AllowedTagFormats = ['ape'];
|
||||
$AllowedTagFormats = array('ape');
|
||||
break;
|
||||
|
||||
case 'flac':
|
||||
$AllowedTagFormats = ['metaflac'];
|
||||
$AllowedTagFormats = array('metaflac');
|
||||
break;
|
||||
|
||||
case 'real':
|
||||
$AllowedTagFormats = ['real'];
|
||||
$AllowedTagFormats = array('real');
|
||||
break;
|
||||
|
||||
case 'ogg':
|
||||
|
@ -126,7 +127,7 @@ class getid3_writetags
|
|||
return false;
|
||||
break;
|
||||
case 'vorbis':
|
||||
$AllowedTagFormats = ['vorbiscomment'];
|
||||
$AllowedTagFormats = array('vorbiscomment');
|
||||
break;
|
||||
default:
|
||||
$this->errors[] = 'metaflac is not (yet) compatible with Ogg files other than OggVorbis';
|
||||
|
@ -136,7 +137,7 @@ class getid3_writetags
|
|||
break;
|
||||
|
||||
default:
|
||||
$AllowedTagFormats = [];
|
||||
$AllowedTagFormats = array();
|
||||
break;
|
||||
}
|
||||
foreach ($this->tagformats as $requested_tag_format) {
|
||||
|
@ -203,6 +204,7 @@ class getid3_writetags
|
|||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Validation of supplied data
|
||||
|
@ -330,11 +332,11 @@ class getid3_writetags
|
|||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function DeleteTags($TagFormatsToDelete)
|
||||
{
|
||||
public function DeleteTags($TagFormatsToDelete) {
|
||||
foreach ($TagFormatsToDelete as $DeleteTagFormat) {
|
||||
$success = false; // overridden if tag deletion is successful
|
||||
switch ($DeleteTagFormat) {
|
||||
|
@ -407,8 +409,7 @@ class getid3_writetags
|
|||
}
|
||||
|
||||
|
||||
public function MergeExistingTagData($TagFormat, &$tag_data)
|
||||
{
|
||||
public function MergeExistingTagData($TagFormat, &$tag_data) {
|
||||
// Merge supplied data with existing data, if requested
|
||||
if ($this->overwrite_tags) {
|
||||
// do nothing - ignore previous data
|
||||
|
@ -422,9 +423,8 @@ class getid3_writetags
|
|||
return true;
|
||||
}
|
||||
|
||||
public function FormatDataForAPE()
|
||||
{
|
||||
$ape_tag_data = [];
|
||||
public function FormatDataForAPE() {
|
||||
$ape_tag_data = array();
|
||||
foreach ($this->tag_data as $tag_key => $valuearray) {
|
||||
switch ($tag_key) {
|
||||
case 'ATTACHED_PICTURE':
|
||||
|
@ -450,8 +450,7 @@ class getid3_writetags
|
|||
}
|
||||
|
||||
|
||||
public function FormatDataForID3v1()
|
||||
{
|
||||
public function FormatDataForID3v1() {
|
||||
$tag_data_id3v1['genreid'] = 255;
|
||||
if (!empty($this->tag_data['GENRE'])) {
|
||||
foreach ($this->tag_data['GENRE'] as $key => $value) {
|
||||
|
@ -461,12 +460,12 @@ class getid3_writetags
|
|||
}
|
||||
}
|
||||
}
|
||||
$tag_data_id3v1['title'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['TITLE']) ? $this->tag_data['TITLE'] : [])));
|
||||
$tag_data_id3v1['artist'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['ARTIST']) ? $this->tag_data['ARTIST'] : [])));
|
||||
$tag_data_id3v1['album'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['ALBUM']) ? $this->tag_data['ALBUM'] : [])));
|
||||
$tag_data_id3v1['year'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['YEAR']) ? $this->tag_data['YEAR'] : [])));
|
||||
$tag_data_id3v1['comment'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['COMMENT']) ? $this->tag_data['COMMENT'] : [])));
|
||||
$tag_data_id3v1['track'] = intval(getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['TRACKNUMBER']) ? $this->tag_data['TRACKNUMBER'] : []))));
|
||||
$tag_data_id3v1['title'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['TITLE'] ) ? $this->tag_data['TITLE'] : array())));
|
||||
$tag_data_id3v1['artist'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['ARTIST'] ) ? $this->tag_data['ARTIST'] : array())));
|
||||
$tag_data_id3v1['album'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['ALBUM'] ) ? $this->tag_data['ALBUM'] : array())));
|
||||
$tag_data_id3v1['year'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['YEAR'] ) ? $this->tag_data['YEAR'] : array())));
|
||||
$tag_data_id3v1['comment'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['COMMENT'] ) ? $this->tag_data['COMMENT'] : array())));
|
||||
$tag_data_id3v1['track'] = intval(getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['TRACKNUMBER']) ? $this->tag_data['TRACKNUMBER'] : array()))));
|
||||
if ($tag_data_id3v1['track'] <= 0) {
|
||||
$tag_data_id3v1['track'] = '';
|
||||
}
|
||||
|
@ -475,13 +474,12 @@ class getid3_writetags
|
|||
return $tag_data_id3v1;
|
||||
}
|
||||
|
||||
public function FormatDataForID3v2($id3v2_majorversion)
|
||||
{
|
||||
$tag_data_id3v2 = [];
|
||||
public function FormatDataForID3v2($id3v2_majorversion) {
|
||||
$tag_data_id3v2 = array();
|
||||
|
||||
$ID3v2_text_encoding_lookup[2] = ['ISO-8859-1'=>0, 'UTF-16'=>1];
|
||||
$ID3v2_text_encoding_lookup[3] = ['ISO-8859-1'=>0, 'UTF-16'=>1];
|
||||
$ID3v2_text_encoding_lookup[4] = ['ISO-8859-1'=>0, 'UTF-16'=>1, 'UTF-16BE'=>2, 'UTF-8'=>3];
|
||||
$ID3v2_text_encoding_lookup[2] = array('ISO-8859-1'=>0, 'UTF-16'=>1);
|
||||
$ID3v2_text_encoding_lookup[3] = array('ISO-8859-1'=>0, 'UTF-16'=>1);
|
||||
$ID3v2_text_encoding_lookup[4] = array('ISO-8859-1'=>0, 'UTF-16'=>1, 'UTF-16BE'=>2, 'UTF-8'=>3);
|
||||
foreach ($this->tag_data as $tag_key => $valuearray) {
|
||||
$ID3v2_framename = getid3_write_id3v2::ID3v2ShortFrameNameLookup($id3v2_majorversion, $tag_key);
|
||||
switch ($ID3v2_framename) {
|
||||
|
@ -499,6 +497,51 @@ class getid3_writetags
|
|||
}
|
||||
break;
|
||||
|
||||
case 'POPM':
|
||||
if (isset($valuearray['email']) &&
|
||||
isset($valuearray['rating']) &&
|
||||
isset($valuearray['data'])) {
|
||||
$tag_data_id3v2['POPM'][] = $valuearray;
|
||||
} else {
|
||||
$this->errors[] = 'ID3v2 POPM data is not properly structured';
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'GRID':
|
||||
if (
|
||||
isset($valuearray['groupsymbol']) &&
|
||||
isset($valuearray['ownerid']) &&
|
||||
isset($valuearray['data'])
|
||||
) {
|
||||
$tag_data_id3v2['GRID'][] = $valuearray;
|
||||
} else {
|
||||
$this->errors[] = 'ID3v2 GRID data is not properly structured';
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'UFID':
|
||||
if (isset($valuearray['ownerid']) &&
|
||||
isset($valuearray['data'])) {
|
||||
$tag_data_id3v2['UFID'][] = $valuearray;
|
||||
} else {
|
||||
$this->errors[] = 'ID3v2 UFID data is not properly structured';
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'TXXX':
|
||||
foreach ($valuearray as $key => $txxx_data_array) {
|
||||
if (isset($txxx_data_array['description']) && isset($txxx_data_array['data'])) {
|
||||
$tag_data_id3v2['TXXX'][] = $txxx_data_array;
|
||||
} else {
|
||||
$this->errors[] = 'ID3v2 TXXX data is not properly structured';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case '':
|
||||
$this->errors[] = 'ID3v2: Skipping "'.$tag_key.'" because cannot match it to a known ID3v2 frame type';
|
||||
// some other data type, don't know how to handle it, ignore it
|
||||
|
@ -543,6 +586,7 @@ class getid3_writetags
|
|||
$tag_data_id3v2[$ID3v2_framename][$key]['data'] = "\xFF\xFE".getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-16LE', $value); // force LittleEndian order version of UTF-16
|
||||
$ID3v2_tag_data_converted = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
// convert data from other encoding to UTF-8
|
||||
$tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 3;
|
||||
|
@ -561,8 +605,7 @@ class getid3_writetags
|
|||
return $tag_data_id3v2;
|
||||
}
|
||||
|
||||
public function FormatDataForVorbisComment()
|
||||
{
|
||||
public function FormatDataForVorbisComment() {
|
||||
$tag_data_vorbiscomment = $this->tag_data;
|
||||
|
||||
// check for multi-line comment values - split out to multiple comments if neccesary
|
||||
|
@ -591,21 +634,20 @@ class getid3_writetags
|
|||
return $tag_data_vorbiscomment;
|
||||
}
|
||||
|
||||
public function FormatDataForMetaFLAC()
|
||||
{
|
||||
public function FormatDataForMetaFLAC() {
|
||||
// FLAC & OggFLAC use VorbisComments same as OggVorbis
|
||||
// but require metaflac to do the writing rather than vorbiscomment
|
||||
return $this->FormatDataForVorbisComment();
|
||||
}
|
||||
|
||||
public function FormatDataForReal()
|
||||
{
|
||||
$tag_data_real['title'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['TITLE']) ? $this->tag_data['TITLE'] : [])));
|
||||
$tag_data_real['artist'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['ARTIST']) ? $this->tag_data['ARTIST'] : [])));
|
||||
$tag_data_real['copyright'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['COPYRIGHT']) ? $this->tag_data['COPYRIGHT'] : [])));
|
||||
$tag_data_real['comment'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['COMMENT']) ? $this->tag_data['COMMENT'] : [])));
|
||||
public function FormatDataForReal() {
|
||||
$tag_data_real['title'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['TITLE'] ) ? $this->tag_data['TITLE'] : array())));
|
||||
$tag_data_real['artist'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['ARTIST'] ) ? $this->tag_data['ARTIST'] : array())));
|
||||
$tag_data_real['copyright'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['COPYRIGHT']) ? $this->tag_data['COPYRIGHT'] : array())));
|
||||
$tag_data_real['comment'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['COMMENT'] ) ? $this->tag_data['COMMENT'] : array())));
|
||||
|
||||
$this->MergeExistingTagData('real', $tag_data_real);
|
||||
return $tag_data_real;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,21 +17,20 @@
|
|||
class getid3_write_real
|
||||
{
|
||||
public $filename;
|
||||
public $tag_data = [];
|
||||
public $tag_data = array();
|
||||
public $fread_buffer_size = 32768; // read buffer size in bytes
|
||||
public $warnings = []; // any non-critical errors will be stored here
|
||||
public $errors = []; // any critical errors will be stored here
|
||||
public $warnings = array(); // any non-critical errors will be stored here
|
||||
public $errors = array(); // any critical errors will be stored here
|
||||
public $paddedlength = 512; // minimum length of CONT tag in bytes
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
public function __construct() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function WriteReal()
|
||||
{
|
||||
public function WriteReal() {
|
||||
// File MUST be writeable - CHMOD(646) at least
|
||||
if (is_writeable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'r+b'))) {
|
||||
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$OldThisFileInfo = $getID3->analyze($this->filename);
|
||||
|
@ -76,12 +75,15 @@ class getid3_write_real
|
|||
}
|
||||
|
||||
if (isset($oldChunkInfo['CONT']['length']) && ($oldChunkInfo['CONT']['length'] == strlen($new_CONT_tag_data))) {
|
||||
|
||||
// new data length is same as old data length - just overwrite
|
||||
fseek($fp_source, $oldChunkInfo['CONT']['offset']);
|
||||
fwrite($fp_source, $new_CONT_tag_data);
|
||||
fclose($fp_source);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
if (empty($oldChunkInfo['CONT'])) {
|
||||
// no existing CONT chunk
|
||||
$BeforeOffset = $oldChunkInfo['DATA']['offset'];
|
||||
|
@ -93,6 +95,7 @@ class getid3_write_real
|
|||
}
|
||||
if ($tempfilename = tempnam(GETID3_TEMP_DIR, 'getID3')) {
|
||||
if (is_writable($tempfilename) && is_file($tempfilename) && ($fp_temp = fopen($tempfilename, 'wb'))) {
|
||||
|
||||
rewind($fp_source);
|
||||
fwrite($fp_temp, fread($fp_source, $BeforeOffset));
|
||||
fwrite($fp_temp, $new_CONT_tag_data);
|
||||
|
@ -109,20 +112,22 @@ class getid3_write_real
|
|||
}
|
||||
unlink($tempfilename);
|
||||
$this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.')';
|
||||
|
||||
} else {
|
||||
$this->errors[] = 'Could not fopen("'.$tempfilename.'", "wb")';
|
||||
}
|
||||
}
|
||||
fclose($fp_source);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
$this->errors[] = 'Could not fopen("'.$this->filename.'", "r+b")';
|
||||
return false;
|
||||
}
|
||||
|
||||
public function GenerateRMFchunk(&$chunks)
|
||||
{
|
||||
public function GenerateRMFchunk(&$chunks) {
|
||||
$oldCONTexists = false;
|
||||
foreach ($chunks as $key => $chunk) {
|
||||
$chunkNameKeys[$chunk['name']] = $key;
|
||||
|
@ -140,8 +145,7 @@ class getid3_write_real
|
|||
return $RMFchunk;
|
||||
}
|
||||
|
||||
public function GeneratePROPchunk(&$chunks, &$new_CONT_tag_data)
|
||||
{
|
||||
public function GeneratePROPchunk(&$chunks, &$new_CONT_tag_data) {
|
||||
$old_CONT_length = 0;
|
||||
$old_DATA_offset = 0;
|
||||
$old_INDX_offset = 0;
|
||||
|
@ -178,8 +182,7 @@ class getid3_write_real
|
|||
return $PROPchunk;
|
||||
}
|
||||
|
||||
public function GenerateCONTchunk()
|
||||
{
|
||||
public function GenerateCONTchunk() {
|
||||
foreach ($this->tag_data as $key => $value) {
|
||||
// limit each value to 0xFFFF bytes
|
||||
$this->tag_data[$key] = substr($value, 0, 65535);
|
||||
|
@ -208,10 +211,10 @@ class getid3_write_real
|
|||
return $CONTchunk;
|
||||
}
|
||||
|
||||
public function RemoveReal()
|
||||
{
|
||||
public function RemoveReal() {
|
||||
// File MUST be writeable - CHMOD(646) at least
|
||||
if (is_writeable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'r+b'))) {
|
||||
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$OldThisFileInfo = $getID3->analyze($this->filename);
|
||||
|
@ -240,6 +243,7 @@ class getid3_write_real
|
|||
$AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length'];
|
||||
if ($tempfilename = tempnam(GETID3_TEMP_DIR, 'getID3')) {
|
||||
if (is_writable($tempfilename) && is_file($tempfilename) && ($fp_temp = fopen($tempfilename, 'wb'))) {
|
||||
|
||||
rewind($fp_source);
|
||||
fwrite($fp_temp, fread($fp_source, $BeforeOffset));
|
||||
fseek($fp_source, $AfterOffset);
|
||||
|
@ -255,6 +259,7 @@ class getid3_write_real
|
|||
}
|
||||
unlink($tempfilename);
|
||||
$this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.')';
|
||||
|
||||
} else {
|
||||
$this->errors[] = 'Could not fopen("'.$tempfilename.'", "wb")';
|
||||
}
|
||||
|
@ -265,4 +270,5 @@ class getid3_write_real
|
|||
$this->errors[] = 'Could not fopen("'.$this->filename.'", "r+b")';
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,16 +20,14 @@ class getid3_write_vorbiscomment
|
|||
|
||||
public $filename;
|
||||
public $tag_data;
|
||||
public $warnings = []; // any non-critical errors will be stored here
|
||||
public $errors = []; // any critical errors will be stored here
|
||||
public $warnings = array(); // any non-critical errors will be stored here
|
||||
public $errors = array(); // any critical errors will be stored here
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
public function __construct() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function WriteVorbisComment()
|
||||
{
|
||||
public function WriteVorbisComment() {
|
||||
|
||||
if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
|
||||
$this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call vorbiscomment, tags not written';
|
||||
|
@ -39,12 +37,14 @@ class getid3_write_vorbiscomment
|
|||
// Create file with new comments
|
||||
$tempcommentsfilename = tempnam(GETID3_TEMP_DIR, 'getID3');
|
||||
if (is_writable($tempcommentsfilename) && is_file($tempcommentsfilename) && ($fpcomments = fopen($tempcommentsfilename, 'wb'))) {
|
||||
|
||||
foreach ($this->tag_data as $key => $value) {
|
||||
foreach ($value as $commentdata) {
|
||||
fwrite($fpcomments, $this->CleanVorbisCommentName($key).'='.$commentdata."\n");
|
||||
}
|
||||
}
|
||||
fclose($fpcomments);
|
||||
|
||||
} else {
|
||||
$this->errors[] = 'failed to open temporary tags file "'.$tempcommentsfilename.'", tags not written';
|
||||
return false;
|
||||
|
@ -52,6 +52,7 @@ class getid3_write_vorbiscomment
|
|||
|
||||
$oldignoreuserabort = ignore_user_abort(true);
|
||||
if (GETID3_OS_ISWINDOWS) {
|
||||
|
||||
if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) {
|
||||
//$commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w --raw -c "'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"';
|
||||
// vorbiscomment works fine if you copy-paste the above commandline into a command prompt,
|
||||
|
@ -77,9 +78,12 @@ class getid3_write_vorbiscomment
|
|||
} else {
|
||||
$VorbiscommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$commandline = 'vorbiscomment -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1';
|
||||
$VorbiscommentError = `$commandline`;
|
||||
|
||||
}
|
||||
|
||||
// Remove temporary comments file
|
||||
|
@ -87,21 +91,21 @@ class getid3_write_vorbiscomment
|
|||
ignore_user_abort($oldignoreuserabort);
|
||||
|
||||
if (!empty($VorbiscommentError)) {
|
||||
|
||||
$this->errors[] = 'system call to vorbiscomment failed with message: '."\n\n".$VorbiscommentError;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function DeleteVorbisComment()
|
||||
{
|
||||
$this->tag_data = [[]];
|
||||
public function DeleteVorbisComment() {
|
||||
$this->tag_data = array(array());
|
||||
return $this->WriteVorbisComment();
|
||||
}
|
||||
|
||||
public function CleanVorbisCommentName($originalcommentname)
|
||||
{
|
||||
public function CleanVorbisCommentName($originalcommentname) {
|
||||
// A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded.
|
||||
// ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through
|
||||
// 0x7A inclusive (a-z).
|
||||
|
@ -110,5 +114,7 @@ class getid3_write_vorbiscomment
|
|||
// Thanks Chris Bolt <chris-getid3Øbolt*cx> for improving this function
|
||||
// note: *reg_replace() replaces nulls with empty string (not space)
|
||||
return strtoupper(preg_replace('#[^ -<>-}]#', ' ', str_replace("\x00", ' ', $originalcommentname)));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -463,6 +463,11 @@ http://www.getid3.org/phpBB3/viewtopic.php?t=25
|
|||
written just "value" (detected by getID3())
|
||||
* Oggenc 0.9-rc3 flags the encoded file as ABR whether it's
|
||||
actually ABR or VBR.
|
||||
* iTunes (versions "v7.0.0.70" is known-guilty, probably
|
||||
other versions are too) writes ID3v2.3 comment tags using an
|
||||
ID3v2.2 frame name (3-bytes) null-padded to 4 bytes which is
|
||||
not valid for ID3v2.3+
|
||||
(detected by getID3() since 1.9.12-201603221746)
|
||||
* iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably
|
||||
other versions are too) writes ID3v2.3 comment tags using a
|
||||
frame name 'COM ' which is not valid for ID3v2.3+ (it's an
|
||||
|
@ -615,3 +620,4 @@ Reference material:
|
|||
* http://wyday.com/cuesharp/specification.php
|
||||
* http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
|
||||
* http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header
|
||||
* http://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf
|
||||
|
|
|
@ -13,6 +13,7 @@ return [
|
|||
*/
|
||||
|
||||
'files_directory' => env('PONYFM_DATASTORE'),
|
||||
'ponify_directory' => env('PONIFY_DIRECTORY'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreatePonifyTracks extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('ponify_tracks', function(Blueprint $table)
|
||||
{
|
||||
$table->increments('id');
|
||||
$table->integer('track_id')->unsigned()->index();
|
||||
$table->string('path')->index();
|
||||
$table->string('filename')->index();
|
||||
$table->string('extension')->index();
|
||||
$table->dateTime('imported_at');
|
||||
$table->text('parsed_tags');
|
||||
$table->text('raw_tags');
|
||||
});
|
||||
|
||||
Schema::table('ponify_tracks', function(Blueprint $table)
|
||||
{
|
||||
$table->foreign('track_id')->references('id')->on('tracks')->onUpdate('RESTRICT')->onDelete('RESTRICT');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('ponify_tracks', function(Blueprint $table)
|
||||
{
|
||||
$table->dropForeign('ponify_tracks_track_id_foreign');
|
||||
});
|
||||
|
||||
Schema::drop('ponify_tracks');
|
||||
}
|
||||
}
|
|
@ -180,10 +180,10 @@
|
|||
contact
|
||||
for more information or answers to my questions?</h2>
|
||||
|
||||
<p>Just shoot a message to Poniverse's Head of Public Relations, Simon,
|
||||
<p>Just shoot a message to Poniverse's Head of Public Relations, Mercury,
|
||||
at
|
||||
<a href="mailto:simon@poniverse.net"
|
||||
target="_blank">simon@poniverse.net</a> and he'll
|
||||
<a href="mailto:mercury@poniverse.net"
|
||||
target="_blank">mercury@poniverse.net</a> and he'll
|
||||
be happy to answer any questions you have about Pony.fm and the
|
||||
advertising deal offered here!</p>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue