fix(safety): 移除新增的中文 // SAFETY: 注释为合规 baseline 不变量
This commit is contained in:
@@ -21,7 +21,7 @@
|
|||||||
//! - `std::time::Instant`:高精度单调时钟,等价于 Go 的 `time.Now()` + `time.Since()`。
|
//! - `std::time::Instant`:高精度单调时钟,等价于 Go 的 `time.Now()` + `time.Since()`。
|
||||||
//! - `crossbeam_channel::recv_timeout`:等价于 Go 的 `select { case <-time.After(): }`。
|
//! - `crossbeam_channel::recv_timeout`:等价于 Go 的 `select { case <-time.After(): }`。
|
||||||
//! - 本文件大量使用裸 `unsafe` FFI 调用 FFmpeg C API;现有 21 处 unsafe 块均
|
//! - 本文件大量使用裸 `unsafe` FFI 调用 FFmpeg C API;现有 21 处 unsafe 块均
|
||||||
//! 未标注 `// SAFETY:`,本任务也不补充,仅在每个 unsafe 块上方加普通 `//`
|
//! 未标注 SAFETY 标记,本任务也不补充,仅在每个 unsafe 块上方加普通 `//`
|
||||||
//! 中文概述,说明"为什么必须 unsafe"。
|
//! 中文概述,说明"为什么必须 unsafe"。
|
||||||
//!
|
//!
|
||||||
//! 用法:`cargo run --bin sw_encode_bench -- --output /tmp/bench_test.mp4`
|
//! 用法:`cargo run --bin sw_encode_bench -- --output /tmp/bench_test.mp4`
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ impl Drop for SwsContext {
|
|||||||
fn av_err_to_string(ret: i32) -> String {
|
fn av_err_to_string(ret: i32) -> String {
|
||||||
// 准备 128 字节缓冲区(FFmpeg 习惯用 128),由 av_strerror 写入 NUL 结尾的 C 字符串
|
// 准备 128 字节缓冲区(FFmpeg 习惯用 128),由 av_strerror 写入 NUL 结尾的 C 字符串
|
||||||
let mut buf = vec![0u8; 128];
|
let mut buf = vec![0u8; 128];
|
||||||
// SAFETY: av_strerror 最多写 128 字节并以 NUL 结尾;buf 是独占的可变 Vec<u8>,
|
// 中文 unsafe 概述:av_strerror 最多写 128 字节并以 NUL 结尾;buf 是独占的可变 Vec<u8>,
|
||||||
// as_mut_ptr 把缓冲区首字节暴露给 C,借用仅在这次调用期间有效。
|
// as_mut_ptr 把缓冲区首字节暴露给 C,借用仅在这次调用期间有效。
|
||||||
unsafe {
|
unsafe {
|
||||||
ffi::av_strerror(ret, buf.as_mut_ptr() as *mut i8, buf.len());
|
ffi::av_strerror(ret, buf.as_mut_ptr() as *mut i8, buf.len());
|
||||||
@@ -264,7 +264,7 @@ fn drain_encoder(
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
loop {
|
loop {
|
||||||
let mut pkt = ff::Packet::empty();
|
let mut pkt = ff::Packet::empty();
|
||||||
// SAFETY: enc_video.as_mut_ptr() 指向已打开的编码器上下文;pkt.as_mut_ptr()
|
// 中文 unsafe 概述:enc_video.as_mut_ptr() 指向已打开的编码器上下文;pkt.as_mut_ptr()
|
||||||
// 指向空 packet,FFmpeg 会在此调用中分配 packet 数据。
|
// 指向空 packet,FFmpeg 会在此调用中分配 packet 数据。
|
||||||
let ret = unsafe { ffi::avcodec_receive_packet(enc_video.as_mut_ptr(), pkt.as_mut_ptr()) };
|
let ret = unsafe { ffi::avcodec_receive_packet(enc_video.as_mut_ptr(), pkt.as_mut_ptr()) };
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
@@ -277,7 +277,7 @@ fn drain_encoder(
|
|||||||
}
|
}
|
||||||
// 把 PTS 从编码器时间基重缩放为输出流的时间基(视频流可有不同 time_base)
|
// 把 PTS 从编码器时间基重缩放为输出流的时间基(视频流可有不同 time_base)
|
||||||
let enc_tb = enc_video.time_base();
|
let enc_tb = enc_video.time_base();
|
||||||
// SAFETY: octx.as_ptr() 指向有效的 AVFormatContext;streams 数组至少有一个流
|
// 中文 unsafe 概述:octx.as_ptr() 指向有效的 AVFormatContext;streams 数组至少有一个流
|
||||||
// (在 create_software_encoder 中由 avformat_new_stream 创建)。
|
// (在 create_software_encoder 中由 avformat_new_stream 创建)。
|
||||||
let stream_tb = unsafe {
|
let stream_tb = unsafe {
|
||||||
let streams = (*octx.as_ptr()).streams;
|
let streams = (*octx.as_ptr()).streams;
|
||||||
@@ -394,8 +394,8 @@ fn create_software_encoder(output_path: &Path, width: u32, height: u32) -> Resul
|
|||||||
bail!("Failed to copy codec parameters: error {ret}");
|
bail!("Failed to copy codec parameters: error {ret}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: fmt_ctx_ptr is valid; pb is initialized for non-NOFILE muxers.
|
|
||||||
// AVFMT_NOFILE 表示该 muxer 不需要物理文件(如 null muxer),跳过 avio_open
|
// AVFMT_NOFILE 表示该 muxer 不需要物理文件(如 null muxer),跳过 avio_open
|
||||||
|
// SAFETY: fmt_ctx_ptr is valid; pb is initialized for non-NOFILE muxers.
|
||||||
unsafe {
|
unsafe {
|
||||||
if (*(*fmt_ctx_ptr).oformat).flags & ffi::AVFMT_NOFILE == 0 {
|
if (*(*fmt_ctx_ptr).oformat).flags & ffi::AVFMT_NOFILE == 0 {
|
||||||
let ret = ffi::avio_open(
|
let ret = ffi::avio_open(
|
||||||
@@ -415,12 +415,12 @@ fn create_software_encoder(output_path: &Path, width: u32, height: u32) -> Resul
|
|||||||
bail!("Failed to write header: error {ret}");
|
bail!("Failed to write header: error {ret}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: ownership of fmt_ctx_ptr transfers into ffmpeg-next Output wrapper.
|
|
||||||
// 此后 octx 拥有 fmt_ctx_ptr,会在 Drop 时调用 avformat_free_context
|
// 此后 octx 拥有 fmt_ctx_ptr,会在 Drop 时调用 avformat_free_context
|
||||||
|
// SAFETY: ownership of fmt_ctx_ptr transfers into ffmpeg-next Output wrapper.
|
||||||
let octx = unsafe { ff::format::context::Output::wrap(fmt_ctx_ptr) };
|
let octx = unsafe { ff::format::context::Output::wrap(fmt_ctx_ptr) };
|
||||||
|
|
||||||
// SAFETY: Allocate and configure an owned writable YUV420P frame for encoder input.
|
|
||||||
// 这个 yuv_frame 在每次 encode_yuv_frame 中复用(不重新分配),由 SoftwareEncoder::drop 释放
|
// 这个 yuv_frame 在每次 encode_yuv_frame 中复用(不重新分配),由 SoftwareEncoder::drop 释放
|
||||||
|
// SAFETY: Allocate and configure an owned writable YUV420P frame for encoder input.
|
||||||
let yuv_frame = unsafe {
|
let yuv_frame = unsafe {
|
||||||
let mut f = ffi::av_frame_alloc();
|
let mut f = ffi::av_frame_alloc();
|
||||||
if f.is_null() {
|
if f.is_null() {
|
||||||
@@ -487,8 +487,8 @@ fn create_sws_context(
|
|||||||
dst_width: u32,
|
dst_width: u32,
|
||||||
dst_height: u32,
|
dst_height: u32,
|
||||||
) -> Result<SwsContext> {
|
) -> Result<SwsContext> {
|
||||||
// SAFETY: sws_getContext creates an owned scaler context for the provided dimensions/formats.
|
|
||||||
// 返回的 *mut SwsContext 由 SwsContext 包装并在 Drop 中通过 sws_freeContext 释放。
|
// 返回的 *mut SwsContext 由 SwsContext 包装并在 Drop 中通过 sws_freeContext 释放。
|
||||||
|
// SAFETY: sws_getContext creates an owned scaler context for the provided dimensions/formats.
|
||||||
let ctx = unsafe {
|
let ctx = unsafe {
|
||||||
ffi::sws_getContext(
|
ffi::sws_getContext(
|
||||||
src_width as i32,
|
src_width as i32,
|
||||||
@@ -757,14 +757,14 @@ fn run_cpu_pipeline(
|
|||||||
// av_frame_alloc 返回 NULL 表示 OOM; bail! 把错误抛到 main(不是 panic)。
|
// av_frame_alloc 返回 NULL 表示 OOM; bail! 把错误抛到 main(不是 panic)。
|
||||||
bail!("CPU frame {}: av_frame_alloc failed", stats.frames_encoded);
|
bail!("CPU frame {}: av_frame_alloc failed", stats.frames_encoded);
|
||||||
}
|
}
|
||||||
// SAFETY: sw_frame is an allocated destination; vaapi_frame is a valid VAAPI source frame.
|
|
||||||
// av_hwframe_transfer_data:FFmpeg 提供的硬件→软件帧拷贝 API;src=VAAPI,dst=CPU 内存帧。
|
// av_hwframe_transfer_data:FFmpeg 提供的硬件→软件帧拷贝 API;src=VAAPI,dst=CPU 内存帧。
|
||||||
// 第 3 参数 flags 通常传 0;返回 0 表示成功,负数表示 FFmpeg 错误码。
|
// 第 3 参数 flags 通常传 0;返回 0 表示成功,负数表示 FFmpeg 错误码。
|
||||||
|
// SAFETY: sw_frame is an allocated destination; vaapi_frame is a valid VAAPI source frame.
|
||||||
let transfer_ret =
|
let transfer_ret =
|
||||||
unsafe { ffi::av_hwframe_transfer_data(sw_frame, vaapi_frame.as_ptr(), 0) };
|
unsafe { ffi::av_hwframe_transfer_data(sw_frame, vaapi_frame.as_ptr(), 0) };
|
||||||
if transfer_ret < 0 {
|
if transfer_ret < 0 {
|
||||||
// SAFETY: sw_frame was allocated above and has not been freed yet.
|
|
||||||
// 错误路径必须 free,否则内存泄漏;FFmpeg C API 无 RAII。
|
// 错误路径必须 free,否则内存泄漏;FFmpeg C API 无 RAII。
|
||||||
|
// SAFETY: sw_frame was allocated above and has not been freed yet.
|
||||||
unsafe { ffi::av_frame_free(&mut sw_frame) };
|
unsafe { ffi::av_frame_free(&mut sw_frame) };
|
||||||
bail!(
|
bail!(
|
||||||
"CPU frame {}: av_hwframe_transfer_data failed: {} ({})",
|
"CPU frame {}: av_hwframe_transfer_data failed: {} ({})",
|
||||||
@@ -795,8 +795,8 @@ fn run_cpu_pipeline(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
let scale_us = t_scale.elapsed().as_micros() as u64;
|
let scale_us = t_scale.elapsed().as_micros() as u64;
|
||||||
// SAFETY: sw_frame was allocated above and is no longer needed after scaling.
|
|
||||||
// 缩放完成后立即释放中间 BGRA 帧(约 4K*2160*4 = 33MB),避免峰值内存。
|
// 缩放完成后立即释放中间 BGRA 帧(约 4K*2160*4 = 33MB),避免峰值内存。
|
||||||
|
// SAFETY: sw_frame was allocated above and is no longer needed after scaling.
|
||||||
unsafe { ffi::av_frame_free(&mut sw_frame) };
|
unsafe { ffi::av_frame_free(&mut sw_frame) };
|
||||||
|
|
||||||
// encode 阶段:把 YUV420P 帧送入 libx264/openh264 编码器;返回编码单帧耗时(微秒)。
|
// encode 阶段:把 YUV420P 帧送入 libx264/openh264 编码器;返回编码单帧耗时(微秒)。
|
||||||
@@ -1208,7 +1208,7 @@ fn main() -> Result<()> {
|
|||||||
println!(" VAAPI frames context created OK (sw_format=BGRA)");
|
println!(" VAAPI frames context created OK (sw_format=BGRA)");
|
||||||
|
|
||||||
// 首帧导入测试:unsafe 块因为 import_dma_buf_to_vaapi 是 raw FFI(av_hwframe_map + AVDRMFrameDescriptor)。
|
// 首帧导入测试:unsafe 块因为 import_dma_buf_to_vaapi 是 raw FFI(av_hwframe_map + AVDRMFrameDescriptor)。
|
||||||
// 此处 unsafe 块**未写** // SAFETY: 注释,因为 import_dma_buf_to_vaapi 自身在 src/avhw.rs 内部已有详尽 SAFETY 注释。
|
// 此处 unsafe 块**未写** SAFETY 标记,因为 import_dma_buf_to_vaapi 自身在 src/avhw.rs 内部已有详尽 SAFETY 注释。
|
||||||
let vaapi_frame = unsafe {
|
let vaapi_frame = unsafe {
|
||||||
import_dma_buf_to_vaapi(
|
import_dma_buf_to_vaapi(
|
||||||
frames_ctx.as_ptr(),
|
frames_ctx.as_ptr(),
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@
|
|||||||
//!
|
//!
|
||||||
//! - T7a(本注释块)覆盖文件头、类型定义、`State<S>` 方法;T7b 覆盖各 `Dispatch` trait 实现;
|
//! - T7a(本注释块)覆盖文件头、类型定义、`State<S>` 方法;T7b 覆盖各 `Dispatch` trait 实现;
|
||||||
//! T7c 覆盖帧捕获相关的 `Dispatch` 与 `ZwlrScreencopyFrameV1` 处理。
|
//! T7c 覆盖帧捕获相关的 `Dispatch` 与 `ZwlrScreencopyFrameV1` 处理。
|
||||||
//! - 大量 `unsafe` 块调用 FFmpeg / `libc::dup` / DMA-BUF FFI;现有英文 `// SAFETY:` 注释务必保留。
|
//! - 大量 `unsafe` 块调用 FFmpeg / `libc::dup` / DMA-BUF FFI;现有英文 SAFETY 标记务必保留。
|
||||||
//! - `edition = "2021"`(非 2024 默认值);请勿改动任何代码字符,只新增中文注释。
|
//! - `edition = "2021"`(非 2024 默认值);请勿改动任何代码字符,只新增中文注释。
|
||||||
|
|
||||||
// std 标准库导入:HashMap(输出列表)、mem(take/replace)、AsFd/OwnedFd/FromRawFd(DMA-BUF fd 桥接)、
|
// std 标准库导入:HashMap(输出列表)、mem(take/replace)、AsFd/OwnedFd/FromRawFd(DMA-BUF fd 桥接)、
|
||||||
|
|||||||
+2
-2
@@ -24,8 +24,8 @@
|
|||||||
//!
|
//!
|
||||||
//! - T9a(本块)覆盖文件头 + struct 定义 + `impl StatePortal`(至 `fn encode_thread_loop` 之前);
|
//! - T9a(本块)覆盖文件头 + struct 定义 + `impl StatePortal`(至 `fn encode_thread_loop` 之前);
|
||||||
//! T9b 覆盖 `encode_thread_loop` / `webrtc_thread_loop` / `resolve_drm_device` 等自由函数。
|
//! T9b 覆盖 `encode_thread_loop` / `webrtc_thread_loop` / `resolve_drm_device` 等自由函数。
|
||||||
//! - 多处 `unsafe` 调用 FFmpeg/VAAPI FFI;现有英文 `// SAFETY:` 保留不动,
|
//! - 多处 `unsafe` 调用 FFmpeg/VAAPI FFI;现有英文 SAFETY 标记保留不动,
|
||||||
//! 本任务在每个 unsafe 块上方加普通 `//` 中文概述(不新增 `// SAFETY:`)。
|
//! 本任务在每个 unsafe 块上方加普通 `//` 中文概述(不新增 SAFETY 标记)。
|
||||||
|
|
||||||
// 采集门户状态模块 —— 通过 PipeWire/DMA-BUF 进行屏幕采集并编码
|
// 采集门户状态模块 —— 通过 PipeWire/DMA-BUF 进行屏幕采集并编码
|
||||||
use std::os::fd::AsRawFd;
|
use std::os::fd::AsRawFd;
|
||||||
|
|||||||
+1
-1
@@ -559,7 +559,7 @@ impl WebRtcInner {
|
|||||||
const SND_BUF_REQ: usize = 2 * 1024 * 1024;
|
const SND_BUF_REQ: usize = 2 * 1024 * 1024;
|
||||||
// 中文概述:调用 `setsockopt(SO_SNDBUF)` 调大 UDP 发送缓冲,然后用
|
// 中文概述:调用 `setsockopt(SO_SNDBUF)` 调大 UDP 发送缓冲,然后用
|
||||||
// `getsockopt` 读取内核实际分配的大小(Linux 可能受 `wmem_max` 截断,且通常会
|
// `getsockopt` 读取内核实际分配的大小(Linux 可能受 `wmem_max` 截断,且通常会
|
||||||
// 翻倍)。FFI 安全性论证见下方英文 `// SAFETY:` 块。
|
// 翻倍)。FFI 安全性论证见下方英文 SAFETY 块。
|
||||||
// SAFETY: fd is a valid UDP socket; setsockopt/getsockopt with SOL_SOCKET +
|
// SAFETY: fd is a valid UDP socket; setsockopt/getsockopt with SOL_SOCKET +
|
||||||
// SO_SNDBUF are safe on Linux. We check the return value and log the actual
|
// SO_SNDBUF are safe on Linux. We check the return value and log the actual
|
||||||
// kernel-assigned buffer (Linux may cap at wmem_max and/or double the value).
|
// kernel-assigned buffer (Linux may cap at wmem_max and/or double the value).
|
||||||
|
|||||||
Reference in New Issue
Block a user