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 c_int,
52 tb_den: *mut c_int,
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 #[inline]
149 pub fn input_format(mut self, format: Option<InputFormat>) -> DemuxerBuilder {
150 self.input_format = format;
151 self
152 }
153
154 pub fn build<T>(mut self, mut io: IO<T>) -> Result<Demuxer<T>, Error>
159 where
160 T: Read,
161 {
162 let io_context_ptr = io.io_context_mut().as_mut_ptr();
163
164 let format_ptr = self
165 .input_format
166 .take()
167 .map(|f| f.ptr)
168 .unwrap_or(ptr::null_mut());
169
170 let ret = unsafe { ffw_demuxer_init(self.ptr, io_context_ptr, format_ptr) };
171
172 if ret < 0 {
173 return Err(Error::from_raw_error_code(ret));
174 }
175
176 let ptr = self.ptr;
177
178 self.ptr = ptr::null_mut();
179
180 let res = Demuxer { ptr, io };
181
182 Ok(res)
183 }
184}
185
186impl Drop for DemuxerBuilder {
187 fn drop(&mut self) {
188 unsafe { ffw_demuxer_free(self.ptr) }
189 }
190}
191
192unsafe impl Send for DemuxerBuilder {}
193unsafe impl Sync for DemuxerBuilder {}
194
195pub struct Demuxer<T> {
197 ptr: *mut c_void,
198 io: IO<T>,
199}
200
201impl Demuxer<()> {
202 pub fn builder() -> DemuxerBuilder {
204 DemuxerBuilder::new()
205 }
206}
207
208impl<T> Demuxer<T> {
209 pub fn set_option<V>(&mut self, name: &str, value: V) -> Result<(), Error>
211 where
212 V: ToString,
213 {
214 let name = CString::new(name).expect("invalid option name");
215 let value = CString::new(value.to_string()).expect("invalid option value");
216
217 let ret =
218 unsafe { ffw_demuxer_set_option(self.ptr, name.as_ptr() as _, value.as_ptr() as _) };
219
220 if ret < 0 {
221 Err(Error::from_raw_error_code(ret))
222 } else {
223 Ok(())
224 }
225 }
226
227 pub fn take(&mut self) -> Result<Option<Packet>, Error> {
229 let mut pptr = ptr::null_mut();
230
231 let mut tb_num: c_int = 0;
232 let mut tb_den: c_int = 0;
233
234 let ret = unsafe { ffw_demuxer_read_frame(self.ptr, &mut pptr, &mut tb_num, &mut tb_den) };
235
236 if ret < 0 {
237 Err(Error::from_raw_error_code(ret))
238 } else if pptr.is_null() {
239 Ok(None)
240 } else {
241 let tb = TimeBase::new(tb_num as i32, tb_den as i32);
242
243 let packet = unsafe { Packet::from_raw_ptr(pptr, tb) };
244
245 Ok(Some(packet))
246 }
247 }
248
249 pub fn seek_to_timestamp(
251 &self,
252 timestamp: Timestamp,
253 seek_target: SeekTarget,
254 ) -> Result<(), Error> {
255 let micros = timestamp
256 .as_micros()
257 .ok_or_else(|| Error::new("null timestamp"))?;
258
259 self.seek(micros, SeekType::Time, seek_target)
260 }
261
262 pub fn seek_to_frame(&self, frame: u64, seek_target: SeekTarget) -> Result<(), Error> {
264 self.seek(frame as _, SeekType::Frame, seek_target)
265 }
266
267 pub fn seek_to_byte(&self, offset: u64) -> Result<(), Error> {
269 self.seek(offset as _, SeekType::Byte, SeekTarget::Precise)
271 }
272
273 fn seek(
275 &self,
276 target_position: i64,
277 seek_by: SeekType,
278 seek_target: SeekTarget,
279 ) -> Result<(), Error> {
280 let res = unsafe {
281 ffw_demuxer_seek(
282 self.ptr,
283 target_position,
284 seek_by.into_raw(),
285 seek_target.into_raw(),
286 )
287 };
288
289 if res >= 0 {
290 Ok(())
291 } else {
292 Err(Error::from_raw_error_code(res))
293 }
294 }
295
296 pub fn find_stream_info(
299 self,
300 max_analyze_duration: Option<Duration>,
301 ) -> Result<DemuxerWithStreamInfo<T>, (Self, Error)> {
302 let max_analyze_duration = max_analyze_duration
303 .unwrap_or_else(|| Duration::from_secs(0))
304 .as_micros()
305 .try_into()
306 .unwrap();
307
308 let ret = unsafe { ffw_demuxer_find_stream_info(self.ptr, max_analyze_duration) };
309
310 if ret < 0 {
311 return Err((self, Error::from_raw_error_code(ret)));
312 }
313
314 let stream_count = unsafe { ffw_demuxer_get_nb_streams(self.ptr) };
315
316 let mut streams = Vec::with_capacity(stream_count as usize);
317
318 for i in 0..stream_count {
319 let stream = unsafe {
320 let ptr = ffw_demuxer_get_stream(self.ptr, i as _);
321
322 if ptr.is_null() {
323 panic!("unable to get stream info");
324 }
325
326 Stream::from_raw_ptr(ptr)
327 };
328
329 streams.push(stream);
330 }
331
332 let res = DemuxerWithStreamInfo {
333 inner: self,
334 streams,
335 };
336
337 Ok(res)
338 }
339
340 pub fn input_format(&self) -> InputFormat {
341 unsafe {
346 InputFormat {
347 ptr: ffw_demuxer_get_input_format(self.ptr) as _,
348 }
349 }
350 }
351 pub fn io(&self) -> &IO<T> {
353 &self.io
354 }
355
356 pub fn io_mut(&mut self) -> &mut IO<T> {
358 &mut self.io
359 }
360}
361
362impl<T> Drop for Demuxer<T> {
363 fn drop(&mut self) {
364 unsafe { ffw_demuxer_free(self.ptr) }
365 }
366}
367
368unsafe impl<T> Send for Demuxer<T> where T: Send {}
369unsafe impl<T> Sync for Demuxer<T> where T: Sync {}
370
371pub struct DemuxerWithStreamInfo<T> {
373 inner: Demuxer<T>,
374 streams: Vec<Stream>,
375}
376
377impl<T> DemuxerWithStreamInfo<T> {
378 pub fn streams(&self) -> &[Stream] {
380 &self.streams
381 }
382
383 pub fn into_demuxer(self) -> Demuxer<T> {
385 self.inner
386 }
387}
388
389impl<T> AsRef<Demuxer<T>> for DemuxerWithStreamInfo<T> {
390 fn as_ref(&self) -> &Demuxer<T> {
391 &self.inner
392 }
393}
394
395impl<T> AsMut<Demuxer<T>> for DemuxerWithStreamInfo<T> {
396 fn as_mut(&mut self) -> &mut Demuxer<T> {
397 &mut self.inner
398 }
399}
400
401impl<T> Borrow<Demuxer<T>> for DemuxerWithStreamInfo<T> {
402 fn borrow(&self) -> &Demuxer<T> {
403 &self.inner
404 }
405}
406
407impl<T> BorrowMut<Demuxer<T>> for DemuxerWithStreamInfo<T> {
408 fn borrow_mut(&mut self) -> &mut Demuxer<T> {
409 &mut self.inner
410 }
411}
412
413impl<T> Deref for DemuxerWithStreamInfo<T> {
414 type Target = Demuxer<T>;
415
416 fn deref(&self) -> &Self::Target {
417 &self.inner
418 }
419}
420
421impl<T> DerefMut for DemuxerWithStreamInfo<T> {
422 fn deref_mut(&mut self) -> &mut Self::Target {
423 &mut self.inner
424 }
425}
426
427pub struct InputFormat {
429 ptr: *mut c_void,
430}
431
432impl InputFormat {
433 pub fn find_by_name(name: &str) -> Option<InputFormat> {
435 let name = CString::new(name).expect("invalid format name");
436
437 let ptr = unsafe { ffw_guess_input_format(name.as_ptr(), ptr::null(), ptr::null()) };
438
439 if ptr.is_null() {
440 return None;
441 }
442
443 let res = InputFormat { ptr };
444
445 Some(res)
446 }
447
448 pub fn find_by_mime_type(mime_type: &str) -> Option<InputFormat> {
450 let mime_type = CString::new(mime_type).expect("invalid MIME type");
451
452 let ptr = unsafe { ffw_guess_input_format(ptr::null(), ptr::null(), mime_type.as_ptr()) };
453
454 if ptr.is_null() {
455 return None;
456 }
457
458 let res = InputFormat { ptr };
459
460 Some(res)
461 }
462
463 pub fn guess_from_file_name(file_name: &str) -> Option<InputFormat> {
465 let file_name = CString::new(file_name).expect("invalid file name");
466
467 let ptr = unsafe { ffw_guess_input_format(ptr::null(), file_name.as_ptr(), ptr::null()) };
468
469 if ptr.is_null() {
470 return None;
471 }
472
473 let res = InputFormat { ptr };
474
475 Some(res)
476 }
477
478 pub fn name(&self) -> &str {
479 unsafe {
480 CStr::from_ptr(ffw_input_format_name(self.ptr))
481 .to_str()
482 .expect("invalid format name")
483 }
484 }
485}
486
487unsafe impl Send for InputFormat {}
488unsafe impl Sync for InputFormat {}