/** * Constructor * * @author Tommy Lacroix <*****@*****.**> * @param int $totalSize * @param int $boxType * @param file|string $f * @param MP4Info_Box $parent * @return MP4Info_Box_ilst_sub * @access public * @throws MP4Info_Exception */ public function __construct($totalSize, $boxType, $data, $parent) { if (!$parent instanceof MP4Info_Box_ilst) { throw new MP4Info_Exception('This box isn\'t "islt" child', MP4Info_Exception::CODE_INCOMPATIBLE, $boxType); } // Call ancestor parent::__construct($totalSize, $boxType, $data, $parent); // Get data $data = $this->data; // Unpack $type = self::getType($this->boxType); $ar = unpack('Nlen', $data); if (substr($data, 4, 4) == 'data') { $info = substr($data, 8, $ar['len'] - 8); switch ($type) { case 'uint8': $info = reset(unpack('C', $info)); break; case 'uint16': $info = reset(unpack('n', $info)); break; case 'uint32': $info = reset(unpack('N', $info)); break; case 'text': break; } $this->data = $info; $parent->setKeyValue($this->boxTypeStr, $info); } else { throw new MP4Info_Exception('Didn\'t get the "data" code'); } }
/** * Constructor * * @author Tommy Lacroix <*****@*****.**> * @param int $totalSize * @param int $boxType * @param file|string $data * @param MP4Info_Box $parent * @return MP4Info_Box_Container * @access public * @throws MP4Info_Exception */ public function __construct($totalSize, $boxType, $data, $parent) { if (!self::isCompatible($boxType, $parent)) { throw new MP4Info_Exception('This box isn\'t a container', MP4Info_Exception::CODE_INCOMPATIBLE, $boxType); } // Call ancestor parent::__construct($totalSize, $boxType, false, $parent); // Unpack if (is_string($data)) { while ($data != '') { try { $box = MP4Info_Box::fromString($data, $this); if (!$box instanceof MP4Info_Box) { break; } } catch (Exception $e) { break; } } } else { do { try { $box = MP4Info_Box::fromStream($data, $this); if (!$box instanceof MP4Info_Box) { break; } } catch (Exception $e) { break; } } while ($box !== false); } }
/** * Constructor * * @author Tommy Lacroix <*****@*****.**> * @param int $totalSize * @param int $boxType * @param file|string $data * @param MP4Info_Box $parent * @return MP4Info_Box_uuid * @access public * @throws MP4Info_Exception */ public function __construct($totalSize, $boxType, $data, $parent) { if (!self::isCompatible($boxType, $parent)) { throw new Exception('This box isn\'t "uuid"'); } // Call ancestor parent::__construct($totalSize, $boxType, '', $parent); // Unpack $data = self::getDataFrom3rd($data, $totalSize); $this->uuid = bin2hex(substr($data, 0, 16)); $this->xmp = substr($data, 16); }
/** * Get information from MP4 file * * @author Tommy Lacroix <*****@*****.**> * @param string $file * @return array * @access public * @static */ public static function getInfo($file) { // Open file $f = fopen($file, 'rb'); if (!$f) { throw new Exception('Cannot open file: ' . $file); } // Get all boxes try { while ($box = MP4Info_Box::fromStream($f)) { $boxes[] = $box; } } catch (Exception $e) { } // Close fclose($f); // Return info return self::getInfoFromBoxes($boxes); }
/** * Constructor * * @author Tommy Lacroix <*****@*****.**> * @param int $totalSize * @param int $boxType * @param file|string $data * @param MP4Info_Box $parent * @return MP4Info_Box_ftyp * @access public * @throws MP4Info_Exception */ public function __construct($totalSize, $boxType, $data, $parent) { if (!self::isCompatible($boxType, $parent)) { throw new MP4Info_Exception('This box isn\'t "ftyp"', MP4Info_Exception::CODE_INCOMPATIBLE, $boxType); } // Call ancestor parent::__construct($totalSize, $boxType, false, $parent); // Get data $data = self::getDataFrom3rd($data, $totalSize); // Unpack $ar = unpack('NmajorBrand/NminorVersion/N*compatibleBrands', $data); $compatibleBrands = array(); foreach ($ar as $k => $v) { if (substr($k, 0, 16) == 'compatibleBrands') { $compatibleBrands[] = $v; } } // Save properties $this->majorBrand = $ar['majorBrand']; $this->minorVersion = $ar['minorVersion']; $this->compatibleBrands = $compatibleBrands; }
/** * Constructor * * @author Tommy Lacroix <*****@*****.**> * @param int $totalSize * @param int $boxType * @param file|string $data * @param MP4Info_Box $parent * @return MP4Info_Box_hdlr * @access public * @throws MP4Info_Exception */ public function __construct($totalSize, $boxType, $data, $parent) { if (!self::isCompatible($boxType, $parent)) { throw new Exception('This box isn\'t "iods"'); } // Get timezone if (self::$timezone === false) { self::$timezone = date('Z'); } // Call ancestor parent::__construct($totalSize, $boxType, '', $parent); // Get data $data = self::getDataFrom3rd($data, $totalSize); // Unpack $ar = unpack('Cversion/C3flags', $data); $ar2 = unpack('CiodTag/Nlength/nODID/CODProfileLevel/CsceneProfileLevel/CaudioProfileLevel/CvideoProfileLevel/CgraphicsProfileLevel', substr($data, 4)); // Save $this->version = $ar['version']; $this->flags = $ar['flags1'] * 65536 + $ar['flags1'] * 256 + $ar['flags1'] * 1; print_r($ar2); die; }
/** * Constructor * * @author Tommy Lacroix <*****@*****.**> * @param int $totalSize * @param int $boxType * @param file|string $data * @param MP4Info_Box $parent * @return MP4Info_Box_hdlr * @access public * @throws MP4Info_Exception */ public function __construct($totalSize, $boxType, $data, $parent) { if (!self::isCompatible($boxType, $parent)) { throw new Exception('This box isn\'t "ftyp"'); } // Get timezone if (self::$timezone === false) { self::$timezone = date('Z'); } // Call ancestor parent::__construct($totalSize, $boxType, '', $parent); // Get data $data = self::getDataFrom3rd($data, $totalSize); // Unpack $ar = unpack('Cversion/C3flags', $data); if ($ar['version'] == 0) { // 32 bit $ar2 = unpack('Nctime/Nmtime/NtimeScale/Nduration', substr($data, 4)); $len = 6 * 4; } else { if ($ar['version'] == 1) { // 64 bit $ar2 = unpack('N2ctime/N2mtime/NtimeScale/N2duration', substr($data, 4)); $len = 9 * 4; } else { throw new Exception('Unhandled version: ' . $ar['version']); } } // Save $this->version = $ar['version']; $this->flags = $ar['flags1'] * 65536 + $ar['flags1'] * 256 + $ar['flags1'] * 1; $this->ctime = date('r', (isset($ar2['ctime']) ? $ar2['ctime'] : $ar2['ctime1']) - 2082826800 - self::$timezone); $this->mtime = date('r', (isset($ar2['mtime']) ? $ar2['mtime'] : $ar2['mtime1']) - 2082826800 - self::$timezone); $this->timeScale = $ar2['timeScale']; $this->duration = isset($ar2['duration']) ? $ar2['duration'] : $ar2['duration1']; $this->handlerType = substr($data, $len, 4); $this->name = substr($data, $len + 8, -1); }
/** * Constructor * * @author Tommy Lacroix <*****@*****.**> * @param int $totalSize * @param int $boxType * @param file|string $data * @param MP4Info_Box $parent * @return MP4Info_Box_stsd * @access public * @throws MP4Info_Exception */ public function __construct($totalSize, $boxType, $data, $parent) { if (!self::isCompatible($boxType, $parent)) { throw new Exception('This box isn\'t "stsd"'); } // Call ancestor parent::__construct($totalSize, $boxType, '', $parent); // Get data $data = self::getDataFrom3rd($data, $totalSize); // Unpack $ar = unpack('Cversion/C3flags/Ncount', $data); $this->version = $ar['version']; $this->flags = $ar['flags1'] * 65536 + $ar['flags1'] * 256 + $ar['flags1'] * 1; $this->count = $ar['count']; // Unpack SAMPLEDESCRIPTION $desc = substr($data, 8); for ($i = 0; $i < $this->count; $i++) { $ar = unpack('Nlen', $desc); $type = substr($desc, 4, 4); $info = substr($desc, 8, $ar['len'] - 8); $desc = substr($desc, $ar['len']); $this->values[$type] = $info; } }
/** * Constructor * * @author Tommy Lacroix <*****@*****.**> * @param int $totalSize * @param int $boxType * @param file|string $data * @param MP4Info_Box $parent * @return MP4Info_Box_mvhd * @access public * @throws MP4Info_Exception */ public function __construct($totalSize, $boxType, $data, $parent) { if (!self::isCompatible($boxType)) { throw new Exception('This box isn\'t "mvhd"'); } // Get timezone if (self::$timezone === false) { self::$timezone = date('Z'); } // Call ancestor's constructor parent::__construct($totalSize, $boxType, '', $parent); // Unpack $ar = unpack('Cversion/C3flags', $data); if ($ar['version'] == 0) { // 32 bit $ar2 = unpack('Nctime/Nmtime/NtimeScale/Nduration/Nrate/nvolume/ndummy/N2dummy2/N9matrix/N3dummy3/NnextTrack', substr($data, 4)); } else { if ($ar['version'] == 1) { // 64 bit $ar2 = unpack('N2ctime/N2mtime/NtimeScale/N2duration/Nrate/nvolume/ndummy/N2dummy2/N9matrix/N3dummy3/NnextTrack', substr($data, 4)); } else { throw new Exception('Unhandled version: ' . $ar['version']); } } // Save $this->version = $ar['version']; $this->flags = $ar['flags1'] * 65536 + $ar['flags1'] * 256 + $ar['flags1'] * 1; $this->ctime = date('r', (isset($ar2['ctime']) ? $ar2['ctime'] : $ar2['ctime1']) - 2082826800 - self::$timezone); $this->mtime = date('r', (isset($ar2['mtime']) ? $ar2['mtime'] : $ar2['mtime1']) - 2082826800 - self::$timezone); $this->timeScale = $ar2['timeScale']; $this->duration = isset($ar2['duration']) ? $ar2['duration'] : $ar2['duration1']; $this->rate = MP4Info_Helper::fromFixed16($ar2['rate']); $this->volume = MP4Info_Helper::fromFixed8($ar2['volume']); }
/** * Constructor * * @author Tommy Lacroix <*****@*****.**> * @param int $totalSize * @param int $boxType * @param file|string $data * @param MP4Info_Box $parent * @return MP4Info_Box_tkhd * @access public * @throws MP4Info_Exception */ public function __construct($totalSize, $boxType, $data, $parent = false) { if (!self::isCompatible($boxType, $parent)) { throw new Exception('This box isn\'t "tkhd"'); } // Get timezone if (self::$timezone === false) { self::$timezone = date('Z'); } // Call ancestor's constructor parent::__construct($totalSize, $boxType, '', $parent); // Get data $data = self::getDataFrom3rd($data, $totalSize); // Unpack $ar = unpack('Cversion/C3flags', $data); if ($ar['version'] == 0) { // 32 bit $ar2 = unpack('Nctime/Nmtime/NtrackId/Ndummy/Nduration/N2dummy1/nlayer/naltGroup/nvolume/ndummy2/N9matrix/Nwidth/Nheight', substr($data, 4)); } else { if ($ar['version'] == 1) { // 64 bit $ar2 = unpack('N2ctime/N2mtime/NtrackId/Ndummy/N2duration/N2dummy1/nlayer/naltGroup/nvolume/ndummy2/N9matrix/Nwidth/Nheight', substr($data, 4)); } else { throw new Exception('Unhandled version: ' . $ar['version']); } } // Save $this->version = $ar['version']; $this->flags = $ar['flags1'] * 65536 + $ar['flags1'] * 256 + $ar['flags1'] * 1; $this->ctime = date('r', (isset($ar2['ctime']) ? $ar2['ctime'] : $ar2['ctime1']) - 2082826800 - self::$timezone); $this->mtime = date('r', (isset($ar2['mtime']) ? $ar2['mtime'] : $ar2['mtime1']) - 2082826800 - self::$timezone); $this->trackId = $ar2['trackId']; $this->duration = isset($ar2['duration']) ? $ar2['duration'] : $ar2['duration1']; $this->layer = $ar2['layer'] > 32767 ? $ar2['layer'] - 65536 : $ar2['layer']; $this->volume = MP4Info_Helper::fromFixed8($ar2['volume']); $this->width = MP4Info_Helper::fromFixed16($ar2['width']); $this->height = MP4Info_Helper::fromFixed16($ar2['height']); }
/** * Create a box from file stream * * @author Tommy Lacroix <*****@*****.**> * @param file $f * @param MP4Info_Box|false $parent * @return MP4Info_Box * @access public * @static */ public static function fromStream($f, $parent = false) { // Get box header $buf = fread($f, 8); if (strlen($buf) < 8) { return false; } $ar = unpack('NtotalSize/NboxType', $buf); if ($ar['totalSize'] == 1) { // Size is bigger than 4GB :-O die // Skip ExtendedSize(UI64) and try to decode anyway $buf = fread($f, 8); $ar2 = unpack('N2extSize', $buf); if ($ar2['extSize1'] > 0) { throw new Exception('Extended size not supported'); } else { $ar['totalSize'] = $ar2['extSize2']; } } // Check if we need to skip if (self::skipBoxType($ar['boxType'])) { //print '+++ Skipping box '.pack('N',$ar['boxType']).'<br>'; fseek($f, $ar['totalSize'] - 8, SEEK_CUR); return self::fromStream($f, $parent); } // Check if box is a container, and skip it if so if (self::ignoreBoxType($ar['boxType'])) { //print '+++ Ignoring box '.pack('N',$ar['boxType']).' of size '.$ar['totalSize'].'<br>'; return self::fromStream($f, $parent); } // Get box content if ($ar['totalSize'] > 0) { if ($ar['totalSize'] < 256 * 1024) { $data = fread($f, $ar['totalSize'] - 8); } else { $data = $f; } } else { $data = ''; } // Create box object $box = MP4Info_Box::factory($ar['totalSize'], $ar['boxType'], $data, $parent); //print 'Got box from stream of type 0x'.dechex($ar['boxType']).'('.pack('N',$ar['boxType']).') and size '.$ar['totalSize'].' bytes: '.$box->toString().'<br>'; return $box; }