ffmpeg_the_third/format/context/
output.rs1use std::ffi::CString;
2use std::mem::size_of;
3use std::ops::{Deref, DerefMut};
4use std::ptr;
5
6use super::common::Context;
7use super::destructor;
8use crate::codec::traits;
9use crate::ffi::*;
10use crate::{format, ChapterMut, Dictionary, Error, Rational, StreamMut};
11
12pub struct Output {
13 ptr: *mut AVFormatContext,
14 ctx: Context,
15}
16
17unsafe impl Send for Output {}
18
19impl Output {
20 pub unsafe fn wrap(ptr: *mut AVFormatContext) -> Self {
21 Output {
22 ptr,
23 ctx: Context::wrap(ptr, destructor::Mode::Output),
24 }
25 }
26
27 pub unsafe fn as_ptr(&self) -> *const AVFormatContext {
28 self.ptr as *const _
29 }
30
31 pub unsafe fn as_mut_ptr(&mut self) -> *mut AVFormatContext {
32 self.ptr
33 }
34}
35
36impl Output {
37 pub fn format(&self) -> format::Output {
38 unsafe { format::Output::from_raw((*self.as_ptr()).oformat).expect("oformat is non-null") }
39 }
40
41 pub fn write_header(&mut self) -> Result<(), Error> {
42 unsafe {
43 match avformat_write_header(self.as_mut_ptr(), ptr::null_mut()) {
44 0 => Ok(()),
45 e => Err(Error::from(e)),
46 }
47 }
48 }
49
50 pub fn write_header_with(&mut self, options: Dictionary) -> Result<Dictionary<'_>, Error> {
51 unsafe {
52 let mut opts = options.disown();
53 let res = avformat_write_header(self.as_mut_ptr(), &mut opts);
54
55 match res {
56 0 => Ok(Dictionary::own(opts)),
57 e => Err(Error::from(e)),
58 }
59 }
60 }
61
62 pub fn write_trailer(&mut self) -> Result<(), Error> {
63 unsafe {
64 match av_write_trailer(self.as_mut_ptr()) {
65 0 => Ok(()),
66 e => Err(Error::from(e)),
67 }
68 }
69 }
70
71 pub fn add_stream<T, E: traits::Encoder<T>>(
72 &mut self,
73 codec: E,
74 ) -> Result<StreamMut<'_>, Error> {
75 unsafe {
76 let codec = codec.encoder();
77 let codec = codec.map_or(ptr::null(), |c| c.as_ptr());
78 let ptr = avformat_new_stream(self.as_mut_ptr(), codec);
79
80 if ptr.is_null() {
81 return Err(Error::Unknown);
82 }
83
84 let index = (*self.ctx.as_ptr()).nb_streams - 1;
85
86 Ok(StreamMut::wrap(&mut self.ctx, index as usize))
87 }
88 }
89
90 pub fn add_chapter<R: Into<Rational>, S: AsRef<str>>(
91 &mut self,
92 id: i64,
93 time_base: R,
94 start: i64,
95 end: i64,
96 title: S,
97 ) -> Result<ChapterMut<'_>, Error> {
98 if start > end {
101 return Err(Error::InvalidData);
102 }
103
104 let mut existing = None;
105 for chapter in self.chapters() {
106 if chapter.id() == id {
107 existing = Some(chapter.index());
108 break;
109 }
110 }
111
112 let index = match existing {
113 Some(index) => index,
114 None => unsafe {
115 let ptr = av_mallocz(size_of::<AVChapter>())
116 .as_mut()
117 .ok_or(Error::Bug)?;
118 let mut nb_chapters = (*self.as_ptr()).nb_chapters as i32;
119
120 av_dynarray_add(
122 &mut (*self.as_mut_ptr()).chapters as *mut _ as *mut libc::c_void,
123 &mut nb_chapters,
124 ptr,
125 );
126
127 if nb_chapters > 0 {
128 (*self.as_mut_ptr()).nb_chapters = nb_chapters as u32;
129 let index = (*self.ctx.as_ptr()).nb_chapters - 1;
130 index as usize
131 } else {
132 av_freep(ptr);
134 return Err(Error::Bug);
135 }
136 },
137 };
138
139 let mut chapter = self.chapter_mut(index).ok_or(Error::Bug)?;
140
141 chapter.set_id(id);
142 chapter.set_time_base(time_base);
143 chapter.set_start(start);
144 chapter.set_end(end);
145 chapter.set_metadata("title", title);
146
147 Ok(chapter)
148 }
149
150 pub fn set_metadata(&mut self, dictionary: Dictionary) {
151 unsafe {
152 (*self.as_mut_ptr()).metadata = dictionary.disown();
153 }
154 }
155}
156
157impl Deref for Output {
158 type Target = Context;
159
160 fn deref(&self) -> &Self::Target {
161 &self.ctx
162 }
163}
164
165impl DerefMut for Output {
166 fn deref_mut(&mut self) -> &mut Self::Target {
167 &mut self.ctx
168 }
169}
170
171pub fn dump(ctx: &Output, index: i32, url: Option<&str>) {
172 let url = url.map(|u| CString::new(u).unwrap());
173
174 unsafe {
175 av_dump_format(
176 ctx.as_ptr() as *mut _,
177 index,
178 url.unwrap_or_else(|| CString::new("").unwrap()).as_ptr(),
179 1,
180 );
181 }
182}