Implement our own quicktime parser
This commit is contained in:
32
app/Media/QuickTime/Atoms/moov/trak/mdia/hdlr.php
Normal file
32
app/Media/QuickTime/Atoms/moov/trak/mdia/hdlr.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Media\QuickTime\Atoms\moov\trak\mdia;
|
||||
|
||||
use App\Media\QuickTime\Atoms\SubAtom;
|
||||
|
||||
class hdlr extends SubAtom
|
||||
{
|
||||
protected const unpack = [
|
||||
'version'=>['c',1],
|
||||
'flags'=>['a3',3],
|
||||
'ctype'=>['a4',4],
|
||||
'csubtype'=>['a4',4],
|
||||
'cmanufact'=>['a4',4],
|
||||
'cflags'=>['a4',4],
|
||||
'cmask'=>['a4',4],
|
||||
];
|
||||
|
||||
public function __construct(int $offset,int $size,string $filename,?string $data)
|
||||
{
|
||||
parent::__construct($offset,$size,$filename);
|
||||
|
||||
$this->cache = $this->cache();
|
||||
$this->cache['name'] = pascal_string($this->unused_data);
|
||||
|
||||
$this->unused_data = (($x=strlen($this->cache['name'])+1) < strlen($this->unused_data)) ? substr($data,$x) : NULL;
|
||||
|
||||
// For debugging
|
||||
if (FALSE)
|
||||
$this->debug = hex_dump($data ?: $this->data());
|
||||
}
|
||||
}
|
39
app/Media/QuickTime/Atoms/moov/trak/mdia/minf.php
Normal file
39
app/Media/QuickTime/Atoms/moov/trak/mdia/minf.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Media\QuickTime\Atoms\moov\trak\mdia;
|
||||
|
||||
use Leenooks\Traits\ObjectIssetFix;
|
||||
|
||||
use App\Media\QuickTime\Atoms\SubAtom;
|
||||
use App\Media\QuickTime\Atoms\Unknown;
|
||||
|
||||
class minf extends SubAtom
|
||||
{
|
||||
use ObjectIssetFix;
|
||||
|
||||
private const subatom_classes = 'App\\Media\\QuickTime\\Atoms\\moov\\trak\\mdia\\minf\\';
|
||||
|
||||
protected ?string $type;
|
||||
public function __construct(int $offset,int $size,string $filename,?string $data,string $arg=NULL)
|
||||
{
|
||||
parent::__construct($offset,$size,$filename);
|
||||
$this->type = $arg;
|
||||
|
||||
$this->atoms = $this->get_atoms(self::subatom_classes,Unknown::class,$offset,$size,$data,$arg);
|
||||
|
||||
// For debugging
|
||||
if (FALSE)
|
||||
$this->debug = hex_dump($data ?: $this->data());
|
||||
}
|
||||
|
||||
public function __get(string $key): mixed
|
||||
{
|
||||
switch ($key) {
|
||||
case 'type':
|
||||
return $this->{$key};
|
||||
|
||||
default:
|
||||
return parent::__get($key);
|
||||
}
|
||||
}
|
||||
}
|
10
app/Media/QuickTime/Atoms/moov/trak/mdia/minf/hdlr.php
Normal file
10
app/Media/QuickTime/Atoms/moov/trak/mdia/minf/hdlr.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Media\QuickTime\Atoms\moov\trak\mdia\minf;
|
||||
|
||||
use App\Media\QuickTime\Atoms\moov\trak\mdia\hdlr as MdiaHdlr;
|
||||
|
||||
class hdlr extends MdiaHdlr
|
||||
{
|
||||
|
||||
}
|
22
app/Media/QuickTime/Atoms/moov/trak/mdia/minf/stbl.php
Normal file
22
app/Media/QuickTime/Atoms/moov/trak/mdia/minf/stbl.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Media\QuickTime\Atoms\moov\trak\mdia\minf;
|
||||
|
||||
use App\Media\QuickTime\Atoms\SubAtom;
|
||||
use App\Media\QuickTime\Atoms\Unknown;
|
||||
|
||||
class stbl extends SubAtom
|
||||
{
|
||||
private const subatom_classes = 'App\\Media\\QuickTime\\Atoms\\moov\\trak\\mdia\\minf\\stbl\\';
|
||||
|
||||
public function __construct(int $offset,int $size,string $filename,?string $data,?string $arg=NULL)
|
||||
{
|
||||
parent::__construct($offset,$size,$filename);
|
||||
|
||||
$this->atoms = $this->get_atoms(self::subatom_classes,Unknown::class,$offset,$size,$data,$arg);
|
||||
|
||||
// For debugging
|
||||
if (FALSE)
|
||||
$this->debug = hex_dump($data ?: $this->data());
|
||||
}
|
||||
}
|
104
app/Media/QuickTime/Atoms/moov/trak/mdia/minf/stbl/stsd.php
Normal file
104
app/Media/QuickTime/Atoms/moov/trak/mdia/minf/stbl/stsd.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace App\Media\QuickTime\Atoms\moov\trak\mdia\minf\stbl;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
use App\Media\QuickTime\Atoms\SubAtom;
|
||||
|
||||
class stsd extends SubAtom
|
||||
{
|
||||
protected const unpack = [
|
||||
'size'=>['N',4],
|
||||
'format'=>['a4',4],
|
||||
'reserved'=>['a6',6],
|
||||
'index'=>['n',2],
|
||||
'encoder_version'=>['n',2],
|
||||
'encoder_revision'=>['n',2],
|
||||
'encoder_vendor'=>['a4',4],
|
||||
];
|
||||
|
||||
protected const audio_record = [
|
||||
'audio_channels'=>['n',2],
|
||||
'audio_bit_depth'=>['n',2],
|
||||
'audio_compression_id'=>['n',2],
|
||||
'audio_packet_size'=>['n',2],
|
||||
'audio_sample_rate'=>['a4',4],
|
||||
];
|
||||
|
||||
protected const video_record = [
|
||||
'temporal_quality'=>['N',4],
|
||||
'spatial_quality'=>['N',4],
|
||||
'width'=>['n',2],
|
||||
'height'=>['n',2],
|
||||
'resolution_x'=>['a4',4],
|
||||
'resolution_y'=>['a4',4],
|
||||
'data_size'=>['N',4],
|
||||
'frame_count'=>['n',2],
|
||||
//'codec_name'=>['a4',4], // pascal string
|
||||
];
|
||||
|
||||
public function __construct(int $offset,int $size,string $filename,?string $data,string $arg=NULL)
|
||||
{
|
||||
parent::__construct($offset,$size,$filename);
|
||||
$this->type = $arg;
|
||||
|
||||
$read = unpack($this->unpack(self::atom_record),substr($data,0,$ptr=$this->unpack_size(self::atom_record)));
|
||||
|
||||
for ($i=0; $i<$read['count']; $i++) {
|
||||
$this->cache = collect(unpack($this->unpack(),substr($data,$ptr,$x=$this->unpack_size())));
|
||||
|
||||
$ptr += $x;
|
||||
|
||||
switch ($this->type) {
|
||||
case 'soun':
|
||||
// Audio Track
|
||||
$this->audio = unpack($this->unpack(self::audio_record),substr($data,$ptr,$x=$this->unpack_size(self::audio_record)));
|
||||
$ptr += $x;
|
||||
|
||||
break;
|
||||
|
||||
case 'vide':
|
||||
// Video Track
|
||||
$this->video = unpack($this->unpack(self::video_record),substr($data,$ptr,$x=$this->unpack_size(self::video_record)));
|
||||
$ptr += $x;
|
||||
|
||||
// codec - pascal string
|
||||
$this->video['codec'] = pascal_string(substr($data,$ptr));
|
||||
|
||||
$ptr += strlen($this->video['codec'])+1;
|
||||
}
|
||||
|
||||
$this->extra = substr($data,$ptr);
|
||||
}
|
||||
}
|
||||
|
||||
public function __get(string $key):mixed
|
||||
{
|
||||
switch ($key) {
|
||||
case 'audio_channels':
|
||||
return Arr::get($this->audio,$key);
|
||||
|
||||
case 'audio_codec':
|
||||
switch ($this->cache->get('format')) {
|
||||
case 'mp4a': return 'ISO/IEC 14496-3 AAC';
|
||||
|
||||
default:
|
||||
return $this->cache->get('format');
|
||||
}
|
||||
|
||||
case 'audio_samplerate':
|
||||
return fixed_point_int_to_float(Arr::get($this->audio,'audio_sample_rate',0));
|
||||
|
||||
case 'video_codec':
|
||||
return Arr::get($this->video,'codec');
|
||||
|
||||
case 'video_framerate':
|
||||
dd($this);
|
||||
// return Arr::get($this->video,'codec');
|
||||
|
||||
default:
|
||||
return parent::__get($key);
|
||||
}
|
||||
}
|
||||
}
|
32
app/Media/QuickTime/Atoms/moov/trak/mdia/minf/stbl/stts.php
Normal file
32
app/Media/QuickTime/Atoms/moov/trak/mdia/minf/stbl/stts.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Media\QuickTime\Atoms\moov\trak\mdia\minf\stbl;
|
||||
|
||||
use App\Media\QuickTime\Atoms\SubAtom;
|
||||
|
||||
class stts extends SubAtom
|
||||
{
|
||||
public function __construct(int $offset,int $size,string $filename,?string $data)
|
||||
{
|
||||
parent::__construct($offset,$size,$filename);
|
||||
|
||||
$read = unpack($this->unpack(self::atom_record),substr($data,0,$ptr=$this->unpack_size(self::atom_record)));
|
||||
|
||||
for ($i=0; $i<$read['count']; $i++) {
|
||||
$this->cache->push(unpack('Ncount/Nduration',substr($data,$ptr,8)));
|
||||
$ptr += 8;
|
||||
}
|
||||
|
||||
// For debugging
|
||||
if (FALSE)
|
||||
$this->debug = hex_dump($data ?: $this->data());
|
||||
}
|
||||
|
||||
public function frame_rate(float $time_scale): float
|
||||
{
|
||||
return $this->cache
|
||||
->pluck('duration')
|
||||
->map(fn($item)=>$time_scale/$item)
|
||||
->max();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user