1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//! # vacc
//!
//! One video codec library for every backend: [`VaccDecoder`] decodes and
//! [`VaccEncoder`] encodes, each accepting a config with a preferred backend
//! order (Vulkan, NVDEC/NVENC, VAAPI, software) and falling back to the next
//! backend in the list whenever the previous one is unavailable or cannot
//! handle the stream.
//!
//! ## Decoding
//!
//! The decode API is streaming-only: construct from an initial chunk of the
//! bitstream, feed the rest with [`vacc_core::decoder::Decoder::submit`],
//! and pull frames one at a time with [`vacc_core::decoder::Decoder::decode`].
//! Nothing in the public API takes or returns the whole stream, so memory
//! stays flat on long-running streams (with the exception of the Vulkan
//! backend, whose inner decoder works on the complete bitstream — see
//! [`VaccDecoder`]).
//!
//! ## Quick start
//!
//! ```no_run
//! use std::io::Read;
//! use vacc_core::decoder::Decoder;
//! use vacc::{Backend, DecoderConfig, VaccDecoder};
//!
//! // Seed the decoder with the stream head; it is consumed as the first
//! // input, and the rest of the stream follows via submit().
//! let mut file = std::fs::File::open("video.h264").unwrap();
//! let mut probe = [0u8; 64 * 1024];
//! let n = file.read(&mut probe).unwrap();
//!
//! // Default chain: vulkan -> nvdec -> vaapi -> software.
//! let mut decoder = VaccDecoder::new_auto(&probe[..n]).unwrap();
//! println!("using backend: {}", decoder.backend());
//!
//! let mut buf = vec![0u8; 1024 * 1024];
//! loop {
//! let n = file.read(&mut buf).unwrap();
//! if n == 0 {
//! break;
//! }
//! decoder.submit(&buf[..n]).unwrap();
//! while let Some(frame) = decoder.decode().unwrap() {
//! println!("frame {}: {}x{}", frame.frame_index, frame.width, frame.height);
//! }
//! }
//! for frame in decoder.flush().unwrap() {
//! println!("frame {}: {}x{}", frame.frame_index, frame.width, frame.height);
//! }
//! ```
//!
//! ## Custom fallback order
//!
//! ```no_run
//! use vacc::{Backend, DecoderConfig, VaccDecoder};
//!
//! let probe: &[u8] = b"\x00\x00\x00\x01..."; // initial bitstream chunk
//! // Prefer NVDEC, fall back to software only.
//! let config = DecoderConfig::new([Backend::Nvdec, Backend::Software]);
//! // or: DecoderConfig::only(Backend::Vaapi) / DecoderConfig::default_order()
//! let decoder = VaccDecoder::new(probe, &config).unwrap();
//! ```
//!
//! If every configured backend fails, the returned error lists each
//! per-backend failure so the caller can report *why* nothing worked.
//!
//! ## Backends and codecs
//!
//! Decode support:
//!
//! | Backend | H.264 | H.265 | VP9 | AV1 |
//! |------------|-------|-------|-----|-----|
//! | `vulkan` | yes | yes | yes | yes |
//! | `nvdec` | yes | yes | yes | yes |
//! | `vaapi` | yes | yes | yes | yes |
//! | `software` | yes | yes | - | - |
//!
//! Encode support (H.264 CQP, NV12 in / Annex B out):
//!
//! | Backend | H.264 |
//! |----------|---------|
//! | `vulkan` | planned |
//! | `nvdec` | planned |
//! | `vaapi` | yes |
//!
//! Each backend is an optional crate feature (`vulkan`, `nvdec`, `vaapi`,
//! `sw`, all on by default); a backend feature enables both its decode and
//! encode crates, so you can build a distribution without any given GPU
//! dependency.
//!
//! ## Encoding
//!
//! [`VaccEncoder`] takes an [`EncoderConfig`] (core parameters plus a
//! preferred backend order) and encodes NV12 frames one at a time:
//!
//! ```no_run
//! use std::io::Write;
//! use vacc_core::encoder::{Encoder, EncoderConfig as CoreCfg, InputFrame};
//! use vacc::{EncoderConfig, VaccEncoder};
//!
//! let params = CoreCfg { width: 320, height: 240, ..Default::default() };
//! let config = EncoderConfig::new(params); // vulkan -> nvdec -> vaapi
//! let mut enc = VaccEncoder::new(&config).unwrap();
//! println!("using backend: {}", enc.backend());
//!
//! let mut out = Vec::new();
//! for i in 0..30u32 {
//! let y = vec![i as u8; 320 * 240];
//! let uv = vec![128u8; 320 * 120];
//! let frame = InputFrame::packed(320, 240, &y, &uv);
//! let au = enc.encode(&frame, (i as i64) * 33_333_333).unwrap();
//! out.extend_from_slice(&au.data);
//! }
//! for au in enc.flush().unwrap() {
//! out.extend_from_slice(&au.data);
//! }
//! let mut f = std::fs::File::create("out.h264").unwrap();
//! f.write_all(&out).unwrap();
//! ```
//!
//! ## Image pipeline
//!
//! A [`DecoderConfig`] may additionally carry an [`ImageConfig`]: after
//! decoding, every frame is optionally down-cast (10/12 -> 8 bit), resized
//! and/or converted to packed RGB(R)(A). On NVIDIA hosts the pipeline runs
//! on the GPU through NPP; on any other host with a Vulkan compute device it
//! runs on the GPU through `vacc-vkimage`; everywhere else (and whenever the
//! GPU path fails) the SIMD software pipeline in `vacc-image` is used. The
//! result lands in the frame itself: scaled 4:2:0 output replaces
//! `pixel_data`, RGB output lands in `rgb_pixels`.
//!
//! ## GPU decode track
//!
//! [`DecoderConfig::with_gpu`] requests the zero-host-copy path: NVDEC writes
//! decoded frames straight into device buffers and the image pipeline runs on
//! the GPU through NPP, so frames come out with [`DecodedFrame::gpu`] set and
//! `pixel_data`/`rgb_pixels` empty. The device pointer is stable while the
//! frame handle is alive, which makes the buffer suitable for downstream
//! inference (e.g. TensorRT). Only the NVDEC backend supports the track;
//! unsupported combinations (e.g. 10-bit sources) transparently fall back to
//! a readback + host processing.
pub use Backend;
pub use detect_codec;
pub use ;
pub use VaccDecoder;
pub use VaccEncoder;
pub use ;
// Re-export the core API so a user only needs this crate for the common path.
pub use ;
// GPU decode track types (device-resident frames).
pub use ;
// Image-pipeline configuration types.
pub use ;