///|
/// Reference and mode type of the block that owns the samples on the current
/// side of one edge (AV1 §7.14.4 inputs `RefFrames[row][col][0]` and
/// `YModes[row][col]`). Plane coordinates are converted back to the luma 4x4
/// grid the motion field lives on, and §7.14.2 then widens a chroma edge to the
/// bottom-right luma unit of its 2x2 group with `row | subY`, `col | subX`.
/// `modeType` is the normative one: any coded mode from NEARESTMV upwards except
/// the two global-motion modes, so intra blocks, GLOBALMV and never-written
/// neighbourhoods all report 0.
fn av1_loop_filter_block_state(
field : Av1MotionField?,
plane : Int,
x : Int,
y : Int,
sub_x : Int,
sub_y : Int,
) -> (Int, Int) {
match field {
None => (av1_intra_frame, 0)
Some(motion) => {
let (row, col) = av1_loop_filter_luma_mi(plane, x, y, sub_x, sub_y)
if row < 0 || row >= motion.rows || col < 0 || col >= motion.cols {
(av1_intra_frame, 0)
} else {
let unit = row * motion.cols + col
let mode = motion.y_modes[unit]
let mode_type = if mode >= av1_mode_nearest_mv &&
mode != av1_mode_global_mv &&
mode != av1_mode_global_global_mv {
1
} else {
0
}
(motion.refs[unit * 2], mode_type)
}
}
}
}
///|
/// AV1 §7.14.2: a skipped inter prediction only filters its coding-block
/// boundaries, even when maximum TX dimensions subdivide that prediction.
/// The current (right/bottom) block alone determines skip and block extent.
fn av1_loop_filter_skip_internal(
field : Av1MotionField?,
plane : Int,
direction : Int,
x : Int,
y : Int,
sub_x : Int,
sub_y : Int,
) -> Bool {
match field {
None => false
Some(motion) => {
let (row, col) = av1_loop_filter_luma_mi(plane, x, y, sub_x, sub_y)
if row >= motion.rows || col >= motion.cols {
return false
}
let unit = row * motion.cols + col
if !motion.is_inter[unit] || motion.skips[unit] == 0 {
return false
}
let (width, height) = av1_plane_residual_size(
motion.width4[unit] * 4,
motion.height4[unit] * 4,
plane,
sub_x,
sub_y,
)
if direction == 0 {
x % width != 0
} else {
y % height != 0
}
}
}
}
///|
/// Filter one four-sample edge segment. The scalar kernel receives only the
/// selected filter's footprint: a four-tap edge must not inspect p2/q2.
fn av1_loop_filter_frame_segment(
pixels : Array[Int],
stride : Int,
x : Int,
y : Int,
direction : Int,
filter_width : Int,
level : Int,
sharpness : Int,
bit_depth : Int,
) -> Bool {
let radius = if filter_width == 4 {
2
} else if filter_width == 6 {
3
} else if filter_width == 8 {
4
} else {
7
}
let normal_step = if direction == 0 { 1 } else { stride }
let along_step = if direction == 0 { stride } else { 1 }
for lane in 0..<4 {
let origin = y * stride + x + lane * along_step
let samples = Array::make(14, 0)
for distance in (0 - radius)..= pixels.length() {
return false
}
samples[7 + distance] = pixels[index]
}
let output = match
av1_loop_filter_edge(samples, filter_width, level, sharpness, bit_depth) {
Some(value) => value
None => return false
}
for distance in (0 - radius).. Bool {
if !av1_loop_filter_config_valid(config) ||
width <= 0 ||
height <= 0 ||
coded_width <= 0 ||
coded_height <= 0 ||
coded_width > MAX_IMAGE_PIXELS / coded_height ||
width > coded_width ||
height > coded_height ||
coded_width % 8 != 0 ||
coded_height % 8 != 0 ||
coded_width - width >= 8 ||
coded_height - height >= 8 ||
(bit_depth != 8 && bit_depth != 10 && bit_depth != 12) ||
(planes.length() != 1 && planes.length() != 3) ||
tx_sizes.length() != planes.length() ||
sub_x < 0 ||
sub_x > 1 ||
sub_y < 0 ||
sub_y > 1 {
return false
}
match block_map {
Some(map) =>
if !av1_loop_filter_block_map_valid(
map,
coded_width / 4,
coded_height / 4,
) {
return false
}
None => ()
}
for plane in 0..> 8
let maximum = if plane == 0 { 64 } else { 32 }
if !av1_tx_block_geometry_valid(tx_width, tx_height) ||
tx_width > maximum ||
tx_height > maximum {
return false
}
}
}
for plane in 0.. if value > 0 { inert = false }
None => return false
}
}
}
if inert {
continue
}
let normal_extent = if direction == 0 {
visible_width
} else {
visible_height
}
let along_extent = if direction == 0 {
visible_height
} else {
visible_width
}
let mut along = 0
while along < along_extent {
let mut normal = 4
while normal < normal_extent {
let x = if direction == 0 { normal } else { along }
let y = if direction == 0 { along } else { normal }
let index = y / 4 * cols + x / 4
let current = map[index]
let dimension = if direction == 0 {
current & 255
} else {
current >> 8
}
if (normal & (dimension - 1)) == 0 &&
!av1_loop_filter_skip_internal(
field, plane, direction, x, y, sub_x, sub_y,
) {
let mut edge_level = match
av1_loop_filter_block_level(
config, field, block_map, plane, direction, x, y, sub_x, sub_y,
) {
Some(value) => value
None => return false
}
// AV1 filterLevel uses the previous side when this side is zero.
// Segment and SB boundaries may assign different deltas to them.
if edge_level == 0 {
edge_level = match
av1_loop_filter_block_level(
config,
field,
block_map,
plane,
direction,
x - (if direction == 0 { 1 } else { 0 }),
y - (if direction == 1 { 1 } else { 0 }),
sub_x,
sub_y,
) {
Some(value) => value
None => return false
}
}
let previous = map[index - (if direction == 0 { 1 } else { cols })]
let previous_dimension = if direction == 0 {
previous & 255
} else {
previous >> 8
}
let minimum = if dimension < previous_dimension {
dimension
} else {
previous_dimension
}
let filter_width = if minimum == 4 {
4
} else if plane != 0 {
6
} else if minimum == 8 {
8
} else {
14
}
if edge_level > 0 &&
!av1_loop_filter_frame_segment(
planes[plane],
stride,
x,
y,
direction,
filter_width,
edge_level,
config.sharpness,
bit_depth,
) {
return false
}
}
normal = normal + 4
}
along = along + 4
}
}
}
true
}