I receive a raw video frame buffer from AviSynth+ (which is 64-byte-aligned; but this thread isn't about alignment safety). The helper function is meant to simplify getting slices out of the raw buffer. A slice either covers the whole buffer or a single row.
I started with const-generics, which doesn't allow &'static str
, and extended the signature with more fixed-at-call-site parameters. The state is currently formally inconsistent. I'd like to use &'static str
and get rid of const-generics:
fn mut_slice_from_surface_etc<'a, B: Broker, I: MemItemType, const PLANE: char>(
surface: &Surface<B>,
row_index: Option<u32>,
must_check_bounds: bool,
) -> Option<&'a mut [I]> {
#![inline]
//! Returns `None` only if `row_index` is `Some(_)` and out of bounds.
let (mut ptr, pitch, mem_items_per_row, height) = match PLANE {
'i' /* interleaved */ | 'r' | 'y' => (
surface.i_r_or_y_plane_ptr,
surface.i_r_or_y_plane_pitch,
surface.i_r_or_y_plane_mem_items_per_row,
surface.i_r_or_y_plane_height,
),
'g' | 'u' => (
surface.g_or_u_plane_ptr,
surface.g_or_u_plane_pitch,
surface.g_or_u_plane_mem_items_per_row,
surface.g_or_u_plane_height,
),
'b' | 'v' => (
surface.b_or_v_plane_ptr,
surface.b_or_v_plane_pitch,
surface.b_or_v_plane_mem_items_per_row,
surface.b_or_v_plane_height,
),
'a' => (
surface.a_plane_ptr,
surface.a_plane_pitch,
surface.a_plane_mem_items_per_row,
surface.a_plane_height,
),
_ => unreachable!(),
};
let len = if let Some(row_index) = row_index {
// Bounds check.
if must_check_bounds && row_index >= height {
return None;
}
// Index.
ptr = unsafe { ptr.offset(pitch as isize * row_index as isize) };
mem_items_per_row as usize
} else {
// Whole plane. (It isn't expected that the same plane slice is requested repeatedly. So, this doesn't need to be optimized.)
pitch as usize * height as usize / surface.bytes_per_mem_item as usize
};
Some(unsafe { slice::from_raw_parts_mut(ptr.cast::<I>(), len) })
}
Getting a row slice for an interleaved format like RGBA where all components of a pixel are stored in one location (for which I have a struct
), with the pixels one after the other:
fn row_pixels_mut(&mut self, index: u32) -> Option<&mut [P]> {
mut_slice_from_surface_etc::<_, _, 'i'>(self, Some(index), true)
}
Getting whole buffer of same frame format:
fn pixels_mut(&mut self) -> &'a mut [P] {
mut_slice_from_surface_etc::<_, _, 'i'>(self, None, false).unwrap()
}
There are the similar functions row_components_mut()
and components_mut()
for planar frame formats where the pixel components are stored at separate memory locations (e.g., just red at one location). References to either the whole buffer or a single row are created like this:
impl<C: ComponentType> ComponentsMut<'_, C> for RgbComponentsMut<'_, C> {
fn from_indexed_surface<B: Broker>(
surface: &Surface<B>,
row_index: Option<u32>,
_chroma_row_index: Option<u32>,
) -> Option<Self> {
#![inline]
Some(Self {
r: mut_slice_from_surface_etc::<_, _, 'r'>(surface, row_index, true)?,
g: mut_slice_from_surface_etc::<_, _, 'g'>(surface, row_index, false).unwrap(),
b: mut_slice_from_surface_etc::<_, _, 'b'>(surface, row_index, false).unwrap(),
sig_bits: surface.sig_bits_per_component,
})
}
}