ffmpeg_next/format/context/
input.rs1use std::ffi::CString;
2use std::mem;
3use std::ops::{Deref, DerefMut};
4
5use super::common::Context;
6use super::destructor;
7#[cfg(not(feature = "ffmpeg_5_0"))]
8use crate::Codec;
9use crate::ffi::*;
10use crate::util::range::Range;
11use crate::{Error, Packet, Stream, format};
12
13pub struct Input {
14 ptr: *mut AVFormatContext,
15 ctx: Context,
16}
17
18unsafe impl Send for Input {}
19
20impl Input {
21 pub unsafe fn wrap(ptr: *mut AVFormatContext) -> Self {
22 unsafe {
23 Input {
24 ptr,
25 ctx: Context::wrap(ptr, destructor::Mode::Input),
26 }
27 }
28 }
29 pub unsafe fn wrap_with_custom_io(
30 ptr: *mut AVFormatContext,
31 custom_io: format::context::StreamIo,
32 ) -> Self {
33 unsafe {
34 Input {
35 ptr,
36 ctx: Context::wrap(ptr, destructor::Mode::InputCustomIo(custom_io)),
37 }
38 }
39 }
40
41 pub unsafe fn wrap_with_interrupt(
42 ptr: *mut AVFormatContext,
43 guard: crate::util::interrupt::InterruptGuard,
44 ) -> Self {
45 unsafe {
46 Input {
47 ptr,
48 ctx: Context::wrap_with_interrupt(ptr, destructor::Mode::Input, guard),
49 }
50 }
51 }
52
53 pub unsafe fn wrap_with_custom_io_and_interrupt(
54 ptr: *mut AVFormatContext,
55 custom_io: format::context::StreamIo,
56 guard: crate::util::interrupt::InterruptGuard,
57 ) -> Self {
58 unsafe {
59 Input {
60 ptr,
61 ctx: Context::wrap_with_interrupt(
62 ptr,
63 destructor::Mode::InputCustomIo(custom_io),
64 guard,
65 ),
66 }
67 }
68 }
69
70 pub unsafe fn as_ptr(&self) -> *const AVFormatContext {
71 self.ptr as *const _
72 }
73
74 pub unsafe fn as_mut_ptr(&mut self) -> *mut AVFormatContext {
75 self.ptr
76 }
77}
78
79impl Input {
80 pub fn format(&self) -> format::Input {
81 #[allow(clippy::unnecessary_cast)]
83 unsafe {
84 format::Input::wrap((*self.as_ptr()).iformat as *mut AVInputFormat)
85 }
86 }
87
88 #[cfg(not(feature = "ffmpeg_5_0"))]
89 pub fn video_codec(&self) -> Option<Codec> {
90 unsafe {
91 let ptr = (*self.as_ptr()).video_codec;
92
93 if ptr.is_null() {
94 None
95 } else {
96 Some(Codec::wrap(ptr))
97 }
98 }
99 }
100
101 #[cfg(not(feature = "ffmpeg_5_0"))]
102 pub fn audio_codec(&self) -> Option<Codec> {
103 unsafe {
104 let ptr = (*self.as_ptr()).audio_codec;
105
106 if ptr.is_null() {
107 None
108 } else {
109 Some(Codec::wrap(ptr))
110 }
111 }
112 }
113
114 #[cfg(not(feature = "ffmpeg_5_0"))]
115 pub fn subtitle_codec(&self) -> Option<Codec> {
116 unsafe {
117 let ptr = (*self.as_ptr()).subtitle_codec;
118
119 if ptr.is_null() {
120 None
121 } else {
122 Some(Codec::wrap(ptr))
123 }
124 }
125 }
126
127 #[cfg(not(feature = "ffmpeg_5_0"))]
128 pub fn data_codec(&self) -> Option<Codec> {
129 unsafe {
130 let ptr = (*self.as_ptr()).data_codec;
131
132 if ptr.is_null() {
133 None
134 } else {
135 Some(Codec::wrap(ptr))
136 }
137 }
138 }
139
140 pub fn probe_score(&self) -> i32 {
141 unsafe { (*self.as_ptr()).probe_score }
142 }
143
144 pub fn packets(&mut self) -> PacketIter<'_> {
145 PacketIter::new(self)
146 }
147
148 pub fn pause(&mut self) -> Result<(), Error> {
149 unsafe {
150 match av_read_pause(self.as_mut_ptr()) {
151 0 => Ok(()),
152 e => Err(Error::from(e)),
153 }
154 }
155 }
156
157 pub fn play(&mut self) -> Result<(), Error> {
158 unsafe {
159 match av_read_play(self.as_mut_ptr()) {
160 0 => Ok(()),
161 e => Err(Error::from(e)),
162 }
163 }
164 }
165
166 pub fn seek<R: Range<i64>>(&mut self, ts: i64, range: R) -> Result<(), Error> {
167 unsafe {
168 let pb = (*self.ptr).pb;
169 let relatch = unlatch_exit(pb);
173 let ret = avformat_seek_file(
174 self.as_mut_ptr(),
175 -1,
176 range.start().cloned().unwrap_or(i64::MIN),
177 ts,
178 range.end().cloned().unwrap_or(i64::MAX),
179 0,
180 );
181 if ret < 0 && relatch {
182 (*pb).error = AVERROR_EXIT;
190 (*pb).eof_reached = 1;
191 }
192 match ret {
193 s if s >= 0 => Ok(()),
194 e => Err(Error::from(e)),
195 }
196 }
197 }
198
199 pub fn io_size(&self) -> Option<i64> {
200 unsafe {
201 let pb = (*self.as_ptr()).pb;
202 if pb.is_null() {
203 return None;
204 }
205 let sz = avio_size(pb);
206 if sz < 0 { None } else { Some(sz) }
207 }
208 }
209
210 pub fn clear_eof(&mut self) -> bool {
211 unsafe {
212 let pb = (*self.as_ptr()).pb;
213 if pb.is_null() {
214 return false;
215 }
216 (*pb).eof_reached = 0;
217 (*pb).error = 0;
218 true
219 }
220 }
221
222 pub fn clear_interrupt(&mut self) -> bool {
231 unsafe { unlatch_exit((*self.ptr).pb) }
232 }
233}
234
235unsafe fn unlatch_exit(pb: *mut AVIOContext) -> bool {
243 unsafe {
244 if pb.is_null() || (*pb).error != AVERROR_EXIT {
245 return false;
246 }
247 (*pb).error = 0;
248 (*pb).eof_reached = 0;
249 true
250 }
251}
252
253impl Deref for Input {
254 type Target = Context;
255
256 fn deref(&self) -> &Self::Target {
257 &self.ctx
258 }
259}
260
261impl DerefMut for Input {
262 fn deref_mut(&mut self) -> &mut Self::Target {
263 &mut self.ctx
264 }
265}
266
267pub struct PacketIter<'a> {
268 context: &'a mut Input,
269}
270
271impl<'a> PacketIter<'a> {
272 pub fn new(context: &mut Input) -> PacketIter<'_> {
273 PacketIter { context }
274 }
275}
276
277impl<'a> Iterator for PacketIter<'a> {
278 type Item = (Stream<'a>, Packet);
279
280 fn next(&mut self) -> Option<<Self as Iterator>::Item> {
281 let mut packet = Packet::empty();
282
283 loop {
284 match packet.read(self.context) {
285 Ok(..) => unsafe {
286 return Some((
287 Stream::wrap(mem::transmute_copy(&self.context), packet.stream()),
288 packet,
289 ));
290 },
291
292 Err(Error::Eof) => return None,
293
294 Err(Error::InvalidData) => (),
298
299 Err(..) => return None,
307 }
308 }
309 }
310}
311
312pub fn dump(ctx: &Input, index: i32, url: Option<&str>) {
313 let url = url.map(|u| CString::new(u).unwrap());
314
315 unsafe {
316 av_dump_format(
317 ctx.as_ptr() as *mut _,
318 index,
319 url.unwrap_or_else(|| CString::new("").unwrap()).as_ptr(),
320 0,
321 );
322 }
323}