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