Skip to main content

libav_ng/avformat/
mod.rs

1use std::ffi::CString;
2
3use libav_sys_ng::{
4    self, AVFormatContext, AVInputFormat, AVOutputFormat, av_dump_format, av_read_frame, av_seek_frame, av_write_frame, av_write_trailer, avformat_alloc_output_context2, avformat_find_stream_info, avformat_free_context, avformat_open_input, avformat_write_header, avio_open
5};
6
7use crate::{
8    avdictionary::Dictionary, avformat::streams_iter::FormatStreamsIter, avpacket::Packet,
9};
10
11pub mod streams_iter;
12pub struct FormatContext {
13    _format_ctx: *mut libav_sys_ng::AVFormatContext,
14}
15
16impl FormatContext {
17    pub fn new(
18        format_name: &str,
19        filename: &str,
20        output_format: Option<AVOutputFormat>,
21    ) -> Option<FormatContext> {
22        unsafe {
23            let mut context = core::ptr::null_mut::<libav_sys_ng::AVFormatContext>();
24
25            let ptr = match output_format {
26                Some(fmt) => &fmt,
27                None => core::ptr::null::<AVOutputFormat>(),
28            };
29
30            let fmt_name = CString::new(format_name).expect("CString::new(format_name) failed");
31            let real_filename = CString::new(filename).expect("CString::new(filename) failed");
32
33            avformat_alloc_output_context2(
34                &mut context,
35                ptr,
36                fmt_name.as_ptr(),
37                real_filename.as_ptr(),
38            );
39
40            if context.is_null() {
41                None
42            } else {
43                Some(FormatContext {
44                    _format_ctx: context,
45                })
46            }
47        }
48    }
49
50    pub fn open_input(url: &str) -> Option<Self> {
51        unsafe {
52            let mut context = core::ptr::null_mut::<libav_sys_ng::AVFormatContext>();
53
54            let url_c = CString::new(url).unwrap();
55
56            // TODO: Manage InputFormat and Options arguments.
57            let result = avformat_open_input(
58                &mut context,
59                url_c.as_ptr(),
60                core::ptr::null(),
61                core::ptr::null_mut(),
62            );
63
64            if result < 0 {
65                None
66            } else {
67                Some(FormatContext {
68                    _format_ctx: context,
69                })
70            }
71        }
72    }
73
74    pub fn find_stream_info(&self) -> i32 {
75        unsafe { avformat_find_stream_info(self._format_ctx, core::ptr::null_mut()) }
76    }
77
78    pub unsafe fn get_input_format(&self) -> *const AVInputFormat {
79        (*self._format_ctx).iformat
80    }
81
82    pub fn get_output_format(&self) -> &AVOutputFormat {
83        unsafe {
84            &*(*self._format_ctx).oformat as &AVOutputFormat
85        }
86    }
87
88    pub unsafe fn raw(&self) -> &AVFormatContext {
89        &*self._format_ctx
90    }
91
92    pub unsafe fn raw_mut(&mut self) -> &mut AVFormatContext {
93        &mut *self._format_ctx
94    }
95
96    pub fn dump(&self, index: i32, url: &str, is_output: bool) {
97        unsafe {
98            let raw_url = CString::new(url).expect("CString::new(url) failed");
99
100            av_dump_format(self._format_ctx, index, raw_url.as_ptr(), is_output as i32)
101        }
102    }
103
104    pub fn open(&mut self, url: &str, flags: i32) -> Result<(), i32> {
105        unsafe {
106            let raw_url = CString::new(url).expect("CString::new(url) failed");
107
108            let x = avio_open(&mut (*self._format_ctx).pb, raw_url.as_ptr(), flags);
109
110            if x < 0 {
111                return Err(x);
112            }
113        }
114
115        Ok(())
116    }
117
118    pub fn write_header(&mut self, options: Option<&mut Dictionary>) -> Result<(), i32> {
119        unsafe {
120            let raw_options = match options {
121                Some(op) => &mut op.raw(),
122                None => core::ptr::null_mut(),
123            };
124
125            let code = avformat_write_header(self._format_ctx, raw_options);
126
127            if code < 0 {
128                return Err(code);
129            }
130        }
131
132        Ok(())
133    }
134
135    pub fn seek_ts(&mut self, stream_idx: i32, timestamp: i64) -> i32 {
136        unsafe { av_seek_frame(self._format_ctx, stream_idx, timestamp, 0) }
137    }
138
139    pub fn seek_msec(&mut self, stream_idx: i32, msec: i64) -> i32 {
140        let tm = match self.streams().nth(stream_idx as _) {
141            Some(st) => st.time_base(),
142            None => return -1,
143        };
144
145        self.seek_ts(
146            stream_idx,
147            (msec as f64 * (tm.den as f64 / tm.num as f64) / 1000.0).floor() as _,
148        )
149    }
150
151    pub fn read_frame(&mut self, packet: &mut Packet) -> i32 {
152        unsafe { av_read_frame(self._format_ctx, packet.raw_mut()) }
153    }
154
155    pub fn write_frame(&mut self, packet: &mut Packet) -> i32 {
156        unsafe { av_write_frame(self._format_ctx, packet.raw_mut()) }
157    }
158
159    pub fn streams(&mut self) -> FormatStreamsIter<'_> {
160        FormatStreamsIter::new(self)
161    }
162
163    pub fn write_trailer(&mut self) {
164        unsafe { av_write_trailer(self._format_ctx) };
165    }
166}
167
168impl Drop for FormatContext {
169    fn drop(&mut self) {
170        unsafe {
171            avformat_free_context(self._format_ctx);
172        }
173    }
174}