ac_ffmpeg/format/
stream.rs

1//! A/V stream information.
2
3use std::{
4    ffi::CString,
5    os::raw::{c_char, c_int, c_void},
6};
7
8use crate::{
9    codec::CodecParameters,
10    time::{TimeBase, Timestamp},
11};
12
13#[cfg(stream_side_data)]
14use crate::{
15    packet::{SideDataRef, SideDataType},
16    Error,
17};
18
19extern "C" {
20    fn ffw_stream_get_time_base(stream: *const c_void, num: *mut c_int, den: *mut c_int);
21    fn ffw_stream_set_time_base(stream: *mut c_void, num: c_int, den: c_int);
22    fn ffw_stream_get_start_time(stream: *const c_void) -> i64;
23    fn ffw_stream_get_duration(stream: *const c_void) -> i64;
24    fn ffw_stream_get_nb_frames(stream: *const c_void) -> i64;
25    fn ffw_stream_get_codec_parameters(stream: *const c_void) -> *mut c_void;
26    fn ffw_stream_get_id(stream: *const c_void) -> c_int;
27    fn ffw_stream_set_metadata(
28        stream: *mut c_void,
29        key: *const c_char,
30        value: *const c_char,
31    ) -> c_int;
32    fn ffw_stream_set_id(stream: *mut c_void, id: c_int);
33
34    #[cfg(stream_side_data)]
35    fn ffw_stream_get_nb_side_data(stream: *const c_void) -> usize;
36
37    #[cfg(stream_side_data)]
38    fn ffw_stream_get_side_data(stream: *const c_void, index: usize) -> *const c_void;
39
40    #[cfg(stream_side_data)]
41    fn ffw_stream_add_side_data(
42        stream: *mut c_void,
43        data_type: c_int,
44        data: *const u8,
45        size: usize,
46    ) -> c_int;
47}
48
49/// Stream.
50pub struct Stream {
51    ptr: *mut c_void,
52    time_base: TimeBase,
53}
54
55impl Stream {
56    /// Create a new stream from its raw representation.
57    pub(crate) unsafe fn from_raw_ptr(ptr: *mut c_void) -> Self {
58        let mut num: c_int = 0;
59        let mut den: c_int = 0;
60
61        ffw_stream_get_time_base(ptr, &mut num, &mut den);
62
63        Stream {
64            ptr,
65            time_base: TimeBase::new(num as _, den as _),
66        }
67    }
68
69    /// Get stream time base.
70    #[inline]
71    pub fn time_base(&self) -> TimeBase {
72        self.time_base
73    }
74
75    /// Provide a hint to the muxer about the desired timebase.
76    pub fn set_time_base(&mut self, time_base: TimeBase) {
77        self.time_base = time_base;
78
79        unsafe {
80            ffw_stream_set_time_base(
81                self.ptr,
82                self.time_base.num() as _,
83                self.time_base.den() as _,
84            );
85        }
86    }
87
88    /// Get the pts of the first frame of the stream in presentation order.
89    pub fn start_time(&self) -> Timestamp {
90        let pts = unsafe { ffw_stream_get_start_time(self.ptr) as _ };
91
92        Timestamp::new(pts, self.time_base)
93    }
94
95    /// Get the duration of the stream.
96    pub fn duration(&self) -> Timestamp {
97        let pts = unsafe { ffw_stream_get_duration(self.ptr) as _ };
98
99        Timestamp::new(pts, self.time_base)
100    }
101
102    /// Get the number of frames in the stream.
103    ///
104    /// # Note
105    /// The number may not represent the total number of frames, depending on the type of the
106    /// stream and the demuxer it may represent only the total number of keyframes.
107    pub fn frames(&self) -> Option<u64> {
108        let count = unsafe { ffw_stream_get_nb_frames(self.ptr) };
109
110        if count <= 0 {
111            None
112        } else {
113            Some(count as _)
114        }
115    }
116
117    /// Get codec parameters.
118    pub fn codec_parameters(&self) -> CodecParameters {
119        unsafe {
120            let ptr = ffw_stream_get_codec_parameters(self.ptr);
121
122            if ptr.is_null() {
123                panic!("unable to allocate codec parameters");
124            }
125
126            CodecParameters::from_raw_ptr(ptr)
127        }
128    }
129
130    /// Get stream id.
131    pub fn stream_id(&self) -> i32 {
132        unsafe { ffw_stream_get_id(self.ptr) as i32 }
133    }
134
135    /// Set stream metadata.
136    pub fn set_metadata<V>(&mut self, key: &str, value: V)
137    where
138        V: ToString,
139    {
140        let key = CString::new(key).expect("invalid metadata key");
141        let value = CString::new(value.to_string()).expect("invalid metadata value");
142
143        let ret = unsafe { ffw_stream_set_metadata(self.ptr, key.as_ptr(), value.as_ptr()) };
144
145        if ret < 0 {
146            panic!("unable to allocate metadata");
147        }
148    }
149
150    /// Set stream id.
151    pub fn set_stream_id(&mut self, id: i32) {
152        unsafe { ffw_stream_set_id(self.ptr, id as c_int) };
153    }
154
155    /// Get stream side data.
156    #[cfg(stream_side_data)]
157    pub fn side_data(&self) -> SideDataIter<'_> {
158        let len = unsafe { ffw_stream_get_nb_side_data(self.ptr) };
159
160        SideDataIter {
161            stream: self,
162            index: 0,
163            len,
164        }
165    }
166
167    /// Add stream side data.
168    #[cfg(stream_side_data)]
169    pub fn add_side_data(&mut self, data_type: SideDataType, data: &[u8]) -> Result<(), Error> {
170        let ret = unsafe {
171            ffw_stream_add_side_data(self.ptr, data_type.into_raw(), data.as_ptr(), data.len())
172        };
173
174        if ret < 0 {
175            Err(Error::from_raw_error_code(ret))
176        } else {
177            Ok(())
178        }
179    }
180}
181
182unsafe impl Send for Stream {}
183unsafe impl Sync for Stream {}
184
185/// Iterator over stream side data.
186#[cfg(stream_side_data)]
187pub struct SideDataIter<'a> {
188    stream: &'a Stream,
189    index: usize,
190    len: usize,
191}
192
193#[cfg(stream_side_data)]
194impl<'a> Iterator for SideDataIter<'a> {
195    type Item = &'a SideDataRef;
196
197    fn next(&mut self) -> Option<Self::Item> {
198        if self.index == self.len {
199            return None;
200        }
201
202        let side_data = unsafe {
203            SideDataRef::from_raw_ptr(ffw_stream_get_side_data(self.stream.ptr, self.index))
204        };
205
206        self.index += 1;
207
208        Some(side_data)
209    }
210
211    fn size_hint(&self) -> (usize, Option<usize>) {
212        let hint = self.len - self.index;
213
214        (hint, Some(hint))
215    }
216}
217
218#[cfg(stream_side_data)]
219impl ExactSizeIterator for SideDataIter<'_> {}