photo/app/Media/QuickTime/Atom.php

144 lines
2.8 KiB
PHP

<?php
namespace App\Media\QuickTime;
use Illuminate\Support\Collection;
use App\Media\QuickTime\Atoms\moov\{mvhd,trak};
use App\Traits\FindQuicktimeAtoms;
abstract class Atom
{
use FindQuicktimeAtoms;
protected const record_size = 16384;
protected const BLOCK_SIZE = 4096;
protected int $offset;
protected int $size;
protected string $filename;
private mixed $fh;
private int $fp;
protected Collection $cache;
protected Collection $atoms;
public function __construct(int $offset,int $size,string $filename)
{
$this->offset = $offset;
// Quick validation
if ($size < 0)
throw new \Exception(sprintf('Atom cannot be negative. (%d)',$size));
$this->size = $size;
$this->filename = $filename;
$this->cache = collect();
}
public function __get(string $key): mixed
{
switch ($key) {
// Create time is in the MOOV/MVHD atom
case 'creation_date':
case 'duration':
case 'preferred_rate':
case 'preferred_volume':
$subatom = $this->find_atoms(mvhd::class,1);
return $subatom->{$key};
// Height is in the moov/trak/tkhd atom
case 'height':
// Width is in the moov/trak/tkhd atom
case 'width':
$atom = $this->find_atoms(trak::class);
return $atom->map(fn($item)=>$item->{$key})->filter()->max();
// Signatures are calculated by the sha of the MDAT atom.
case 'signature':
return $this->signature();
default:
throw new \Exception('Unknown key: '.$key);
}
}
protected function data(): string
{
// Quick validation
if ($this->size > self::record_size)
throw new \Exception(sprintf('Refusing to read more than %d of data',self::record_size));
$data = '';
if ($this->fopen()) {
while (! is_null($read=$this->fread()))
$data .= $read;
$this->fclose();
}
return $data;
}
protected function fclose(): bool
{
fclose($this->fh);
unset($this->fh);
return TRUE;
}
/**
* Open the file and seek to the atom
*
* @return bool
*/
protected function fopen(): bool
{
$this->fh = fopen($this->filename,'r');
fseek($this->fh,$this->offset);
$this->fp = 0;
return TRUE;
}
/**
* Read the atom from the file
*
* @param int $size
* @return string|NULL
*/
protected function fread(int $size=4096): ?string
{
if ($this->fp === $this->size)
return NULL;
if ($this->fp+$size > $this->size)
$size = $this->size-$this->fp;
$read = fread($this->fh,$size);
$this->fp += $size;
return $read;
}
protected function fseek(int $offset): int
{
$this->fp = $offset;
return fseek($this->fh,$this->offset+$this->fp);
}
protected function unpack(array $unpack=[]): string
{
return collect($unpack ?: static::unpack)->map(fn($v,$k)=>$v[0].$k)->join('/');
}
protected function unpack_size(array $unpack=[]): int
{
return collect($unpack ?: static::unpack)->map(fn($v,$k)=>$v[1])->sum();
}
}