Skip to main content

ff_decode/video/builder/
network.rs

1//! Network and image-sequence options for [`VideoDecoderBuilder`].
2
3use ff_format::NetworkOptions;
4
5use super::VideoDecoderBuilder;
6
7impl VideoDecoderBuilder {
8    /// Sets the frame rate for image sequence decoding.
9    ///
10    /// Only used when the path contains `%` (e.g. `"frames/frame%04d.png"`).
11    /// Defaults to 25 fps when not set.
12    ///
13    /// # Examples
14    ///
15    /// ```ignore
16    /// use ff_decode::VideoDecoder;
17    ///
18    /// let decoder = VideoDecoder::open("frames/frame%04d.png")?
19    ///     .frame_rate(30)
20    ///     .build()?;
21    /// ```
22    #[must_use]
23    pub fn frame_rate(mut self, fps: u32) -> Self {
24        self.frame_rate = Some(fps);
25        self
26    }
27
28    /// Sets network options for URL-based sources.
29    ///
30    /// When set, the builder skips the file-existence check and passes connect
31    /// and read timeouts to `avformat_open_input` via an `AVDictionary`.
32    /// Call this before `.build()` when opening `rtmp://`, `rtsp://`, `http://`,
33    /// `https://`, `udp://`, `srt://`, or `rtp://` URLs.
34    ///
35    /// # HLS / M3U8 Playlists
36    ///
37    /// HLS playlists (`.m3u8`) are detected automatically by `FFmpeg` — no extra
38    /// configuration is required beyond calling `.network()`. Pass the full
39    /// HTTP(S) URL of the master or media playlist:
40    ///
41    /// ```ignore
42    /// use ff_decode::VideoDecoder;
43    /// use ff_format::NetworkOptions;
44    ///
45    /// let decoder = VideoDecoder::open("https://example.com/live/index.m3u8")
46    ///     .network(NetworkOptions::default())
47    ///     .build()?;
48    /// ```
49    ///
50    /// # DASH / MPD Streams
51    ///
52    /// MPEG-DASH manifests (`.mpd`) are detected automatically by `FFmpeg`'s
53    /// built-in `dash` demuxer. The demuxer downloads the manifest, selects the
54    /// highest-quality representation, and fetches segments automatically:
55    ///
56    /// ```ignore
57    /// use ff_decode::VideoDecoder;
58    /// use ff_format::NetworkOptions;
59    ///
60    /// let decoder = VideoDecoder::open("https://example.com/dash/manifest.mpd")
61    ///     .network(NetworkOptions::default())
62    ///     .build()?;
63    /// ```
64    ///
65    /// # Examples
66    ///
67    /// ```ignore
68    /// use ff_decode::VideoDecoder;
69    /// use ff_format::NetworkOptions;
70    ///
71    /// let decoder = VideoDecoder::open("rtmp://live.example.com/app/stream_key")
72    ///     .network(NetworkOptions::default())
73    ///     .build()?;
74    /// ```
75    #[must_use]
76    pub fn network(mut self, opts: NetworkOptions) -> Self {
77        self.network_opts = Some(opts);
78        self
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85    use std::path::PathBuf;
86
87    #[test]
88    fn builder_frame_rate_should_set_fps() {
89        let builder =
90            VideoDecoderBuilder::new(PathBuf::from("frames/frame%04d.png")).frame_rate(30);
91
92        assert_eq!(builder.frame_rate, Some(30));
93    }
94
95    #[test]
96    fn builder_frame_rate_last_setter_wins() {
97        let builder = VideoDecoderBuilder::new(PathBuf::from("frames/frame%04d.png"))
98            .frame_rate(25)
99            .frame_rate(60);
100
101        assert_eq!(builder.frame_rate, Some(60));
102    }
103
104    #[test]
105    fn builder_network_should_set_network_opts() {
106        let builder = VideoDecoderBuilder::new(PathBuf::from("rtmp://example.com/live/stream"))
107            .network(NetworkOptions::default());
108
109        assert!(builder.network_opts.is_some());
110    }
111
112    #[test]
113    fn builder_frame_rate_default_should_be_none() {
114        let builder = VideoDecoderBuilder::new(PathBuf::from("frames/frame%04d.png"));
115
116        assert!(builder.frame_rate.is_none());
117    }
118}