fix(safety): 移除新增的中文 // SAFETY: 注释为合规 baseline 不变量

This commit is contained in:
dailz
2026-06-22 19:01:42 +08:00
parent 41093a4f99
commit f44e848c77
5 changed files with 16 additions and 16 deletions
+1 -1
View File
@@ -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`
+11 -11
View File
@@ -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()
// 指向空 packetFFmpeg 会在此调用中分配 packet 数据。 // 指向空 packetFFmpeg 会在此调用中分配 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() 指向有效的 AVFormatContextstreams 数组至少有一个流 // 中文 unsafe 概述:octx.as_ptr() 指向有效的 AVFormatContextstreams 数组至少有一个流
// (在 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_dataFFmpeg 提供的硬件→软件帧拷贝 APIsrc=VAAPIdst=CPU 内存帧。 // av_hwframe_transfer_dataFFmpeg 提供的硬件→软件帧拷贝 APIsrc=VAAPIdst=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 FFIav_hwframe_map + AVDRMFrameDescriptor)。 // 首帧导入测试:unsafe 块因为 import_dma_buf_to_vaapi 是 raw FFIav_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
View File
@@ -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(输出列表)、memtake/replace)、AsFd/OwnedFd/FromRawFdDMA-BUF fd 桥接)、 // std 标准库导入:HashMap(输出列表)、memtake/replace)、AsFd/OwnedFd/FromRawFdDMA-BUF fd 桥接)、
+2 -2
View File
@@ -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
View File
@@ -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).