From ed751cb3ccdfaa74bbff95cf92210ea7d47cb318 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 25 Aug 2026 00:06:25 +1000 Subject: [PATCH] Decode every AV1 tile superblock row --- .../Heif/Av1/Pipeline/Av1FrameDecoder.cs | 37 ++++++++----------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1FrameDecoder.cs b/src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1FrameDecoder.cs index 6f9821cf6..95947f29f 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1FrameDecoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1FrameDecoder.cs @@ -111,40 +111,33 @@ internal class Av1FrameDecoder : IAv1FrameDecoder /// SVT-AV1: decode_tile. private void DecodeFrameTiles(int tileColumn) { - int tileRowCount = this.frameHeader.TilesInfo.TileRowCount; - int tileCount = tileRowCount * this.frameHeader.TilesInfo.TileColumnCount; - for (int row = 0; row < tileRowCount; row++) + ObuTileGroupHeader tileInfo = this.frameHeader.TilesInfo; + for (int tileRow = 0; tileRow < tileInfo.TileRowCount; tileRow++) { - // Tile row starts are signaled in 4x4 mode-info units. Convert to pixels and then to superblock rows - // so the frame-level superblock store and the tile-local syntax address the same region. - int superblockRowTileStart = this.frameHeader.TilesInfo.TileRowStartModeInfo[row] << Av1Constants.ModeInfoSizeLog2 >> - this.sequenceHeader.SuperblockSizeLog2; - int superblockRow = row + superblockRowTileStart; - - int modeInfoRow = superblockRow << this.sequenceHeader.SuperblockSizeLog2 >> Av1Constants.ModeInfoSizeLog2; - - // EbColorConfig* color_config = &dec_mod_ctxt->seq_header->color_config; - // svt_cfl_init(&dec_mod_ctxt->cfl_ctx, color_config); - this.DecodeTileRow(row, tileColumn, modeInfoRow, superblockRow); + // Tile boundaries are expressed in 4x4 mode-info units. Walk every superblock row between consecutive + // boundaries; using only the tile-row index would reconstruct one row and leave taller tiles incomplete. + int modeInfoRowStart = tileInfo.TileRowStartModeInfo[tileRow]; + int modeInfoRowEnd = tileInfo.TileRowStartModeInfo[tileRow + 1]; + for (int modeInfoRow = modeInfoRowStart; + modeInfoRow < modeInfoRowEnd; + modeInfoRow += this.sequenceHeader.SuperblockModeInfoSize) + { + int superblockRow = modeInfoRow / this.sequenceHeader.SuperblockModeInfoSize; + this.DecodeTileSuperblockRow(tileRow, tileColumn, modeInfoRow, superblockRow); + } } } /// - /// Reconstructs the superblocks in one tile row from left to right. + /// Reconstructs one superblock row within a tile from left to right. /// /// The zero-based tile-row index. /// The zero-based tile-column index. /// The frame-relative row in 4x4 mode-info units. /// The frame-relative superblock row. /// SVT-AV1: decode_tile_row. - private void DecodeTileRow(int tileRow, int tileColumn, int modeInfoRow, int superblockRow) + private void DecodeTileSuperblockRow(int tileRow, int tileColumn, int modeInfoRow, int superblockRow) { - int superblockModeInfoSizeLog2 = this.sequenceHeader.SuperblockSizeLog2 - Av1Constants.ModeInfoSizeLog2; - int superblockRowTileStart = this.frameHeader.TilesInfo.TileRowStartModeInfo[tileRow] << Av1Constants.ModeInfoSizeLog2 >> - this.sequenceHeader.SuperblockSizeLog2; - - int superblockRowInTile = superblockRow - superblockRowTileStart; - ObuTileGroupHeader tileInfo = this.frameHeader.TilesInfo; for (int modeInfoColumn = tileInfo.TileColumnStartModeInfo[tileColumn]; modeInfoColumn < tileInfo.TileColumnStartModeInfo[tileColumn + 1]; modeInfoColumn += this.sequenceHeader.SuperblockModeInfoSize)