playa_ffmpeg/format/context/
input.rs

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