ffmpeg_next/format/context/
output.rs1use std::ffi::CString;
2use std::mem::size_of;
3use std::ops::{Deref, DerefMut};
4use std::ptr;
5
6use libc;
7
8use super::common::Context;
9use super::destructor;
10use crate::codec::traits;
11use crate::ffi::*;
12use crate::{ChapterMut, Dictionary, Error, Rational, StreamMut, codec, format};
13
14pub enum AvStreamInitStatus {
15 InWriteHeader,
17 InInitOutput,
19}
20
21pub struct Output {
22 ptr: *mut AVFormatContext,
23 ctx: Context,
24}
25
26unsafe impl Send for Output {}
27
28impl Output {
29 pub unsafe fn wrap(ptr: *mut AVFormatContext) -> Self {
30 unsafe {
31 Output {
32 ptr,
33 ctx: Context::wrap(ptr, destructor::Mode::Output),
34 }
35 }
36 }
37 pub unsafe fn wrap_with_custom_io(
38 ptr: *mut AVFormatContext,
39 custom_io: format::context::StreamIo,
40 ) -> Self {
41 unsafe {
42 Output {
43 ptr,
44 ctx: Context::wrap(ptr, destructor::Mode::OutputCustomIo(custom_io)),
45 }
46 }
47 }
48
49 pub unsafe fn as_ptr(&self) -> *const AVFormatContext {
50 self.ptr as *const _
51 }
52
53 pub unsafe fn as_mut_ptr(&mut self) -> *mut AVFormatContext {
54 self.ptr
55 }
56}
57
58impl Output {
59 pub fn format(&self) -> format::Output {
60 #[allow(clippy::unnecessary_cast)]
62 unsafe {
63 format::Output::wrap((*self.as_ptr()).oformat as *mut AVOutputFormat)
64 }
65 }
66
67 pub fn write_header(&mut self) -> Result<AvStreamInitStatus, Error> {
68 unsafe {
69 match avformat_write_header(self.as_mut_ptr(), ptr::null_mut()) {
70 0 => Ok(AvStreamInitStatus::InWriteHeader),
71 1 => Ok(AvStreamInitStatus::InInitOutput),
72 e => Err(Error::from(e)),
73 }
74 }
75 }
76
77 pub fn write_header_with(&mut self, options: Dictionary) -> Result<Dictionary<'_>, Error> {
78 unsafe {
79 let mut opts = options.disown();
80 let res = avformat_write_header(self.as_mut_ptr(), &mut opts);
81
82 let opts = Dictionary::own(opts);
83 match res {
84 0 => Ok(opts),
85 1 => Ok(opts),
86 e => Err(Error::from(e)),
87 }
88 }
89 }
90
91 pub fn write_trailer(&mut self) -> Result<(), Error> {
92 unsafe {
93 match av_write_trailer(self.as_mut_ptr()) {
98 e if e >= 0 => Ok(()),
99 e => Err(Error::from(e)),
100 }
101 }
102 }
103
104 pub fn add_stream<E: traits::Encoder>(&mut self, codec: E) -> Result<StreamMut<'_>, Error> {
105 unsafe {
106 let codec = codec.encoder();
107 let codec = codec.map_or(ptr::null(), |c| c.as_ptr());
108 let ptr = avformat_new_stream(self.as_mut_ptr(), codec);
109
110 if ptr.is_null() {
111 return Err(Error::Unknown);
112 }
113
114 let index = (*self.ctx.as_ptr()).nb_streams - 1;
115
116 Ok(StreamMut::wrap(&mut self.ctx, index as usize))
117 }
118 }
119
120 pub fn add_stream_with(&mut self, context: &codec::Context) -> Result<StreamMut<'_>, Error> {
121 unsafe {
122 let ptr = avformat_new_stream(self.as_mut_ptr(), ptr::null());
123
124 if ptr.is_null() {
125 return Err(Error::Unknown);
126 }
127
128 match avcodec_parameters_from_context((*ptr).codecpar, context.as_ptr()) {
129 0 => (),
130 e => return Err(Error::from(e)),
131 }
132
133 let index = (*self.ctx.as_ptr()).nb_streams - 1;
134
135 Ok(StreamMut::wrap(&mut self.ctx, index as usize))
136 }
137 }
138
139 pub fn add_chapter<R: Into<Rational>, S: AsRef<str>>(
140 &mut self,
141 id: i64,
142 time_base: R,
143 start: i64,
144 end: i64,
145 title: S,
146 ) -> Result<ChapterMut<'_>, Error> {
147 if start > end {
150 return Err(Error::InvalidData);
151 }
152
153 let mut existing = None;
154 for chapter in self.chapters() {
155 if chapter.id() == id {
156 existing = Some(chapter.index());
157 break;
158 }
159 }
160
161 let index = match existing {
162 Some(index) => index,
163 None => unsafe {
164 let ptr = av_mallocz(size_of::<AVChapter>())
165 .as_mut()
166 .ok_or(Error::Bug)?;
167 let mut nb_chapters = (*self.as_ptr()).nb_chapters as i32;
168
169 av_dynarray_add(
171 &mut (*self.as_mut_ptr()).chapters as *mut _ as *mut libc::c_void,
172 &mut nb_chapters,
173 ptr,
174 );
175
176 if nb_chapters > 0 {
177 (*self.as_mut_ptr()).nb_chapters = nb_chapters as u32;
178 let index = (*self.ctx.as_ptr()).nb_chapters - 1;
179 index as usize
180 } else {
181 av_freep(ptr);
183 return Err(Error::Bug);
184 }
185 },
186 };
187
188 let mut chapter = self.chapter_mut(index).ok_or(Error::Bug)?;
189
190 chapter.set_id(id);
191 chapter.set_time_base(time_base);
192 chapter.set_start(start);
193 chapter.set_end(end);
194 chapter.set_metadata("title", title);
195
196 Ok(chapter)
197 }
198
199 pub fn set_metadata(&mut self, dictionary: Dictionary) {
200 unsafe {
201 (*self.as_mut_ptr()).metadata = dictionary.disown();
202 }
203 }
204}
205
206impl Deref for Output {
207 type Target = Context;
208
209 fn deref(&self) -> &Self::Target {
210 &self.ctx
211 }
212}
213
214impl DerefMut for Output {
215 fn deref_mut(&mut self) -> &mut Self::Target {
216 &mut self.ctx
217 }
218}
219
220pub fn dump(ctx: &Output, index: i32, url: Option<&str>) {
221 let url = url.map(|u| CString::new(u).unwrap());
222
223 unsafe {
224 av_dump_format(
225 ctx.as_ptr() as *mut _,
226 index,
227 url.unwrap_or_else(|| CString::new("").unwrap()).as_ptr(),
228 1,
229 );
230 }
231}