1use 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 codec::traits;
11use ffi::*;
12use {codec, format, ChapterMut, Dictionary, Error, Rational, StreamMut};
13
14pub struct Output {
15 ptr: *mut AVFormatContext,
16 ctx: Context,
17}
18
19unsafe impl Send for Output {}
20
21impl Output {
22 pub unsafe fn wrap(ptr: *mut AVFormatContext) -> Self {
23 Output {
24 ptr,
25 ctx: Context::wrap(ptr, destructor::Mode::Output),
26 }
27 }
28
29 pub unsafe fn as_ptr(&self) -> *const AVFormatContext {
30 self.ptr as *const _
31 }
32
33 pub unsafe fn as_mut_ptr(&mut self) -> *mut AVFormatContext {
34 self.ptr
35 }
36}
37
38impl Output {
39 pub fn format(&self) -> format::Output {
40 // We get a clippy warning in 4.4 but not in 5.0 and newer, so we allow that cast to not complicate the code
41 #[allow(clippy::unnecessary_cast)]
42 unsafe {
43 format::Output::wrap((*self.as_ptr()).oformat as *mut AVOutputFormat)
44 }
45 }
46
47 pub fn write_header(&mut self) -> Result<(), Error> {
48 unsafe {
49 match avformat_write_header(self.as_mut_ptr(), ptr::null_mut()) {
50 0 => Ok(()),
51 e => Err(Error::from(e)),
52 }
53 }
54 }
55
56 pub fn write_header_with(&mut self, options: Dictionary) -> Result<Dictionary, Error> {
57 unsafe {
58 let mut opts = options.disown();
59 let res = avformat_write_header(self.as_mut_ptr(), &mut opts);
60
61 match res {
62 0 => Ok(Dictionary::own(opts)),
63 e => Err(Error::from(e)),
64 }
65 }
66 }
67
68 pub fn write_trailer(&mut self) -> Result<(), Error> {
69 unsafe {
70 match av_write_trailer(self.as_mut_ptr()) {
71 0 => Ok(()),
72 e => Err(Error::from(e)),
73 }
74 }
75 }
76
77 pub fn add_stream<E: traits::Encoder>(&mut self, codec: E) -> 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_stream_with(&mut self, context: &codec::Context) -> Result<StreamMut, Error> {
94 unsafe {
95 let ptr = avformat_new_stream(self.as_mut_ptr(), ptr::null());
96
97 if ptr.is_null() {
98 return Err(Error::Unknown);
99 }
100
101 match avcodec_parameters_from_context((*ptr).codecpar, context.as_ptr()) {
102 0 => (),
103 e => return Err(Error::from(e)),
104 }
105
106 let index = (*self.ctx.as_ptr()).nb_streams - 1;
107
108 Ok(StreamMut::wrap(&mut self.ctx, index as usize))
109 }
110 }
111
112 pub fn add_chapter<R: Into<Rational>, S: AsRef<str>>(
113 &mut self,
114 id: i64,
115 time_base: R,
116 start: i64,
117 end: i64,
118 title: S,
119 ) -> Result<ChapterMut, Error> {
120 // avpriv_new_chapter is private (libavformat/internal.h)
121
122 if start > end {
123 return Err(Error::InvalidData);
124 }
125
126 let mut existing = None;
127 for chapter in self.chapters() {
128 if chapter.id() == id {
129 existing = Some(chapter.index());
130 break;
131 }
132 }
133
134 let index = match existing {
135 Some(index) => index,
136 None => unsafe {
137 let ptr = av_mallocz(size_of::<AVChapter>())
138 .as_mut()
139 .ok_or(Error::Bug)?;
140 let mut nb_chapters = (*self.as_ptr()).nb_chapters as i32;
141
142 // chapters array will be freed by `avformat_free_context`
143 av_dynarray_add(
144 &mut (*self.as_mut_ptr()).chapters as *mut _ as *mut libc::c_void,
145 &mut nb_chapters,
146 ptr,
147 );
148
149 if nb_chapters > 0 {
150 (*self.as_mut_ptr()).nb_chapters = nb_chapters as u32;
151 let index = (*self.ctx.as_ptr()).nb_chapters - 1;
152 index as usize
153 } else {
154 // failed to add the chapter
155 av_freep(ptr);
156 return Err(Error::Bug);
157 }
158 },
159 };
160
161 let mut chapter = self.chapter_mut(index).ok_or(Error::Bug)?;
162
163 chapter.set_id(id);
164 chapter.set_time_base(time_base);
165 chapter.set_start(start);
166 chapter.set_end(end);
167 chapter.set_metadata("title", title);
168
169 Ok(chapter)
170 }
171
172 pub fn set_metadata(&mut self, dictionary: Dictionary) {
173 unsafe {
174 (*self.as_mut_ptr()).metadata = dictionary.disown();
175 }
176 }
177}
178
179impl Deref for Output {
180 type Target = Context;
181
182 fn deref(&self) -> &Self::Target {
183 &self.ctx
184 }
185}
186
187impl DerefMut for Output {
188 fn deref_mut(&mut self) -> &mut Self::Target {
189 &mut self.ctx
190 }
191}
192
193pub fn dump(ctx: &Output, index: i32, url: Option<&str>) {
194 let url: Option = url.map(|u: &str| CString::new(u).unwrap());
195
196 unsafe {
197 av_dump_format(
198 ctx.as_ptr() as *mut _,
199 index,
200 url.unwrap_or_else(|| CString::new("").unwrap()).as_ptr(),
201 1,
202 );
203 }
204}
205