Skip to main content

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}