1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#[cfg(test)]
mod tests;
use crate::util::Pixel;
use semisafe::slice::get as semisafe_get;
use semisafe::slice::get_mut as semisafe_get_mut;
use std::num::NonZeroUsize;
/// Pads a reference frame by extending edge pixels to fill the padding areas.
///
/// This function takes a frame and extends its borders by replicating edge pixels
/// to create padding around the original image. This is commonly used in video
/// processing for motion estimation and filtering operations where algorithms
/// need to access pixels beyond the frame boundaries.
///
/// The padding is applied in all directions:
/// - Corners are filled with the nearest corner pixel value
/// - Top/bottom edges are filled by extending the first/last row
/// - Left/right edges are filled by extending the first/last column
///
/// # Parameters
/// - `offset`: Starting byte offset in the destination buffer where the padded frame begins
/// - `ref_pitch`: Number of pixels per row in the destination buffer (including padding)
/// - `hpad`: Horizontal padding amount (pixels to add on left and right sides)
/// - `vpad`: Vertical padding amount (pixels to add on top and bottom)
/// - `width`: Width of the original frame in pixels (excluding padding)
/// - `height`: Height of the original frame in pixels (excluding padding)
/// - `dest`: Destination buffer containing the frame data to be padded
#[inline]
pub fn pad_reference_frame<T: Pixel>(
offset: usize,
ref_pitch: NonZeroUsize,
hpad: usize,
vpad: usize,
width: NonZeroUsize,
height: NonZeroUsize,
dest: &mut [T],
) {
let pfoff = offset + vpad * ref_pitch.get() + hpad;
let max_offset = offset + hpad + width.get() + (vpad + height.get()) * ref_pitch.get();
debug_assert!(dest.len() >= max_offset + ref_pitch.get() * (vpad - 1) + hpad);
// SAFETY: bounds are checked above
unsafe {
// Up-Left
pad_corner(
offset,
*semisafe_get(dest, pfoff),
hpad,
vpad,
ref_pitch,
dest,
);
// Up-Right
pad_corner(
offset + hpad + width.get(),
*semisafe_get(dest, pfoff + width.get() - 1),
hpad,
vpad,
ref_pitch,
dest,
);
// Down-Left
pad_corner(
offset + (vpad + height.get()) * ref_pitch.get(),
*semisafe_get(dest, pfoff + (height.get() - 1) * ref_pitch.get()),
hpad,
vpad,
ref_pitch,
dest,
);
// Down-Right
pad_corner(
offset + hpad + width.get() + (vpad + height.get()) * ref_pitch.get(),
*semisafe_get(
dest,
pfoff + (height.get() - 1) * ref_pitch.get() + width.get() - 1,
),
hpad,
vpad,
ref_pitch,
dest,
);
// Up
for i in 0..width.get() {
let value = *semisafe_get(dest, pfoff + i);
let mut poff = offset + hpad + i;
for _j in 0..vpad {
*semisafe_get_mut(dest, poff) = value;
poff += ref_pitch.get();
}
}
// Left
for i in 0..height.get() {
let value = *semisafe_get(dest, pfoff + i * ref_pitch.get());
let poff = offset + (vpad + i) * ref_pitch.get();
semisafe_get_mut(semisafe_get_mut(dest, poff..), ..hpad).fill(value);
}
// Right
for i in 0..height.get() {
let value = *semisafe_get(dest, pfoff + i * ref_pitch.get() + width.get() - 1);
let poff = offset + (vpad + i) * ref_pitch.get() + width.get() + hpad;
semisafe_get_mut(semisafe_get_mut(dest, poff..), ..hpad).fill(value);
}
// Down
for i in 0..width.get() {
let value = *semisafe_get(dest, pfoff + i + (height.get() - 1) * ref_pitch.get());
let mut poff = offset + hpad + i + (height.get() + vpad) * ref_pitch.get();
for _j in 0..vpad {
*semisafe_get_mut(dest, poff) = value;
poff += ref_pitch.get();
}
}
}
}
/// # Safety
///
/// The caller must ensure `dest.len() >= offset + ref_pitch.get() * (vpad - 1) + hpad`.
/// Do not make this a public function.
unsafe fn pad_corner<T: Pixel>(
mut offset: usize,
val: T,
hpad: usize,
vpad: usize,
ref_pitch: NonZeroUsize,
dest: &mut [T],
) {
for _i in 0..vpad {
semisafe_get_mut(semisafe_get_mut(dest, offset..), ..hpad).fill(val);
offset += ref_pitch.get();
}
}