1use std::ffi::CString;
2use std::mem;
3use std::ops::{Deref, DerefMut};
4
5use super::common::Context;
6use super::destructor;
7use ffi::*;
8use util::range::Range;
9#[cfg(not(feature = "ffmpeg_5_0"))]
10use Codec;
11use {format, Error, Packet, Stream};
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 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
37impl 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
141impl Deref for Input {
142 type Target = Context;
143
144 fn deref(&self) -> &Self::Target {
145 &self.ctx
146 }
147}
148
149impl DerefMut for Input {
150 fn deref_mut(&mut self) -> &mut Self::Target {
151 &mut self.ctx
152 }
153}
154
155pub struct PacketIter<'a> {
156 context: &'a mut Input,
157}
158
159impl<'a> PacketIter<'a> {
160 pub fn new(context: &mut Input) -> PacketIter {
161 PacketIter { context }
162 }
163}
164
165impl<'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
188pub 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