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 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}