Task 048 - .AVIF File Format

Task 048 - .AVIF File Format

1. Properties of the AVIF File Format Intrinsic to Its File System

The AV1 Image File Format (AVIF) is a modern, open, royalty-free image format that stores images or image sequences compressed with the AV1 codec within a High Efficiency Image File Format (HEIF) container, based on the ISO Base Media File Format (ISOBMFF). Below is a list of intrinsic properties of the AVIF file format, derived from its specification and structure as defined by the Alliance for Open Media (AOMedia) and related standards. These properties are inherent to the file format’s structure and its interaction with the file system.

  • File Extension: .avif for still images, .avis for image sequences/animations.
  • MIME Type: image/avif (IANA-registered media type for AVIF files).
  • Container Format: Based on HEIF (High Efficiency Image File Format), which itself is built upon ISOBMFF (ISO Base Media File Format, ISO/IEC 14496-12).
  • Compression Codec: Uses AV1 (AOMedia Video 1) for lossy or lossless compression of image data.
  • File Type Signifiers: The FileTypeBox (ftyp) in the file structure includes:
  • Major brand: avif (for still images) or avis (for image sequences).
  • Compatible brands: Includes avif, avis, miaf (Multi-Image Application Format), and mif1 (HEIF-specific brand).
  • Color Space Support:
  • Multiple color spaces: sRGB, BT.709, BT.601, BT.2020 (for HDR).
  • Color space signaling via CICP (ITU-T H.273/ISO/IEC 23091-2) or ICC profiles.
  • Support for SDR and HDR (PQ or HLG transfer functions, BT.2100 for HDR).
  • Bit Depth: Supports 8-bit, 10-bit, and 12-bit color depths.
  • Chroma Subsampling: Supports 4:2:0, 4:2:2, 4:4:4 chroma subsampling, and RGB.
  • Transparency Support: Includes alpha channel for transparency (monochrome or multi-component).
  • Image Types:
  • Single image (still image).
  • Image sequences (animations, similar to animated GIFs).
  • Compression Modes: Supports both lossless and lossy compression.
  • Profiles:
  • AVIF Baseline Profile: Uses AV1 Main Profile, level 5.1 or lower.
  • AVIF Advanced Profile: Supports additional AV1 features (e.g., film grain synthesis).
  • Metadata Support:
  • Color profile metadata (e.g., ICC profiles).
  • Experimental GeoHEIF georeferencing metadata (read-only, requires libavif 1.2.0+).
  • Animation Support: Supports multiple frames for image sequences (similar to video tracks in ISOBMFF).
  • Progressive Loading: Supports progressive decoding for gradual image rendering.
  • File Structure Boxes: Key ISOBMFF/HEIF boxes relevant to AVIF include:
  • ftyp (File Type Box): Defines the file type and compatible brands.
  • meta (Metadata Box): Contains metadata like image properties.
  • mdat (Media Data Box): Stores the compressed AV1 bitstream.
  • ispe (Image Spatial Extents): Specifies image dimensions (width, height).
  • colr (Colour Information Box): Defines color space and profile.
  • pixi (Pixel Information): Specifies bit depth and channel count.
  • av1C (AV1 Codec Configuration Box): Contains AV1 codec configuration.
  • ipma (Item Property Association): Links properties to image items.
  • File Size Efficiency: Achieves up to 50% smaller file sizes compared to JPEG at similar quality due to AV1 compression.
  • Royalty-Free: Open and royalty-free, developed by the Alliance for Open Media.

These properties are intrinsic to the AVIF file format as they define its structure, encoding, and metadata within the file system, based on the HEIF/ISOBMFF container and AV1 codec.

2. Python Class for AVIF File Handling

Below is a Python class that uses the pillow library (with AVIF support via pillow-avif-plugin) and pyavif to open, decode, read, write, and print AVIF file properties. Note that handling low-level ISOBMFF boxes requires a library like isobmff or manual parsing, but here we focus on accessible properties using available libraries.

from PIL import Image
import avif
import os
import struct
import io

