ac_ffmpeg/format/
stream.rs1use 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
49pub struct Stream {
51 ptr: *mut c_void,
52 time_base: TimeBase,
53}
54
55impl Stream {
56 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 #[inline]
71 pub fn time_base(&self) -> TimeBase {
72 self.time_base
73 }
74
75 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 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 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 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 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 pub fn stream_id(&self) -> i32 {
132 unsafe { ffw_stream_get_id(self.ptr) as i32 }
133 }
134
135 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 pub fn set_stream_id(&mut self, id: i32) {
152 unsafe { ffw_stream_set_id(self.ptr, id as c_int) };
153 }
154
155 #[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 #[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#[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<'_> {}