nv_media/hook.rs
1//! Post-decode hook types for platform-specific pipeline element injection.
2//!
3//! These types allow callers to inject a GStreamer element between the decoder
4//! output and the color-space converter. This is needed on platforms where the
5//! hardware decoder outputs memory types that the standard `videoconvert`
6//! cannot accept (e.g., `memory:NVMM` on NVIDIA Jetson).
7//!
8//! The hook is a callback that inspects the decoded stream characteristics
9//! and optionally returns a GStreamer element name to insert.
10//!
11//! # Interaction with `DeviceResidency::Provider`
12//!
13//! When a [`GpuPipelineProvider`](crate::GpuPipelineProvider) is active
14//! (i.e., `DeviceResidency::Provider`), the pipeline builder **skips**
15//! the post-decode hook entirely — the provider controls the full
16//! decoder → pipeline-tail path. Hooks are only evaluated for
17//! `DeviceResidency::Host` and `DeviceResidency::Cuda` paths.
18//!
19//! This means hooks can be set unconditionally (e.g., always install an
20//! NVMM bridge hook) without interfering with provider-managed feeds.
21
22use std::sync::Arc;
23
24/// Information about a decoded stream, provided to [`PostDecodeHook`] callbacks.
25///
26/// Describes the decoded media stream characteristics so platform-specific
27/// hooks can decide whether additional pipeline elements are needed.
28#[derive(Debug, Clone)]
29pub struct DecodedStreamInfo {
30 /// Media type string (e.g., `"video/x-raw"`).
31 pub media_type: String,
32 /// Optional memory type qualifier (e.g., `Some("NVMM")` for Jetson
33 /// GPU-mapped buffers, `None` for system memory).
34 pub memory_type: Option<String>,
35 /// Optional pixel format string (e.g., `Some("NV12")`).
36 pub format: Option<String>,
37}
38
39/// Hook invoked once per feed when the decoded stream's caps are known.
40///
41/// The hook receives a [`DecodedStreamInfo`] describing the decoded stream
42/// and returns an optional GStreamer element name to insert between the
43/// decoder and the color-space converter. Returning `None` means no
44/// additional element is needed.
45///
46/// # Example
47///
48/// On Jetson, hardware decoders output `video/x-raw(memory:NVMM)` — GPU-mapped
49/// buffers that the standard `videoconvert` cannot accept. A post-decode hook
50/// can bridge this:
51///
52/// ```rust,ignore
53/// use std::sync::Arc;
54/// use nv_media::PostDecodeHook;
55///
56/// let hook: PostDecodeHook = Arc::new(|info| {
57/// if info.memory_type.as_deref() == Some("NVMM") {
58/// Some("nvvidconv".into())
59/// } else {
60/// None
61/// }
62/// });
63/// ```
64pub type PostDecodeHook = Arc<dyn Fn(&DecodedStreamInfo) -> Option<String> + Send + Sync>;
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn decoded_stream_info_clone() {
72 let info = DecodedStreamInfo {
73 media_type: "video/x-raw".into(),
74 memory_type: Some("NVMM".into()),
75 format: Some("NV12".into()),
76 };
77 let cloned = info.clone();
78 assert_eq!(cloned.media_type, "video/x-raw");
79 assert_eq!(cloned.memory_type.as_deref(), Some("NVMM"));
80 assert_eq!(cloned.format.as_deref(), Some("NV12"));
81 }
82
83 #[test]
84 fn decoded_stream_info_none_fields() {
85 let info = DecodedStreamInfo {
86 media_type: "video/x-raw".into(),
87 memory_type: None,
88 format: None,
89 };
90 assert!(info.memory_type.is_none());
91 assert!(info.format.is_none());
92 }
93
94 #[test]
95 fn hook_type_is_send_sync() {
96 fn assert_send_sync<T: Send + Sync>() {}
97 assert_send_sync::<PostDecodeHook>();
98 }
99}