mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-09-12 10:34:24 +08:00
feat: 新增 Amlogic AMLENC 硬件编码支持
- 新增动态加载及 ABI 校验的 AMLENC H.264/H.265 编码器 - 注册 Amlogic 后端并扩展编码器自检 - 并行执行 MJPEG 解码与 AMLENC 编码 - 复用 NV12 缓冲区并移除冗余帧初始化 - 优化低延迟帧分发及 RTCP 关键帧恢复 - 动态调整 AMLENC 码率尚未完成,效果不佳
This commit is contained in:
@@ -1119,25 +1119,73 @@ pub fn mjpg_size(src: &[u8]) -> Result<(i32, i32)> {
|
||||
|
||||
/// Decode MJPEG directly to NV12.
|
||||
pub fn mjpg_to_nv12(src: &[u8], dst: &mut [u8], width: i32, height: i32) -> Result<()> {
|
||||
if width % 2 != 0 || height % 2 != 0 {
|
||||
return Err(YuvError::InvalidDimensions);
|
||||
}
|
||||
|
||||
let w = width as usize;
|
||||
let h = height as usize;
|
||||
if dst.len() < nv12_size(w, h) {
|
||||
let (y_size, output_size) = mjpg_nv12_plane_sizes(width, height)?;
|
||||
if dst.len() < output_size {
|
||||
return Err(YuvError::BufferTooSmall);
|
||||
}
|
||||
|
||||
let y_size = w * h;
|
||||
let (dst_y, dst_uv) = dst.split_at_mut(y_size);
|
||||
// SAFETY: the length check above guarantees writable storage for both planes.
|
||||
unsafe { mjpg_to_nv12_raw(src, dst_y.as_mut_ptr(), dst_uv.as_mut_ptr(), width, height) }
|
||||
}
|
||||
|
||||
/// Decode MJPEG directly into a reusable `Vec` without zero-filling the output first.
|
||||
///
|
||||
/// `Vec::resize` must initialize every byte before libyuv immediately overwrites the
|
||||
/// complete NV12 frame. This variant lets libyuv initialize spare capacity directly
|
||||
/// and publishes the new length only after a successful conversion.
|
||||
pub fn mjpg_to_nv12_vec(src: &[u8], dst: &mut Vec<u8>, width: i32, height: i32) -> Result<()> {
|
||||
let (y_size, output_size) = mjpg_nv12_plane_sizes(width, height)?;
|
||||
|
||||
dst.clear();
|
||||
dst.reserve(output_size);
|
||||
|
||||
// SAFETY: reserve above guarantees writable capacity for the Y and UV planes.
|
||||
// MJPGToNV12 writes the complete output on success; set_len is deliberately
|
||||
// delayed until then so callers can never observe partially initialized bytes.
|
||||
let result = unsafe {
|
||||
let dst_y = dst.as_mut_ptr();
|
||||
mjpg_to_nv12_raw(src, dst_y, dst_y.add(y_size), width, height)
|
||||
};
|
||||
result?;
|
||||
|
||||
// SAFETY: a successful MJPGToNV12 call initialized exactly output_size bytes.
|
||||
unsafe { dst.set_len(output_size) };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn mjpg_nv12_plane_sizes(width: i32, height: i32) -> Result<(usize, usize)> {
|
||||
if width % 2 != 0 || height % 2 != 0 || width <= 0 || height <= 0 {
|
||||
return Err(YuvError::InvalidDimensions);
|
||||
}
|
||||
let y_size = (width as usize)
|
||||
.checked_mul(height as usize)
|
||||
.ok_or(YuvError::InvalidDimensions)?;
|
||||
let output_size = y_size
|
||||
.checked_mul(3)
|
||||
.map(|size| size / 2)
|
||||
.ok_or(YuvError::InvalidDimensions)?;
|
||||
Ok((y_size, output_size))
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// `dst_y` and `dst_uv` must point to writable planes sized for `width` x `height` NV12.
|
||||
#[inline]
|
||||
unsafe fn mjpg_to_nv12_raw(
|
||||
src: &[u8],
|
||||
dst_y: *mut u8,
|
||||
dst_uv: *mut u8,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> Result<()> {
|
||||
call_yuv!(MJPGToNV12(
|
||||
src.as_ptr(),
|
||||
usize_to_size_t(src.len()),
|
||||
dst_y.as_mut_ptr(),
|
||||
dst_y,
|
||||
width,
|
||||
dst_uv.as_mut_ptr(),
|
||||
dst_uv,
|
||||
width,
|
||||
width,
|
||||
height,
|
||||
|
||||
Reference in New Issue
Block a user