Avifinfo

Parser::parse_ipco()privateWP 1.0

Parses an "ipco" box.

"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.

Метод класса: Parser{}

Хуков нет.

Возвращает

Status. FOUND on success or an error on failure.

Использование

// private - только в коде основоного (родительского) класса
$result = $this->parse_ipco( $num_remaining_bytes );
$num_remaining_bytes(int) (обязательный)
The number of bytes that should be available from the resource.

Код Parser::parse_ipco() WP 6.6.2

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;
}