mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-10-28 08:20:49 +08:00
fix(video): 统一关键帧参数集处理并缓存启动帧
在共享管线中将长度前缀 H264 转为 Annex-B,要求编码器标记与 IDR/IRAP 内容一致,并补齐参数集后才标记可独立解码的关键帧。 向新订阅者提供缓存启动帧,启动管线时清理缓存,并移除 RustDesk 会话内重复的 SPS/PPS 处理。补充格式归一化、关键帧判定和订阅测试。
This commit is contained in:
@@ -252,13 +252,37 @@ pub fn avcc_to_annex_b(data: &[u8]) -> Option<Vec<u8>> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn normalize_for_webrtc(data: &[u8]) -> Vec<u8> {
|
||||
if is_annex_b(data) {
|
||||
return strip_aud_nal_units(data);
|
||||
/// Normalize a length-prefixed H.264 access unit to Annex-B when necessary.
|
||||
///
|
||||
/// FFmpeg normally exposes elementary H.264 from hardware encoders as
|
||||
/// Annex-B, but some V4L2 M2M drivers return AVCC-style packets. Consumers
|
||||
/// such as RustDesk do not receive codec extradata from our protocol adapter,
|
||||
/// so passing those packets through unchanged leaves the decoder unable to
|
||||
/// find NAL unit boundaries.
|
||||
pub fn normalize_annex_b(data: bytes::Bytes) -> bytes::Bytes {
|
||||
// A four-byte start code is unambiguous for real encoder output. A
|
||||
// three-byte prefix is not: an AVCC NAL of 256..511 bytes also begins
|
||||
// with 00 00 01. Validate AVCC before accepting that shorter prefix.
|
||||
if data.starts_with(&[0, 0, 0, 1]) {
|
||||
return data;
|
||||
}
|
||||
|
||||
if let Some(annex_b) = avcc_to_annex_b(data) {
|
||||
return strip_aud_nal_units(&annex_b);
|
||||
if let Some(annex_b) = avcc_to_annex_b(data.as_ref()) {
|
||||
return bytes::Bytes::from(annex_b);
|
||||
}
|
||||
|
||||
data
|
||||
}
|
||||
|
||||
pub fn normalize_for_webrtc(data: &[u8]) -> Vec<u8> {
|
||||
if !data.starts_with(&[0, 0, 0, 1]) {
|
||||
if let Some(annex_b) = avcc_to_annex_b(data) {
|
||||
return strip_aud_nal_units(&annex_b);
|
||||
}
|
||||
}
|
||||
|
||||
if is_annex_b(data) {
|
||||
return strip_aud_nal_units(data);
|
||||
}
|
||||
|
||||
data.to_vec()
|
||||
@@ -296,4 +320,36 @@ mod tests {
|
||||
Some("42402a".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converts_avcc_access_unit_to_annex_b() {
|
||||
let avcc = [
|
||||
0, 0, 0, 4, 0x67, 0x42, 0x40, 0x1f, // SPS
|
||||
0, 0, 0, 2, 0x68, 0xce, // PPS
|
||||
0, 0, 0, 3, 0x65, 0x88, 0x84, // IDR
|
||||
];
|
||||
|
||||
let annex_b = normalize_annex_b(bytes::Bytes::copy_from_slice(&avcc));
|
||||
assert!(is_annex_b(&annex_b));
|
||||
assert!(has_sps_pps(&annex_b));
|
||||
assert!(is_keyframe(&annex_b));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leaves_annex_b_packet_unchanged() {
|
||||
let annex_b = bytes::Bytes::from_static(&[0, 0, 0, 1, 0x65, 0x88, 0x84]);
|
||||
let normalized = normalize_annex_b(annex_b.clone());
|
||||
assert_eq!(normalized, annex_b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recognizes_avcc_length_that_looks_like_three_byte_start_code() {
|
||||
let mut avcc = vec![0, 0, 1, 0];
|
||||
avcc.push(0x65);
|
||||
avcc.resize(4 + 256, 0x88);
|
||||
|
||||
let annex_b = normalize_annex_b(bytes::Bytes::from(avcc));
|
||||
assert_eq!(&annex_b[..5], &[0, 0, 0, 1, 0x65]);
|
||||
assert!(is_keyframe(&annex_b));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user