1use std::{
4 borrow::{Borrow, BorrowMut},
5 convert::TryInto,
6 ffi::{CStr, CString},
7 io::Read,
8 ops::{Deref, DerefMut},
9 os::raw::{c_char, c_int, c_uint, c_void},
10 ptr,
11 time::Duration,
12};
13
14use crate::{
15 format::{io::IO, stream::Stream},
16 packet::Packet,
17 time::{TimeBase, Timestamp},
18 Error,
19};
20
21extern "C" {
22 fn ffw_guess_input_format(
23 short_name: *const c_char,
24 file_name: *const c_char,
25 mime_type: *const c_char,
26 ) -> *mut c_void;
27
28 fn ffw_demuxer_new() -> *mut c_void;
29 fn ffw_demuxer_init(
30 demuxer: *mut c_void,
31 io_context: *mut c_void,
32 format: *mut c_void,
33 ) -> c_int;
34 fn ffw_demuxer_set_initial_option(
35 demuxer: *mut c_void,
36 key: *const c_char,
37 value: *const c_char,
38 ) -> c_int;
39 fn ffw_demuxer_set_option(
40 demuxer: *mut c_void,
41 key: *const c_char,
42 value: *const c_char,
43 ) -> c_int;
44 fn ffw_demuxer_find_stream_info(demuxer: *mut c_void, max_analyze_duration: i64) -> c_int;
45 fn ffw_demuxer_get_nb_streams(demuxer: *const c_void) -> c_uint;
46 fn ffw_demuxer_get_stream(demuxer: *mut c_void, index: c_uint) -> *mut c_void;
47 fn ffw_demuxer_get_input_format(demuxer: *const c_void) -> *const c_void;
48 fn ffw_demuxer_read_frame(
49 demuxer: *mut c_void,
50 packet: *mut *mut c_void,
51 tb_num: *mut u32,
52 tb_den: *mut u32,
53 ) -> c_int;
54 fn ffw_demuxer_seek(
55 demuxer: *mut c_void,
56 timestamp: i64,
57 seek_by: c_int,
58 seek_target: c_int,
59 ) -> c_int;
60 fn ffw_demuxer_free(demuxer: *mut c_void);
61 fn ffw_input_format_name(input_format: *const c_void) -> *const c_char;
62}
63
64enum SeekType {
66 Time,
67 Byte,
68 Frame,
69}
70
71impl SeekType {
72 fn into_raw(self) -> i32 {
74 match self {
75 SeekType::Time => 0,
76 SeekType::Byte => 1,
77 SeekType::Frame => 2,
78 }
79 }
80}
81
82pub enum SeekTarget {
85 From,
88 UpTo,
91 Precise,
94}
95
96impl SeekTarget {
97 fn into_raw(self) -> i32 {
99 match self {
100 SeekTarget::From => 0,
101 SeekTarget::UpTo => 1,
102 SeekTarget::Precise => 2,
103 }
104 }
105}
106
107pub struct DemuxerBuilder {
109 ptr: *mut c_void,
110 input_format: Option<InputFormat>,
111}
112
113impl DemuxerBuilder {
114 fn new() -> DemuxerBuilder {
116 let ptr = unsafe { ffw_demuxer_new() };
117
118 if ptr.is_null() {
119 panic!("unable to allocate a demuxer context");
120 }
121
122 DemuxerBuilder {
123 ptr,
124 input_format: None,
125 }
126 }
127
128 pub fn set_option<V>(self, name: &str, value: V) -> DemuxerBuilder
130 where
131 V: ToString,
132 {
133 let name = CString::new(name).expect("invalid option name");
134 let value = CString::new(value.to_string()).expect("invalid option value");
135
136 let ret = unsafe {
137 ffw_demuxer_set_initial_option(self.ptr, name.as_ptr() as _, value.as_ptr() as _)
138 };
139
140 if ret < 0 {
141 panic!("unable to allocate an option");
142 }
143
144 self
145 }
146
147 pub fn input_format(mut self, format: Option<InputFormat>) -> DemuxerBuilder {
149 self.input_format = format;
150 self
151 }
152
153 pub fn build<T>(mut self, mut io: IO<T>) -> Result<Demuxer<T>, Error>
158 where
159 T: Read,
160 {
161 let io_context_ptr = io.io_context_mut().as_mut_ptr();
162
163 let format_ptr = self
164 .input_format
165 .take()
166 .map(|f| f.ptr)
167 .unwrap_or(ptr::null_mut());
168
169 let ret = unsafe { ffw_demuxer_init(self.ptr, io_context_ptr, format_ptr) };
170
171 if ret < 0 {
172 return Err(Error::from_raw_error_code(ret));
173 }
174
175 let ptr = self.ptr;
176
177 self.ptr = ptr::null_mut();
178
179 let res = Demuxer { ptr, io };
180
181 Ok(res)
182 }
183}
184
185impl Drop for DemuxerBuilder {
186 fn drop(&mut self) {
187 unsafe { ffw_demuxer_free(self.ptr) }
188 }
189}
190
191unsafe impl Send for DemuxerBuilder {}
192unsafe impl Sync for DemuxerBuilder {}
193
194pub struct Demuxer<T> {
196 ptr: *mut c_void,
197 io: IO<T>,
198}
199
200impl Demuxer<()> {
201 pub fn builder() -> DemuxerBuilder {
203 DemuxerBuilder::new()
204 }
205}
206
207impl<T> Demuxer<T> {
208 pub fn set_option<V>(&mut self, name: &str, value: V) -> Result<(), Error>
210 where
211 V: ToString,
212 {
213 let name = CString::new(name).expect("invalid option name");
214 let value = CString::new(value.to_string()).expect("invalid option value");
215
216 let ret =
217 unsafe { ffw_demuxer_set_option(self.ptr, name.as_ptr() as _, value.as_ptr() as _) };
218
219 if ret < 0 {
220 Err(Error::from_raw_error_code(ret))
221 } else {
222 Ok(())
223 }
224 }
225
226 pub fn take(&mut self) -> Result<Option<Packet>, Error> {
228 let mut pptr = ptr::null_mut();
229
230 let mut tb_num = 0;
231 let mut tb_den = 0;
232
233 let ret = unsafe { ffw_demuxer_read_frame(self.ptr, &mut pptr, &mut tb_num, &mut tb_den) };
234
235 if ret < 0 {
236 Err(Error::from_raw_error_code(ret))
237 } else if pptr.is_null() {
238 Ok(None)
239 } else {
240 let packet = unsafe { Packet::from_raw_ptr(pptr, TimeBase::new(tb_num, tb_den)) };
241
242 Ok(Some(packet))
243 }
244 }
245
246 pub fn seek_to_timestamp(
248 &self,
249 timestamp: Timestamp,
250 seek_target: SeekTarget,
251 ) -> Result<(), Error> {
252 let micros = timestamp
253 .as_micros()
254 .ok_or_else(|| Error::new("null timestamp"))?;
255
256 self.seek(micros, SeekType::Time, seek_target)
257 }
258
259 pub fn seek_to_frame(&self, frame: u64, seek_target: SeekTarget) -> Result<(), Error> {
261 self.seek(frame as _, SeekType::Frame, seek_target)
262 }
263
264 pub fn seek_to_byte(&self, offset: u64) -> Result<(), Error> {
266 self.seek(offset as _, SeekType::Byte, SeekTarget::Precise)
268 }
269
270 fn seek(
272 &self,
273 target_position: i64,
274 seek_by: SeekType,
275 seek_target: SeekTarget,
276 ) -> Result<(), Error> {
277 let res = unsafe {
278 ffw_demuxer_seek(
279 self.ptr,
280 target_position,
281 seek_by.into_raw(),
282 seek_target.into_raw(),
283 )
284 };
285
286 if res >= 0 {
287 Ok(())
288 } else {
289 Err(Error::from_raw_error_code(res))
290 }
291 }
292
293 pub fn find_stream_info(
296 self,
297 max_analyze_duration: Option<Duration>,
298 ) -> Result<DemuxerWithStreamInfo<T>, (Self, Error)> {
299 let max_analyze_duration = max_analyze_duration
300 .unwrap_or_else(|| Duration::from_secs(0))
301 .as_micros()
302 .try_into()
303 .unwrap();
304
305 let ret = unsafe { ffw_demuxer_find_stream_info(self.ptr, max_analyze_duration) };
306
307 if ret < 0 {
308 return Err((self, Error::from_raw_error_code(ret)));
309 }
310
311 let stream_count = unsafe { ffw_demuxer_get_nb_streams(self.ptr) };
312
313 let mut streams = Vec::with_capacity(stream_count as usize);
314
315 for i in 0..stream_count {
316 let stream = unsafe {
317 let ptr = ffw_demuxer_get_stream(self.ptr, i as _);
318
319 if ptr.is_null() {
320 panic!("unable to get stream info");
321 }
322
323 Stream::from_raw_ptr(ptr)
324 };
325
326 streams.push(stream);
327 }
328
329 let res = DemuxerWithStreamInfo {
330 inner: self,
331 streams,
332 };
333
334 Ok(res)
335 }
336
337 pub fn input_format(&self) -> InputFormat {
338 unsafe {
343 InputFormat {
344 ptr: ffw_demuxer_get_input_format(self.ptr) as _,
345 }
346 }
347 }
348 pub fn io(&self) -> &IO<T> {
350 &self.io
351 }
352
353 pub fn io_mut(&mut self) -> &mut IO<T> {
355 &mut self.io
356 }
357}
358
359impl<T> Drop for Demuxer<T> {
360 fn drop(&mut self) {
361 unsafe { ffw_demuxer_free(self.ptr) }
362 }
363}
364
365unsafe impl<T> Send for Demuxer<T> where T: Send {}
366unsafe impl<T> Sync for Demuxer<T> where T: Sync {}
367
368pub struct DemuxerWithStreamInfo<T> {
370 inner: Demuxer<T>,
371 streams: Vec<Stream>,
372}
373
374impl<T> DemuxerWithStreamInfo<T> {
375 pub fn streams(&self) -> &[Stream] {
377 &self.streams
378 }
379
380 pub fn into_demuxer(self) -> Demuxer<T> {
382 self.inner
383 }
384}
385
386impl<T> AsRef<Demuxer<T>> for DemuxerWithStreamInfo<T> {
387 fn as_ref(&self) -> &Demuxer<T> {
388 &self.inner
389 }
390}
391
392impl<T> AsMut<Demuxer<T>> for DemuxerWithStreamInfo<T> {
393 fn as_mut(&mut self) -> &mut Demuxer<T> {
394 &mut self.inner
395 }
396}
397
398impl<T> Borrow<Demuxer<T>> for DemuxerWithStreamInfo<T> {
399 fn borrow(&self) -> &Demuxer<T> {
400 &self.inner
401 }
402}
403
404impl<T> BorrowMut<Demuxer<T>> for DemuxerWithStreamInfo<T> {
405 fn borrow_mut(&mut self) -> &mut Demuxer<T> {
406 &mut self.inner
407 }
408}
409
410impl<T> Deref for DemuxerWithStreamInfo<T> {
411 type Target = Demuxer<T>;
412
413 fn deref(&self) -> &Self::Target {
414 &self.inner
415 }
416}
417
418impl<T> DerefMut for DemuxerWithStreamInfo<T> {
419 fn deref_mut(&mut self) -> &mut Self::Target {
420 &mut self.inner
421 }
422}
423
424pub struct InputFormat {
426 ptr: *mut c_void,
427}
428
429impl InputFormat {
430 pub fn find_by_name(name: &str) -> Option<InputFormat> {
432 let name = CString::new(name).expect("invalid format name");
433
434 let ptr = unsafe { ffw_guess_input_format(name.as_ptr(), ptr::null(), ptr::null()) };
435
436 if ptr.is_null() {
437 return None;
438 }
439
440 let res = InputFormat { ptr };
441
442 Some(res)
443 }
444
445 pub fn find_by_mime_type(mime_type: &str) -> Option<InputFormat> {
447 let mime_type = CString::new(mime_type).expect("invalid MIME type");
448
449 let ptr = unsafe { ffw_guess_input_format(ptr::null(), ptr::null(), mime_type.as_ptr()) };
450
451 if ptr.is_null() {
452 return None;
453 }
454
455 let res = InputFormat { ptr };
456
457 Some(res)
458 }
459
460 pub fn guess_from_file_name(file_name: &str) -> Option<InputFormat> {
462 let file_name = CString::new(file_name).expect("invalid file name");
463
464 let ptr = unsafe { ffw_guess_input_format(ptr::null(), file_name.as_ptr(), ptr::null()) };
465
466 if ptr.is_null() {
467 return None;
468 }
469
470 let res = InputFormat { ptr };
471
472 Some(res)
473 }
474
475 pub fn name(&self) -> &str {
476 unsafe {
477 CStr::from_ptr(ffw_input_format_name(self.ptr))
478 .to_str()
479 .expect("invalid format name")
480 }
481 }
482}
483
484unsafe impl Send for InputFormat {}
485unsafe impl Sync for InputFormat {}