Files
wz-phone/crates/wzp-video/src/lib.rs
Siavash Sameni 5d05b021aa fix(wzp-video): gate shiguredo AV1 crates to macOS only; fix Linux relay build
- Cargo.toml: merge duplicate [target.macos.deps] sections; move
  shiguredo_dav1d/svt_av1/video_toolbox into single block
- lib.rs: dav1d + svt_av1 modules and re-exports guarded by
  cfg(target_os = "macos") instead of cfg(not(android))
- factory.rs: AV1 encoder/decoder paths split into macos (svt-av1/dav1d)
  and linux fallback (NotInitialized); update doc comments and tests
- build-linux-docker.sh: build only wzp-relay + wzp-web (drops
  wzp-client which pulled in shiguredo crates); fix Docker copy step;
  add --deploy flag + deploy_relay(); fix branch auto-detection
- build-tauri-android.sh: default to release build, arm64 only

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 06:33:35 +04:00

108 lines
3.5 KiB
Rust

//! WZP video pipeline — H.264 / H.265 framer and depacketizer.
//!
//! This crate lives alongside `wzp-codec` and handles video-specific
//! packetization (NAL fragmentation / reassembly). Platform encoders and
//! decoders land in T4.2/T4.3/T5.4.
pub mod av1_obu;
pub mod controller;
#[cfg(target_os = "macos")]
pub mod dav1d;
pub mod decoder;
pub mod depacketizer;
pub mod encoder;
pub mod encoder_mode;
pub mod factory;
pub mod framer;
pub mod mediacodec;
pub mod nack;
pub mod simulcast;
#[cfg(target_os = "macos")]
pub mod svt_av1;
pub mod videotoolbox;
pub use av1_obu::{Av1Depacketizer, Av1ObuFramer, is_keyframe_obu};
pub use controller::{VideoQualityController, VideoTarget};
#[cfg(target_os = "macos")]
pub use dav1d::Dav1dDecoder;
pub use decoder::VideoDecoder;
pub use depacketizer::H264Depacketizer;
pub use encoder::{VideoEncoder, VideoError, VideoFrame};
pub use encoder_mode::EncoderMode;
pub use factory::{create_video_decoder, create_video_encoder};
pub use framer::{FramedPacket, H264Framer};
pub use mediacodec::{
MediaCodecAv1Decoder, MediaCodecAv1Encoder, MediaCodecDecoder, MediaCodecEncoder,
MediaCodecHevcDecoder, MediaCodecHevcEncoder,
};
pub use nack::{CachedPacket, NackAction, NackReceiver, NackSender};
pub use simulcast::{LayerPacket, LayerTarget, SimulcastEncoder, SimulcastLayer};
#[cfg(target_os = "macos")]
pub use svt_av1::SvtAv1Encoder;
pub use videotoolbox::{
VideoToolboxAv1Decoder, VideoToolboxDecoder, VideoToolboxEncoder, VideoToolboxHevcDecoder,
VideoToolboxHevcEncoder,
};
#[cfg(test)]
mod tests {
use crate::{H264Depacketizer, H264Framer};
/// Build a synthetic H.264 access unit (Annex-B, 3-byte start codes):
/// - NAL 1: IDR slice (type 5) with 100-byte payload
/// - NAL 2: non-IDR slice (type 1) with 50-byte payload
fn synthetic_access_unit() -> Vec<u8> {
let mut au = Vec::new();
au.extend_from_slice(&[0x00, 0x00, 0x01, 0x65]); // IDR start code
au.extend_from_slice(&[0xCC; 100]);
au.extend_from_slice(&[0x00, 0x00, 0x01, 0x41]); // non-IDR start code
au.extend_from_slice(&[0xDD; 50]);
au
}
#[test]
fn roundtrip_single_nal() {
let au = synthetic_access_unit();
let framer = H264Framer::new(500);
let packets = framer.frame(&au);
let mut dep = H264Depacketizer::new();
let mut result = None;
for pkt in &packets {
result = dep.push(&pkt.payload, pkt.is_frame_end);
}
assert_eq!(result, Some(au));
}
#[test]
fn roundtrip_with_fu_a_fragmentation() {
let au = synthetic_access_unit();
// Max payload 30 bytes forces the 100-byte NAL into FU-A fragments.
let framer = H264Framer::new(30);
let packets = framer.frame(&au);
// The 100-byte NAL (1 header + 100 payload = 101 bytes) will be
// fragmented. 30-byte max means 28 bytes of data per fragment
// (2 bytes FU-A header). 100 payload bytes → 4 fragments.
// The 50-byte NAL (1 + 50 = 51) also fragments → 2 fragments.
// Total packets = 4 + 2 = 6.
assert_eq!(packets.len(), 6);
let mut dep = H264Depacketizer::new();
let mut result = None;
for pkt in &packets {
result = dep.push(&pkt.payload, pkt.is_frame_end);
}
assert_eq!(result, Some(au));
}
#[test]
fn roundtrip_empty_access_unit() {
let framer = H264Framer::new(100);
let packets = framer.frame(&[]);
assert!(packets.is_empty());
}
}