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
//! **Legacy fallback** — retained for the default-feature build and
//! as a failover target when the `codec/ffmpeg` feature is enabled.
//! New dispatch prefers `super::ffmpeg::FfmpegDecoder` which wires
//! `hwaccel=cuda` onto libavcodec to drive the same NVDEC silicon
//! with a battle-tested frame pipeline (see the 2026-04-19 migration
//! in `mod.rs::create_decoder`). This custom libnvcuvid wrapper remains
//! engaged for the default-feature build (no FFmpeg dep) and as a
//! failover when the FFmpeg path errors.
//!
//! NVDEC hardware video decoder via NVIDIA CUDA Video Decoder API.
//!
//! Loads libcuda and libnvcuvid at runtime via dlopen. No compile-time
//! CUDA SDK needed — the vendored headers in `vendor/nvidia/` are the
//! authoritative reference for the struct layouts and function
//! signatures used here.
//!
//! Flow:
//! 1. cuInit + cuCtxCreate (driver init)
//! 2. cuvidCreateVideoParser (stateless parser)
//! 3. per sample: cuCtxPushCurrent + cuvidParseVideoData + cuCtxPopCurrent
//! - pfn_sequence_callback: cuvidCreateDecoder (first time)
//! - pfn_decode_picture: cuvidDecodePicture
//! - pfn_display_picture: cuvidMapVideoFrame + cuMemcpy2D then push
//! NV12 bytes into FrameCollector
//! 4. cuvidDestroyVideoParser + cuvidDestroyDecoder + cuCtxDestroy
//!
//! Library-lifetime note: CUDA + CUVID libraries are stored as fields on
//! NvdecDecoder and declared LAST so they drop after every resource that
//! references them (Rust drops struct fields in source order — Reference
//! §10.8). All FFI fn pointers captured into CallbackState are borrowed
//! from libraries whose Library handles outlive the callback dispatch.
//!
//! Thread-safety note: cuCtxCreate makes the context current only on the
//! calling thread. Every cuvid* call happens under cuCtxPushCurrent /
//! cuCtxPopCurrent so a tokio worker that migrates between threads still
//! has the right context bound before touching the decoder.
//!
//! ## Module layout
//!
//! | File | Contents |
//! |------------------|-----------------------------------------------|
//! | `mod.rs` | Public error type + module declarations + re-exports |
//! | `ffi.rs` | FFI structs, type aliases, constants, size witnesses |
//! | `state.rs` | `DecodedFrame`, `FrameCollector`, `CallbackState`, `CtxScope` |
//! | `convert.rs` | Codec-string → cuvid id, format validate, NV12/P016 deinterleave |
//! | `callbacks.rs` | `sequence_callback`, `decode_callback`, `display_callback`, `get_operating_point_callback` |
//! | `eager.rs` | `NvdecDecoder` (eager / post-decode cursor) |
//! | `push.rs` | `NvdecPushDecoder` (buffer-until-finish wrapper)|
//! | `streaming.rs` | `NvdecStreamingDecoder` (Squad-36 incremental parse) + `NvdecInitErrorDecoder` |
use c_int;
// ─── Typed errors surfaced to the caller ──────────────────────────
//
// `anyhow::Error::downcast_ref::<NvdecError>()` lets callers (and tests)
// pattern-match on specific NVDEC reject reasons without string-matching
// the display message. The decode_next / new paths wrap these in
// anyhow::Error so the Decoder trait signature stays unchanged.
//
// Reviewer note (codec-review-2 HIGH-1, HIGH-2): previously any of
// these rejects surfaced as an opaque "NVDEC produced no frames: <string>"
// anyhow and the pipeline couldn't tell "4:2:2 unsupported" from
// "driver OOM". A typed variant keeps the CPU-fallback decision in
// decode/mod.rs explainable.
// ─── Public re-exports ────────────────────────────────────────────
//
// Everything exported from `nvdec.rs` before the split is re-exported
// here so all call sites (`use crate::decode::nvdec::NvdecDecoder`,
// `use codec::decode::nvdec::validate_format`, etc.) continue to
// resolve unchanged — the directory split is transparent to consumers.
pub use ;
pub use NvdecDecoder;
pub use NvdecPushDecoder;
pub use NvdecStreamingDecoder;