class AVIFHandler:
    def __init__(self, filepath):
        self.filepath = filepath
        self.image = None
        self.properties = {}

    def read_properties(self):
        """Read and decode AVIF file properties."""
        try:
            self.image = Image.open(self.filepath)
            if self.image.format != 'AVIF':
                raise ValueError("File is not in AVIF format")

            # Basic file properties
            self.properties['file_extension'] = os.path.splitext(self.filepath)[1].lower()
            self.properties['mime_type'] = 'image/avif'
            self.properties['container_format'] = 'HEIF/ISOBMFF'
            self.properties['compression_codec'] = 'AV1'
            self.properties['width'], self.properties['height'] = self.image.size
            self.properties['bit_depth'] = self.image.mode  # e.g., RGB, RGBA, L
            self.properties['has_alpha'] = 'A' in self.image.mode
            self.properties['color_space'] = self.image.info.get('icc_profile', 'Unknown') or 'sRGB/BT.709'
            
            # File size
            self.properties['file_size'] = os.path.getsize(self.filepath)
            
            # Read basic ISOBMFF boxes (simplified, requires isobmff library for full parsing)
            with open(self.filepath, 'rb') as f:
                data = f.read(32)  # Read header for ftyp box
                ftyp = data[8:12].decode('utf-8', errors='ignore')
                compatible_brands = data[12:20].decode('utf-8', errors='ignore')
                self.properties['major_brand'] = ftyp
                self.properties['compatible_brands'] = compatible_brands.split('\x00')

            # Animation check (basic, assumes single image if no frames)
            self.properties['is_animated'] = getattr(self.image, 'is_animated', False)
            
            # Compression mode (approximate, as PIL doesn't expose this directly)
            self.properties['compression_mode'] = 'Lossy'  # AVIF typically lossy unless specified

        except Exception as e:
            print(f"Error reading AVIF properties: {e}")

    def print_properties(self):
        """Print all properties to console."""
        for key, value in self.properties.items():
            print(f"{key}: {value}")

    def write_avif(self, output_path, quality=50):
        """Write the AVIF image to a new file."""
        try:
            if self.image:
                self.image.save(output_path, format='AVIF', quality=quality)
                print(f"AVIF file written to {output_path}")
            else:
                print("No image loaded to write")
        except Exception as e:
            print(f"Error writing AVIF file: {e}")

# Example usage
if __name__ == "__main__":
    avif_file = "sample.avif"
    handler = AVIFHandler(avif_file)
    handler.read_properties()
    handler.print_properties()
    handler.write_avif("output.avif")

Dependencies:

  • Install pillow, pillow-avif-plugin, and pyavif:
pip install pillow pillow-avif-plugin pyavif
  • The isobmff library (not used here but recommended for low-level box parsing) can be installed if needed.

Notes:

  • This implementation uses PIL for high-level image handling. Low-level ISOBMFF box parsing (e.g., av1C, colr) requires additional libraries or custom parsing, which is simplified here.
  • The write_avif method allows saving with adjustable quality (0-100, where lower values increase lossy compression).
  • Not all properties (e.g., exact chroma subsampling, AV1 profile) are easily accessible via PIL. For deeper inspection, use libavif bindings or parse the file manually.

3. Java Class for AVIF File Handling

Below is a Java class using the libavif library (via JNI bindings, assuming a Java wrapper like libavif-java) to handle AVIF files. Since Java lacks native AVIF support in standard libraries, we assume a third-party library or manual ISOBMFF parsing.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

// Placeholder for libavif Java bindings (assumed available)
import org.libavif.AvifDecoder;
import org.libavif.AvifEncoder;
import org.libavif.AvifImage;

public class AVIFHandler {
    private String filepath;
    private AvifImage image;
    private Map<String, Object> properties;

    public AVIFHandler(String filepath) {
        this.filepath = filepath;
        this.properties = new HashMap<>();
    }

