1 | use std::ffi::CString; |
2 | use std::mem; |
3 | use std::ops::{Deref, DerefMut}; |
4 | |
5 | use super::common::Context; |
6 | use super::destructor; |
7 | use ffi::*; |
8 | use util::range::Range; |
9 | #[cfg (not(feature = "ffmpeg_5_0" ))] |
10 | use Codec; |
11 | use {format, Error, Packet, Stream}; |
12 | |
13 | pub struct Input { |
14 | ptr: *mut AVFormatContext, |
15 | ctx: Context, |
16 | } |
17 | |
18 | unsafe impl Send for Input {} |
19 | |
20 | impl Input { |
21 | pub unsafe fn wrap(ptr: *mut AVFormatContext) -> Self { |
22 | Input { |
23 | ptr, |
24 | ctx: Context::wrap(ptr, destructor::Mode::Input), |
25 | } |
26 | } |
27 | |
28 | pub unsafe fn as_ptr(&self) -> *const AVFormatContext { |
29 | self.ptr as *const _ |
30 | } |
31 | |
32 | pub unsafe fn as_mut_ptr(&mut self) -> *mut AVFormatContext { |
33 | self.ptr |
34 | } |
35 | } |
36 | |
37 | impl Input { |
38 | pub fn format(&self) -> format::Input { |
39 | // We get a clippy warning in 4.4 but not in 5.0 and newer, so we allow that cast to not complicate the code |
40 | #[allow (clippy::unnecessary_cast)] |
41 | unsafe { |
42 | format::Input::wrap((*self.as_ptr()).iformat as *mut AVInputFormat) |
43 | } |
44 | } |
45 | |
46 | #[cfg (not(feature = "ffmpeg_5_0" ))] |
47 | pub fn video_codec(&self) -> Option<Codec> { |
48 | unsafe { |
49 | let ptr = (*self.as_ptr()).video_codec; |
50 | |
51 | if ptr.is_null() { |
52 | None |
53 | } else { |
54 | Some(Codec::wrap(ptr)) |
55 | } |
56 | } |
57 | } |
58 | |
59 | #[cfg (not(feature = "ffmpeg_5_0" ))] |
60 | pub fn audio_codec(&self) -> Option<Codec> { |
61 | unsafe { |
62 | let ptr = (*self.as_ptr()).audio_codec; |
63 | |
64 | if ptr.is_null() { |
65 | None |
66 | } else { |
67 | Some(Codec::wrap(ptr)) |
68 | } |
69 | } |
70 | } |
71 | |
72 | #[cfg (not(feature = "ffmpeg_5_0" ))] |
73 | pub fn subtitle_codec(&self) -> Option<Codec> { |
74 | unsafe { |
75 | let ptr = (*self.as_ptr()).subtitle_codec; |
76 | |
77 | if ptr.is_null() { |
78 | None |
79 | } else { |
80 | Some(Codec::wrap(ptr)) |
81 | } |
82 | } |
83 | } |
84 | |
85 | #[cfg (not(feature = "ffmpeg_5_0" ))] |
86 | pub fn data_codec(&self) -> Option<Codec> { |
87 | unsafe { |
88 | let ptr = (*self.as_ptr()).data_codec; |
89 | |
90 | if ptr.is_null() { |
91 | None |
92 | } else { |
93 | Some(Codec::wrap(ptr)) |
94 | } |
95 | } |
96 | } |
97 | |
98 | pub fn probe_score(&self) -> i32 { |
99 | unsafe { (*self.as_ptr()).probe_score } |
100 | } |
101 | |
102 | pub fn packets(&mut self) -> PacketIter { |
103 | PacketIter::new(self) |
104 | } |
105 | |
106 | pub fn pause(&mut self) -> Result<(), Error> { |
107 | unsafe { |
108 | match av_read_pause(self.as_mut_ptr()) { |
109 | 0 => Ok(()), |
110 | e => Err(Error::from(e)), |
111 | } |
112 | } |
113 | } |
114 | |
115 | pub fn play(&mut self) -> Result<(), Error> { |
116 | unsafe { |
117 | match av_read_play(self.as_mut_ptr()) { |
118 | 0 => Ok(()), |
119 | e => Err(Error::from(e)), |
120 | } |
121 | } |
122 | } |
123 | |
124 | pub fn seek<R: Range<i64>>(&mut self, ts: i64, range: R) -> Result<(), Error> { |
125 | unsafe { |
126 | match avformat_seek_file( |
127 | self.as_mut_ptr(), |
128 | -1, |
129 | range.start().cloned().unwrap_or(i64::min_value()), |
130 | ts, |
131 | range.end().cloned().unwrap_or(i64::max_value()), |
132 | 0, |
133 | ) { |
134 | s if s >= 0 => Ok(()), |
135 | e => Err(Error::from(e)), |
136 | } |
137 | } |
138 | } |
139 | } |
140 | |
141 | impl Deref for Input { |
142 | type Target = Context; |
143 | |
144 | fn deref(&self) -> &Self::Target { |
145 | &self.ctx |
146 | } |
147 | } |
148 | |
149 | impl DerefMut for Input { |
150 | fn deref_mut(&mut self) -> &mut Self::Target { |
151 | &mut self.ctx |
152 | } |
153 | } |
154 | |
155 | pub struct PacketIter<'a> { |
156 | context: &'a mut Input, |
157 | } |
158 | |
159 | impl<'a> PacketIter<'a> { |
160 | pub fn new(context: &mut Input) -> PacketIter { |
161 | PacketIter { context } |
162 | } |
163 | } |
164 | |
165 | impl<'a> Iterator for PacketIter<'a> { |
166 | type Item = (Stream<'a>, Packet); |
167 | |
168 | fn next(&mut self) -> Option<<Self as Iterator>::Item> { |
169 | let mut packet: Packet = Packet::empty(); |
170 | |
171 | loop { |
172 | match packet.read(self.context) { |
173 | Ok(..) => unsafe { |
174 | return Some(( |
175 | Stream::wrap(context:mem::transmute_copy(&self.context), index:packet.stream()), |
176 | packet, |
177 | )); |
178 | }, |
179 | |
180 | Err(Error::Eof) => return None, |
181 | |
182 | Err(..) => (), |
183 | } |
184 | } |
185 | } |
186 | } |
187 | |
188 | pub fn dump(ctx: &Input, index: i32, url: Option<&str>) { |
189 | let url: Option = url.map(|u: &str| CString::new(u).unwrap()); |
190 | |
191 | unsafe { |
192 | av_dump_format( |
193 | ctx.as_ptr() as *mut _, |
194 | index, |
195 | url.unwrap_or_else(|| CString::new("" ).unwrap()).as_ptr(), |
196 | 0, |
197 | ); |
198 | } |
199 | } |
200 | |