Implement our own quicktime parser
This commit is contained in:
33
app/Media/QuickTime/Atoms/moov/trak/mdia.php
Normal file
33
app/Media/QuickTime/Atoms/moov/trak/mdia.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Media\QuickTime\Atoms\moov\trak;
|
||||
|
||||
use App\Media\QuickTime\Atoms\moov\trak\mdia\hdlr;
|
||||
use App\Media\QuickTime\Atoms\SubAtom;
|
||||
use App\Media\QuickTime\Atoms\Unknown;
|
||||
|
||||
class mdia extends SubAtom
|
||||
{
|
||||
private const subatom_classes = 'App\\Media\\QuickTime\\Atoms\\moov\\trak\\mdia\\';
|
||||
|
||||
|
||||
public function __construct(int $offset,int $size,string $filename,?string $data)
|
||||
{
|
||||
parent::__construct($offset,$size,$filename);
|
||||
|
||||
// We'll find atoms
|
||||
$this->atoms = $this->get_atoms(
|
||||
self::subatom_classes,
|
||||
Unknown::class,
|
||||
$offset,
|
||||
$size,
|
||||
$data,
|
||||
NULL,
|
||||
fn($atom)=>($atom instanceof hdlr) ? $atom->cache['csubtype'] : NULL
|
||||
);
|
||||
|
||||
// For debugging
|
||||
if (FALSE)
|
||||
$this->debug = hex_dump($data ?: $this->data());
|
||||
}
|
||||
}
|
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();
|
||||
}
|
||||
}
|
10
app/Media/QuickTime/Atoms/moov/trak/meta.php
Normal file
10
app/Media/QuickTime/Atoms/moov/trak/meta.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Media\QuickTime\Atoms\moov\trak;
|
||||
|
||||
use App\Media\QuickTime\Atoms\moov\meta as MoovMeta;
|
||||
|
||||
class meta extends MoovMeta
|
||||
{
|
||||
|
||||
}
|
55
app/Media/QuickTime/Atoms/moov/trak/tkhd.php
Normal file
55
app/Media/QuickTime/Atoms/moov/trak/tkhd.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Media\QuickTime\Atoms\moov\trak;
|
||||
|
||||
// An atom that specifies the characteristics of a single track within a movie
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
use App\Media\QuickTime\Atoms\SubAtom;
|
||||
|
||||
class tkhd extends SubAtom
|
||||
{
|
||||
protected const unpack = [
|
||||
'version'=>['c',1],
|
||||
'flags'=>['a3',3],
|
||||
'create'=>['N',4],
|
||||
'modified'=>['N',4],
|
||||
'trakid'=>['N',4], // The value 0 cannot be used
|
||||
'reserved1'=>['a4',4],
|
||||
'duration'=>['N',4],
|
||||
'reserved2'=>['a8',8],
|
||||
'layer'=>['n',2],
|
||||
'altgroup'=>['n',2],
|
||||
'volume'=>['a2',2], // 16 bit fixed point
|
||||
'reserved3'=>['a2',2],
|
||||
'matrix'=>['a36',36],
|
||||
'twidth'=>['a4',4], // 32 bit fixed point
|
||||
'theight'=>['a4',4], // 32 bit fixed point
|
||||
];
|
||||
|
||||
public function __construct(int $offset,int $size,string $filename,?string $data)
|
||||
{
|
||||
parent::__construct($offset,$size,$filename,$data);
|
||||
|
||||
$this->cache = $this->cache();
|
||||
|
||||
// For debugging
|
||||
if (FALSE)
|
||||
$this->debug = hex_dump($data ?: $this->data());
|
||||
}
|
||||
|
||||
public function __get($key): mixed
|
||||
{
|
||||
switch ($key) {
|
||||
case 'height':
|
||||
return fixed_point_int_to_float(Arr::get($this->cache(),'theight'));
|
||||
|
||||
case 'width':
|
||||
return fixed_point_int_to_float(Arr::get($this->cache(),'twidth'));
|
||||
|
||||
default:
|
||||
return parent::__get($key);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user