    public void readProperties() {
        try {
            File file = new File(filepath);
            if (!file.exists() || !filepath.toLowerCase().endsWith(".avif")) {
                throw new IllegalArgumentException("Invalid AVIF file");
            }

            // Decode AVIF using libavif
            AvifDecoder decoder = new AvifDecoder();
            this.image = decoder.decode(new FileInputStream(file));

            // Extract properties
            properties.put("file_extension", ".avif");
            properties.put("mime_type", "image/avif");
            properties.put("container_format", "HEIF/ISOBMFF");
            properties.put("compression_codec", "AV1");
            properties.put("width", image.getWidth());
            properties.put("height", image.getHeight());
            properties.put("bit_depth", image.getBitDepth());
            properties.put("has_alpha", image.hasAlpha());
            properties.put("color_space", image.getColorSpace() != null ? image.getColorSpace() : "sRGB/BT.709");
            properties.put("file_size", file.length());

            // Read ftyp box (simplified)
            try (FileInputStream fis = new FileInputStream(file)) {
                byte[] header = new byte[32];
                fis.read(header);
                String majorBrand = new String(header, 8, 4, "UTF-8");
                String compatibleBrands = new String(header, 12, 8, "UTF-8");
                properties.put("major_brand", majorBrand);
                properties.put("compatible_brands", compatibleBrands.trim().split("\0"));
            }

            // Animation and compression (simplified)
            properties.put("is_animated", image.isAnimated());
            properties.put("compression_mode", "Lossy"); // Default assumption

        } catch (Exception e) {
            System.err.println("Error reading AVIF properties: " + e.getMessage());
        }
    }

    public void printProperties() {
        properties.forEach((key, value) -> System.out.println(key + ": " + value));
    }

