Parser::parse_ipco( int $num_remaining_bytes ): AvifinfoStatus

In this article

This function’s access is marked private. This means it is not intended for use by plugin or theme developers, only in other core functions. It is listed here for completeness.

Parses an “ipco” box.

Description

"ispe" is used for width and height, "pixi" and "av1C" are used for bit depth and number of channels, and "auxC" is used for alpha.

Parameters

$handleAvifinfostreamrequired
The resource the box will be parsed from.
$num_remaining_bytesintrequired
The number of bytes that should be available from the resource.

Return

AvifinfoStatus FOUND on success or an error on failure.

Source

private function parse_ipco( $num_remaining_bytes ) {
  $box_index = 1; // 1-based index. Used for iterating over properties.
  do {
    $box    = new Box();
    $status = $box->parse( $this->handle, $this->num_parsed_boxes, $num_remaining_bytes );
    if ( $status != FOUND ) {
      return $status;
    }

    if ( $box->type == 'ispe' ) {
      // See ISO/IEC 23008-12:2017(E) 6.5.3.2
      if ( $box->content_size < 8 ) {
        return INVALID;
      }
      if ( !( $data = read( $this->handle, 8 ) ) ) {
        return TRUNCATED;
      }
      $width  = read_big_endian( substr( $data, 0, 4 ), 4 );
      $height = read_big_endian( substr( $data, 4, 4 ), 4 );
      if ( $width == 0 || $height == 0 ) {
        return INVALID;
      }
      if ( count( $this->features->dim_props ) <= MAX_FEATURES &&
           $box_index <= MAX_VALUE ) {
        $dim_prop_count = count( $this->features->dim_props );
        $this->features->dim_props[$dim_prop_count]                 = new Dim_Prop();
        $this->features->dim_props[$dim_prop_count]->property_index = $box_index;
        $this->features->dim_props[$dim_prop_count]->width          = $width;
        $this->features->dim_props[$dim_prop_count]->height         = $height;
      } else {
        $this->data_was_skipped = true;
      }
      if ( !skip( $this->handle, $box->content_size - 8 ) ) {
        return TRUNCATED;
      }
    } else if ( $box->type == 'pixi' ) {
      // See ISO/IEC 23008-12:2017(E) 6.5.6.2
      if ( $box->content_size < 1 ) {
        return INVALID;
      }
      if ( !( $data = read( $this->handle, 1 ) ) ) {
        return TRUNCATED;
      }
      $num_channels = read_big_endian( $data, 1 );
      if ( $num_channels < 1 ) {
        return INVALID;
      }
      if ( $box->content_size < 1 + $num_channels ) {
        return INVALID;
      }
      if ( !( $data = read( $this->handle, 1 ) ) ) {
        return TRUNCATED;
      }
      $bit_depth = read_big_endian( $data, 1 );
      if ( $bit_depth < 1 ) {
        return INVALID;
      }
      for ( $i = 1; $i < $num_channels; ++$i ) {
        if ( !( $data = read( $this->handle, 1 ) ) ) {
          return TRUNCATED;
        }
        // Bit depth should be the same for all channels.
        if ( read_big_endian( $data, 1 ) != $bit_depth ) {
          return INVALID;
        }
        if ( $i > 32 ) {
          return ABORTED; // Be reasonable.
        }
      }
      if ( count( $this->features->chan_props ) <= MAX_FEATURES &&
           $box_index <= MAX_VALUE && $bit_depth <= MAX_VALUE &&
           $num_channels <= MAX_VALUE ) {
        $chan_prop_count = count( $this->features->chan_props );
        $this->features->chan_props[$chan_prop_count]                 = new Chan_Prop();
        $this->features->chan_props[$chan_prop_count]->property_index = $box_index;
        $this->features->chan_props[$chan_prop_count]->bit_depth      = $bit_depth;
        $this->features->chan_props[$chan_prop_count]->num_channels   = $num_channels;
      } else {
        $this->data_was_skipped = true;
      }
      if ( !skip( $this->handle, $box->content_size - ( 1 + $num_channels ) ) ) {
        return TRUNCATED;
      }
    } else if ( $box->type == 'av1C' ) {
      // See AV1 Codec ISO Media File Format Binding 2.3.1
      // at https://aomediacodec.github.io/av1-isobmff/#av1c
      // Only parse the necessary third byte. Assume that the others are valid.
      if ( $box->content_size < 3 ) {
        return INVALID;
      }
      if ( !( $data = read( $this->handle, 3 ) ) ) {
        return TRUNCATED;
      }
      $byte          = read_big_endian( substr( $data, 2, 1 ), 1 );
      $high_bitdepth = ( $byte & 0x40 ) != 0;
      $twelve_bit    = ( $byte & 0x20 ) != 0;
      $monochrome    = ( $byte & 0x10 ) != 0;
      if ( $twelve_bit && !$high_bitdepth ) {
          return INVALID;
      }
      if ( count( $this->features->chan_props ) <= MAX_FEATURES &&
           $box_index <= MAX_VALUE ) {
        $chan_prop_count = count( $this->features->chan_props );
        $this->features->chan_props[$chan_prop_count]                 = new Chan_Prop();
        $this->features->chan_props[$chan_prop_count]->property_index = $box_index;
        $this->features->chan_props[$chan_prop_count]->bit_depth      =
            $high_bitdepth ? $twelve_bit ? 12 : 10 : 8;
        $this->features->chan_props[$chan_prop_count]->num_channels   = $monochrome ? 1 : 3;
      } else {
        $this->data_was_skipped = true;
      }
      if ( !skip( $this->handle, $box->content_size - 3 ) ) {
        return TRUNCATED;
      }
    } else if ( $box->type == 'auxC' ) {
      // See AV1 Image File Format (AVIF) 4
      // at https://aomediacodec.github.io/av1-avif/#auxiliary-images
      $kAlphaStr       = "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0";
      $kAlphaStrLength = 44; // Includes terminating character.
      if ( $box->content_size >= $kAlphaStrLength ) {
        if ( !( $data = read( $this->handle, $kAlphaStrLength ) ) ) {
          return TRUNCATED;
        }
        if ( substr( $data, 0, $kAlphaStrLength ) == $kAlphaStr ) {
          // Note: It is unlikely but it is possible that this alpha plane does
          //       not belong to the primary item or a tile. Ignore this issue.
          $this->features->has_alpha = true;
        }
        if ( !skip( $this->handle, $box->content_size - $kAlphaStrLength ) ) {
          return TRUNCATED;
        }
      } else {
        if ( !skip( $this->handle, $box->content_size ) ) {
          return TRUNCATED;
        }
      }
    } else {
      if ( !skip( $this->handle, $box->content_size ) ) {
        return TRUNCATED;
      }
    }
    ++$box_index;
    $num_remaining_bytes -= $box->size;
  } while ( $num_remaining_bytes > 0 );
  return NOT_FOUND;
}

User Contributed Notes

You must log in before being able to contribute a note or feedback.