class Box {
public $size; // In bytes.
public $type; // Four characters.
public $version; // 0 or actual version if this is a full box.
public $flags; // 0 or actual value if this is a full box.
public $content_size; // 'size' minus the header size.
/**
* Reads the box header.
*
* @param stream $handle The resource the header will be parsed from.
* @param int $num_parsed_boxes The total number of parsed boxes. Prevents timeouts.
* @param int $num_remaining_bytes The number of bytes that should be available from the resource.
* @return Status FOUND on success or an error on failure.
*/
public function parse( $handle, &$num_parsed_boxes, $num_remaining_bytes = MAX_SIZE ) {
// See ISO/IEC 14496-12:2012(E) 4.2
$header_size = 8; // box 32b size + 32b type (at least)
if ( $header_size > $num_remaining_bytes ) {
return INVALID;
}
if ( !( $data = read( $handle, 8 ) ) ) {
return TRUNCATED;
}
$this->size = read_big_endian( $data, 4 );
$this->type = substr( $data, 4, 4 );
// 'box->size==1' means 64-bit size should be read after the box type.
// 'box->size==0' means this box extends to all remaining bytes.
if ( $this->size == 1 ) {
$header_size += 8;
if ( $header_size > $num_remaining_bytes ) {
return INVALID;
}
if ( !( $data = read( $handle, 8 ) ) ) {
return TRUNCATED;
}
// Stop the parsing if any box has a size greater than 4GB.
if ( read_big_endian( $data, 4 ) != 0 ) {
return ABORTED;
}
// Read the 32 least-significant bits.
$this->size = read_big_endian( substr( $data, 4, 4 ), 4 );
} else if ( $this->size == 0 ) {
$this->size = $num_remaining_bytes;
}
if ( $this->size < $header_size ) {
return INVALID;
}
if ( $this->size > $num_remaining_bytes ) {
return INVALID;
}
$has_fullbox_header = $this->type == 'meta' || $this->type == 'pitm' ||
$this->type == 'ipma' || $this->type == 'ispe' ||
$this->type == 'pixi' || $this->type == 'iref' ||
$this->type == 'auxC';
if ( $has_fullbox_header ) {
$header_size += 4;
}
if ( $this->size < $header_size ) {
return INVALID;
}
$this->content_size = $this->size - $header_size;
// Avoid timeouts. The maximum number of parsed boxes is arbitrary.
++$num_parsed_boxes;
if ( $num_parsed_boxes >= MAX_NUM_BOXES ) {
return ABORTED;
}
$this->version = 0;
$this->flags = 0;
if ( $has_fullbox_header ) {
if ( !( $data = read( $handle, 4 ) ) ) {
return TRUNCATED;
}
$this->version = read_big_endian( $data, 1 );
$this->flags = read_big_endian( substr( $data, 1, 3 ), 3 );
// See AV1 Image File Format (AVIF) 8.1
// at https://aomediacodec.github.io/av1-avif/#avif-boxes (available when
// https://github.com/AOMediaCodec/av1-avif/pull/170 is merged).
$is_parsable = ( $this->type == 'meta' && $this->version <= 0 ) ||
( $this->type == 'pitm' && $this->version <= 1 ) ||
( $this->type == 'ipma' && $this->version <= 1 ) ||
( $this->type == 'ispe' && $this->version <= 0 ) ||
( $this->type == 'pixi' && $this->version <= 0 ) ||
( $this->type == 'iref' && $this->version <= 1 ) ||
( $this->type == 'auxC' && $this->version <= 0 );
// Instead of considering this file as invalid, skip unparsable boxes.
if ( !$is_parsable ) {
$this->type = 'unknownversion';
}
}
// print_r( $this ); // Uncomment to print all boxes.
return FOUND;
}
}
View all references View on Trac View on GitHub
User Contributed Notes
You must log in before being able to contribute a note or feedback.