    public void writeAVIF(String outputPath, int quality) {
        try {
            if (image != null) {
                AvifEncoder encoder = new AvifEncoder();
                encoder.setQuality(quality);
                encoder.encode(image, new FileOutputStream(outputPath));
                System.out.println("AVIF file written to " + outputPath);
            } else {
                System.err.println("No image loaded to write");
            }
        } catch (Exception e) {
            System.err.println("Error writing AVIF file: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        AVIFHandler handler = new AVIFHandler("sample.avif");
        handler.readProperties();
        handler.printProperties();
        handler.writeAVIF("output.avif", 50);
    }
}

Dependencies:

  • Requires libavif and a Java JNI wrapper (e.g., libavif-java, which may need to be custom-built).
  • Alternatively, use a library like Apache Commons Imaging (if AVIF support is added) or manual ISOBMFF parsing.

Notes:

  • The libavif library is assumed for decoding/encoding. If unavailable, you’d need to parse ISOBMFF boxes manually using ByteBuffer.
  • Properties like av1C or colr require deep parsing of the HEIF structure, which is simplified here.
  • Quality parameter (0-100) controls lossy compression level.

4. JavaScript Class for AVIF File Handling

Below is a JavaScript class using the libavif JavaScript bindings (e.g., avif.js) or a browser-based Image API for AVIF handling. Node.js is assumed for file system operations.

const fs = require('fs').promises;
const { decode, encode } = require('avif'); // Hypothetical libavif JS bindings

class AVIFHandler {
    constructor(filepath) {
        this.filepath = filepath;
        this.image = null;
        this.properties = {};
    }

    async readProperties() {
        try {
            if (!this.filepath.toLowerCase().endsWith('.avif')) {
                throw new Error('Invalid AVIF file');
            }

            // Read file
            const buffer = await fs.readFile(this.filepath);

            // Decode AVIF
            this.image = await decode(buffer);

            // Extract properties
            this.properties.file_extension = '.avif';
            this.properties.mime_type = 'image/avif';
            this.properties.container_format = 'HEIF/ISOBMFF';
            this.properties.compression_codec = 'AV1';
            this.properties.width = this.image.width;
            this.properties.height = this.image.height;
            this.properties.bit_depth = this.image.bitDepth || 8;
            this.properties.has_alpha = this.image.hasAlpha || false;
            this.properties.color_space = this.image.colorSpace || 'sRGB/BT.709';
            this.properties.file_size = buffer.length;

            // Parse ftyp box (simplified)
            const ftyp = buffer.toString('utf8', 8, 12);
            const compatibleBrands = buffer.toString('utf8', 12, 20).split('\0').filter(Boolean);
            this.properties.major_brand = ftyp;
            this.properties.compatible_brands = compatibleBrands;

            // Animation and compression
            this.properties.is_animated = this.image.isAnimated || false;
            this.properties.compression_mode = 'Lossy'; // Default

        } catch (error) {
            console.error('Error reading AVIF properties:', error.message);
        }
    }

    printProperties() {
        for (const [key, value] of Object.entries(this.properties)) {
            console.log(`${key}: ${value}`);
        }
    }

    async writeAVIF(outputPath, quality = 50) {
        try {
            if (this.image) {
                const encoded = await encode(this.image, { quality });
                await fs.writeFile(outputPath, encoded);
                console.log(`AVIF file written to ${outputPath}`);
            } else {
                console.error('No image loaded to write');
            }
        } catch (error) {
            console.error('Error writing AVIF file:', error.message);
        }
    }
}

// Example usage
(async () => {
    const handler = new AVIFHandler('sample.avif');
    await handler.readProperties();
    handler.printProperties();
    await handler.writeAVIF('output.avif');
})();

Dependencies:

  • Install avif or similar library:
npm install avif
  • Alternatively, use browser APIs (Image object) for client-side decoding, but file system operations require Node.js.

Notes:

  • The avif library is hypothetical; you may need libavif with JS bindings or a library like squoosh for AVIF encoding/decoding.
  • Low-level box parsing (av1C, colr) is simplified; use a dedicated ISOBMFF parser for full details.
  • Quality parameter (0-100) controls lossy compression.

5. C Class for AVIF File Handling

Below is a C implementation using libavif for AVIF file handling. This provides low-level access to AVIF properties and encoding/decoding.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <avif/avif.h>

typedef struct {
    char* filepath;
    avifImage* image;
    avifDecoder* decoder;
    struct {
        char* file_extension;
        char* mime_type;
        char* container_format;
        char* compression_codec;
        uint32_t width;
        uint32_t height;
        uint8_t bit_depth;
        int has_alpha;
        char* color_space;
        long file_size;
        char* major_brand;
        char* compatible_brands[8];
        int is_animated;
        char* compression_mode;
    } properties;
} AVIFHandler;

void avif_handler_init(AVIFHandler* handler, const char* filepath) {
    handler->filepath = strdup(filepath);
    handler->image = NULL;
    handler->decoder = NULL;
    handler->properties.file_extension = ".avif";
    handler->properties.mime_type = "image/avif";
    handler->properties.container_format = "HEIF/ISOBMFF";
    handler->properties.compression_codec = "AV1";
    handler->properties.color_space = "sRGB/BT.709";
    handler->properties.compression_mode = "Lossy";
}

void avif_handler_read_properties(AVIFHandler* handler) {
    FILE* file = fopen(handler->filepath, "rb");
    if (!file || strstr(handler->filepath, ".avif") == NULL) {
        printf("Error: Invalid AVIF file\n");
        return;
    }

    // Decode AVIF
    handler->decoder = avifDecoderCreate();
    avifResult result = avifDecoderReadFile(handler->decoder, handler->filepath, &handler->image);
    if (result != AVIF_RESULT_OK) {
        printf("Error decoding AVIF: %s\n", avifResultToString(result));
        fclose(file);
        return;
    }

    // Extract properties
    handler->properties.width = handler->image->width;
    handler->properties.height = handler->image->height;
    handler->properties.bit_depth = handler->image->depth;
    handler->properties.has_alpha = handler->image->alphaPlane != NULL;
    fseek(file, 0, SEEK_END);
    handler->properties.file_size = ftell(file);

    // Read ftyp box (simplified)
    fseek(file, 8, SEEK_SET);
    char ftyp[5] = {0};
    fread(ftyp, 1, 4, file);
    handler->properties.major_brand = strdup(ftyp);
    char brands[9] = {0};
    fread(brands, 1, 8, file);
    for (int i = 0; i < 2; i++) {
        handler->properties.compatible_brands[i] = strndup(brands + i*4, 4);
    }
    handler->properties.is_animated = handler->decoder->imageCount > 1;

    fclose(file);
}

void avif_handler_print_properties(AVIFHandler* handler) {
    printf("file_extension: %s\n", handler->properties.file_extension);
    printf("mime_type: %s\n", handler->properties.mime_type);
    printf("container_format: %s\n", handler->properties.container_format);
    printf("compression_codec: %s\n", handler->properties.compression_codec);
    printf("width: %u\n", handler->properties.width);
    printf("height: %u\n", handler->properties.height);
    printf("bit_depth: %u\n", handler->properties.bit_depth);
    printf("has_alpha: %d\n", handler->properties.has_alpha);
    printf("color_space: %s\n", handler->properties.color_space);
    printf("file_size: %ld\n", handler->properties.file_size);
    printf("major_brand: %s\n", handler->properties.major_brand);
    printf("compatible_brands: %s %s\n", handler->properties.compatible_brands[0], 
           handler->properties.compatible_brands[1]);
    printf("is_animated: %d\n", handler->properties.is_animated);
    printf("compression_mode: %s\n", handler->properties.compression_mode);
}

void avif_handler_write_avif(AVIFHandler* handler, const char* output_path, int quality) {
    if (!handler->image) {
        printf("No image loaded to write\n");
        return;
    }

    avifEncoder* encoder = avifEncoderCreate();
    encoder->quality = quality;
    avifRWData output = AVIF_DATA_EMPTY;
    avifResult result = avifEncoderWrite(encoder, handler->image, &output);
    if (result == AVIF_RESULT_OK) {
        FILE* out = fopen(output_path, "wb");
        fwrite(output.data, 1, output.size, out);
        fclose(out);
        printf("AVIF file written to %s\n", output_path);
    } else {
        printf("Error writing AVIF: %s\n", avifResultToString(result));
    }
    avifRWDataFree(&output);
    avifEncoderDestroy(encoder);
}

void avif_handler_destroy(AVIFHandler* handler) {
    if (handler->image) avifImageDestroy(handler->image);
    if (handler->decoder) avifDecoderDestroy(handler->decoder);
    free(handler->filepath);
    free(handler->properties.major_brand);
    for (int i = 0; i < 2; i++) free(handler->properties.compatible_brands[i]);
}

int main() {
    AVIFHandler handler;
    avif_handler_init(&handler, "sample.avif");
    avif_handler_read_properties(&handler);
    avif_handler_print_properties(&handler);
    avif_handler_write_avif(&handler, "output.avif", 50);
    avif_handler_destroy(&handler);
    return 0;
}

Dependencies:

  • Install libavif:
# On Ubuntu
sudo apt-get install libavif-dev
  • Compile with:
gcc -o avif_handler avif_handler.c -lavif

Notes:

  • Uses libavif for robust AVIF handling, including decoding/encoding.
  • Simplified ftyp box parsing; full ISOBMFF parsing requires additional libraries or custom code.
  • Quality parameter (0-100) controls lossy compression.

General Notes

  • Library Availability: The Python, Java, and JavaScript implementations assume third-party libraries (pillow-avif-plugin, libavif, etc.). If unavailable, manual ISOBMFF parsing is required, which is complex and not fully implemented here due to space constraints.
  • Property Extraction: Not all properties (e.g., exact chroma subsampling, AV1 profile) are easily accessible without deep parsing. The provided code extracts accessible properties and simplifies box parsing.
  • Error Handling: Each implementation includes basic error handling, but production code should include more robust checks.
  • Writing AVIF: The write functionality assumes lossy compression by default, as lossless requires specific encoder settings not universally supported in all libraries.
  • Testing: Test with a valid .avif file. Sample files are available from Netflix’s AVIF test set or AOMedia’s repository.

If you need deeper ISOBMFF parsing or specific property extraction (e.g., av1C details), please let me know, and I can provide a more detailed implementation!

  1. List of properties:
  • Major brand
  • Minor version
  • Compatible brands
  • Image width
  • Image height
  • Bit depth
  • Number of channels
  • Colour primaries
  • Transfer characteristics
  • Matrix coefficients
  • Full range flag
  • ICC profile
  • Max content light level
  • Max pic average light level
  • Mastering primaries (R,G,B x/y)
  • Mastering white point (x/y)
  • Max display luminance
  • Min display luminance
  • Rotation
  • Mirror axis
  • Clean aperture (width, height, h_offset, v_offset)
  • Operating point index
  • Layer ID
  • Layer sizes
  • Auxiliary type
  • AV1 configuration
  • EXIF data
  • XMP data
  1. Python class:
import struct
import os

class AVIFParser:
    def __init__(self, filename):
        self.filename = filename
        self.properties = {}
        self.boxes = {}
        self.parse()

    def parse_box(self, data, pos):
        size = struct.unpack('>I', data[pos:pos+4])[0]
        box_type = data[pos+4:pos+8].decode('ascii')
        header_size = 8
        if size == 1:
            size = struct.unpack('>Q', data[pos+8:pos+16])[0]
            header_size = 16
        return box_type, size, header_size, data[pos+header_size:pos+size]

    def parse(self):
        with open(self.filename, 'rb') as f:
            data = f.read()
        pos = 0
        while pos < len(data):
            box_type, size, header_size, box_data = self.parse_box(data, pos)
            self.boxes[box_type] = box_data
            pos += size
            if box_type == 'ftyp':
                self.properties['major_brand'] = box_data[0:4].decode('ascii')
                self.properties['minor_version'] = struct.unpack('>I', box_data[4:8])[0]
                self.properties['compatible_brands'] = [box_data[i:i+4].decode('ascii') for i in range(8, len(box_data), 4)]
            elif box_type == 'meta':
                meta_pos = 4  # skip version/flags
                while meta_pos < len(box_data):
                    sub_type, sub_size, sub_header, sub_data = self.parse_box(box_data, meta_pos)
                    if sub_type == 'iprp':
                        iprp_pos = 0
                        while iprp_pos < len(sub_data):
                            ip_type, ip_size, ip_header, ip_data = self.parse_box(sub_data, iprp_pos)
                            if ip_type == 'ipco':
                                ipco_pos = 0
                                prop_index = 1
                                while ipco_pos < len(ip_data):
                                    p_type, p_size, p_header, p_data = self.parse_box(ip_data, ipco_pos)
                                    if p_type == 'ispe':
                                        self.properties['image_width'] = struct.unpack('>I', p_data[4:8])[0]
                                        self.properties['image_height'] = struct.unpack('>I', p_data[8:12])[0]
                                    elif p_type == 'pixi':
                                        num_channels = p_data[0]
                                        self.properties['num_channels'] = num_channels
                                        self.properties['bit_depth'] = p_data[1]  # first channel
                                    elif p_type == 'colr':
                                        colr_type = p_data[0:4].decode('ascii')
                                        if colr_type == 'nclx':
                                            self.properties['colour_primaries'] = struct.unpack('>H', p_data[4:6])[0]
                                            self.properties['transfer_characteristics'] = struct.unpack('>H', p_data[6:8])[0]
                                            self.properties['matrix_coefficients'] = struct.unpack('>H', p_data[8:10])[0]
                                            self.properties['full_range_flag'] = (p_data[10] >> 7) & 1
                                        else:
                                            self.properties['icc_profile'] = p_data[4:]
                                    elif p_type == 'clli':
                                        self.properties['max_content_light_level'] = struct.unpack('>H', p_data[0:2])[0]
                                        self.properties['max_pic_average_light_level'] = struct.unpack('>H', p_data[2:4])[0]
                                    elif p_type == 'mdcv':
                                        primaries = []
                                        for i in range(0, 12, 2):
                                            primaries.append(struct.unpack('>H', p_data[i:i+2])[0] / 50000.0)
                                        self.properties['mastering_primaries'] = primaries
                                        self.properties['mastering_white_point'] = [struct.unpack('>H', p_data[12:14])[0] / 50000.0, struct.unpack('>H', p_data[14:16])[0] / 50000.0]
                                        self.properties['max_display_luminance'] = struct.unpack('>I', p_data[16:20])[0] / 10000.0
                                        self.properties['min_display_luminance'] = struct.unpack('>I', p_data[20:24])[0] / 10000.0
                                    elif p_type == 'irot':
                                        self.properties['rotation'] = (p_data[0] & 0x3) * 90
                                    elif p_type == 'imir':
                                        self.properties['mirror_axis'] = p_data[0] & 0x1
                                    elif p_type == 'clap':
                                        # Fractions: num/denom
                                        self.properties['clean_aperture'] = {
                                            'width': struct.unpack('>I', p_data[0:4])[0] / struct.unpack('>I', p_data[4:8])[0],
                                            'height': struct.unpack('>I', p_data[8:12])[0] / struct.unpack('>I', p_data[12:16])[0],
                                            'h_offset': struct.unpack('>I', p_data[16:20])[0] / struct.unpack('>I', p_data[20:24])[0],
                                            'v_offset': struct.unpack('>I', p_data[24:28])[0] / struct.unpack('>I', p_data[28:32])[0]
                                        }
                                    elif p_type == 'a1op':
                                        self.properties['operating_point_index'] = p_data[0]
                                    elif p_type == 'lsel':
                                        self.properties['layer_id'] = struct.unpack('>H', p_data[0:2])[0]
                                    elif p_type == 'a1lx':
                                        large_size = p_data[0] & 1
                                        field_len = (large_size + 1) * 16 // 8  # bytes
                                        self.properties['layer_sizes'] = []
                                        for i in range(1, 1 + 3*field_len, field_len):
                                            self.properties['layer_sizes'].append(struct.unpack('>I' if field_len==4 else '>H', p_data[i:i+field_len])[0])
                                    elif p_type == 'auxC':
                                        self.properties['auxiliary_type'] = p_data[4:].decode('utf-8').rstrip('\x00')
                                    elif p_type == 'av1C':
                                        self.properties['av1_configuration'] = p_data
                                    prop_index += 1
                                    ipco_pos += p_size
                            iprp_pos += ip_size
                    elif sub_type == 'iinf':
                        # Item infos, for EXIF, XMP
                        iinf_pos = 4  # version, flags
                        entry_count = struct.unpack('>H', sub_data[iinf_pos:iinf_pos+2])[0]
                        iinf_pos += 2
                        for _ in range(entry_count):
                            # Parse infe boxes
                            infe_type, infe_size, infe_header, infe_data = self.parse_box(sub_data, iinf_pos)
                            if infe_type == 'infe':
                                version = infe_data[0]
                                flags = struct.unpack('>I', b'\x00' + infe_data[1:4])[0]
                                item_id = struct.unpack('>H' if version==2 else '>I', infe_data[4:4+(2 if version==2 else 4)])[0]
                                # ... item_type, name
                                item_type = infe_data[-4:].decode('ascii')
                                if item_type == 'Exif':
                                    self.properties['exif_data'] = 'present'  # would need to read from iloc + mdat
                                elif item_type == 'mime':
                                    # Check name or content_type for XMP
                                    self.properties['xmp_data'] = 'present'
                            iinf_pos += infe_size
                    # Add parsing for iloc to get data if needed
                    meta_pos += sub_size

    def write(self, new_filename=None):
        # For write, rebuild the file with updated properties
        # This is complex, assuming no change in data size for simplicity
        # Implement setting properties and rebuilding boxes
        # Omitted for brevity, but in full would pack back using struct.pack
        pass
  1. Java class:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashMap;
import java.util.Map;

public class AVIFParser {
    private String filename;
    private Map<String, Object> properties = new HashMap<>();
    private Map<String, byte[]> boxes = new HashMap<>();

    public AVIFParser(String filename) {
        this.filename = filename;
        parse();
    }

    private int[] parseBox(byte[] data, int pos) {
        ByteBuffer bb = ByteBuffer.wrap(data, pos, data.length - pos).order(ByteOrder.BIG_ENDIAN);
        int size = bb.getInt();
        String boxType = new String(data, pos + 4, 4);
        int headerSize = 8;
        if (size == 1) {
            long largeSize = bb.getLong(8);
            size = (int) largeSize;  // Assume fits in int
            headerSize = 16;
        }
        byte[] boxData = new byte[size - headerSize];
        System.arraycopy(data, pos + headerSize, boxData, 0, boxData.length);
        return new int[]{size, headerSize};  // Return size and header for pos update
    }

    private void parse() {
        try (FileInputStream fis = new FileInputStream(filename)) {
            byte[] data = fis.readAllBytes();
            int pos = 0;
            while (pos < data.length) {
                ByteBuffer bb = ByteBuffer.wrap(data, pos, 8).order(ByteOrder.BIG_ENDIAN);
                int size = bb.getInt();
                String boxType = new String(data, pos + 4, 4);
                int headerSize = 8;
                if (size == 1) {
                    ByteBuffer bbLarge = ByteBuffer.wrap(data, pos + 8, 8).order(ByteOrder.BIG_ENDIAN);
                    size = (int) bbLarge.getLong();
                    headerSize = 16;
                }
                byte[] boxData = new byte[size - headerSize];
                System.arraycopy(data, pos + headerSize, boxData, 0, boxData.length);
                boxes.put(boxType, boxData);
                pos += size;
                if (boxType.equals("ftyp")) {
                    properties.put("major_brand", new String(boxData, 0, 4));
                    properties.put("minor_version", ByteBuffer.wrap(boxData, 4, 4).order(ByteOrder.BIG_ENDIAN).getInt());
                    // Compatible brands
                } // Similar parsing as in Python for other boxes and properties
                // Implement full parsing similar to Python
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void write(String newFilename) {
        // Similar to Python, rebuild and write
        // Omitted for brevity
    }
}
  1. JavaScript class:
const fs = require('fs');

class AVIFParser {
    constructor(filename) {
        this.filename = filename;
        this.properties = {};
        this.boxes = {};
        this.parse();
    }

    parseBox(data, pos) {
        let dv = new DataView(data.buffer, data.byteOffset + pos);
        let size = dv.getUint32(0);
        let boxType = String.fromCharCode(dv.getUint8(4), dv.getUint8(5), dv.getUint8(6), dv.getUint8(7));
        let headerSize = 8;
        if (size === 1) {
            size = Number(dv.getBigUint64(8));
            headerSize = 16;
        }
        let boxData = data.slice(pos + headerSize, pos + size);
        return {boxType, size, boxData};
    }

    parse() {
        let data = fs.readFileSync(this.filename);
        let pos = 0;
        while (pos < data.length) {
            let {boxType, size, boxData} = this.parseBox(data, pos);
            this.boxes[boxType] = boxData;
            pos += size;
            if (boxType === 'ftyp') {
                this.properties.major_brand = String.fromCharCode(...boxData.slice(0,4));
                this.properties.minor_version = new DataView(boxData.buffer, boxData.byteOffset + 4, 4).getUint32(0);
                // etc.
            } // Similar to Python for other
        }
    }

    write(newFilename) {
        // Rebuild and fs.writeFileSync
        // Omitted
    }
}
  1. C class (C++):
#include <fstream>
#include <vector>
#include <map>
#include <string>
#include <cstdint>

class AVIFParser {
private:
    std::string filename;
    std::map<std::string, std::vector<uint8_t>> boxes;
    std::map<std::string, std::string> properties;  // Use variant for different types

public:
    AVIFParser(const std::string& fn) : filename(fn) {
        parse();
    }

    void parse() {
        std::ifstream file(filename, std::ios::binary);
        std::vector<uint8_t> data((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
        size_t pos = 0;
        while (pos < data.size()) {
            uint32_t size = (data[pos] << 24) | (data[pos+1] << 16) | (data[pos+2] << 8) | data[pos+3];
            std::string boxType(data.begin() + pos + 4, data.begin() + pos + 8);
            size_t headerSize = 8;
            if (size == 1) {
                uint64_t largeSize = ((uint64_t)data[pos+8] << 56) | ((uint64_t)data[pos+9] << 48) | // etc
                size = static_cast<uint32_t>(largeSize);
                headerSize = 16;
            }
            std::vector<uint8_t> boxData(data.begin() + pos + headerSize, data.begin() + pos + size);
            boxes[boxType] = boxData;
            pos += size;
            if (boxType == "ftyp") {
                // Parse similar
            } // etc.
        }
    }

    void write(const std::string& newFilename) {
        // Similar
    }
};