playa_ffmpeg/format/context/
output.rs1use std::{
2 ffi::CString,
3 mem::size_of,
4 ops::{Deref, DerefMut},
5 ptr,
6};
7
8use libc;
9
10use super::{common::Context, destructor};
11use crate::{ChapterMut, Dictionary, Error, Rational, StreamMut, codec, codec::traits, ffi::*, format};
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 { ptr, ctx: unsafe { Context::wrap(ptr, destructor::Mode::Output) } }
23 }
24
25 pub unsafe fn as_ptr(&self) -> *const AVFormatContext {
26 self.ptr as *const _
27 }
28
29 pub unsafe fn as_mut_ptr(&mut self) -> *mut AVFormatContext {
30 self.ptr
31 }
32}
33
34impl Output {
35 pub fn format(&self) -> format::Output {
36 #[allow(clippy::unnecessary_cast)]
38 unsafe {
39 format::Output::wrap((*self.as_ptr()).oformat as *mut AVOutputFormat)
40 }
41 }
42
43 pub fn write_header(&mut self) -> Result<(), Error> {
44 unsafe {
45 match avformat_write_header(self.as_mut_ptr(), ptr::null_mut()) {
46 0 => Ok(()),
47 e => Err(Error::from(e)),
48 }
49 }
50 }
51
52 pub fn write_header_with(&mut self, options: Dictionary) -> Result<Dictionary<'_>, Error> {
53 unsafe {
54 let mut opts = options.disown();
55 let res = avformat_write_header(self.as_mut_ptr(), &mut opts);
56
57 match res {
58 0 => Ok(Dictionary::own(opts)),
59 e => Err(Error::from(e)),
60 }
61 }
62 }
63
64 pub fn write_trailer(&mut self) -> Result<(), Error> {
65 unsafe {
66 match av_write_trailer(self.as_mut_ptr()) {
67 0 => Ok(()),
68 e => Err(Error::from(e)),
69 }
70 }
71 }
72
73 pub fn add_stream<E: traits::Encoder>(&mut self, codec: E) -> Result<StreamMut<'_>, Error> {
74 unsafe {
75 let codec = codec.encoder();
76 let codec = codec.map_or(ptr::null(), |c| c.as_ptr());
77 let ptr = avformat_new_stream(self.as_mut_ptr(), codec);
78
79 if ptr.is_null() {
80 return Err(Error::Unknown);
81 }
82
83 let index = (*self.ctx.as_ptr()).nb_streams - 1;
84
85 Ok(StreamMut::wrap(&mut self.ctx, index as usize))
86 }
87 }
88
89 pub fn add_stream_with(&mut self, context: &codec::Context) -> Result<StreamMut<'_>, Error> {
90 unsafe {
91 let ptr = avformat_new_stream(self.as_mut_ptr(), ptr::null());
92
93 if ptr.is_null() {
94 return Err(Error::Unknown);
95 }
96
97 match avcodec_parameters_from_context((*ptr).codecpar, context.as_ptr()) {
98 0 => (),
99 e => return Err(Error::from(e)),
100 }
101
102 let index = (*self.ctx.as_ptr()).nb_streams - 1;
103
104 Ok(StreamMut::wrap(&mut self.ctx, index as usize))
105 }
106 }
107
108 pub fn add_chapter<R: Into<Rational>, S: AsRef<str>>(&mut self, id: i64, time_base: R, start: i64, end: i64, title: S) -> Result<ChapterMut<'_>, Error> {
109 if start > end {
112 return Err(Error::InvalidData);
113 }
114
115 let mut existing = None;
116 for chapter in self.chapters() {
117 if chapter.id() == id {
118 existing = Some(chapter.index());
119 break;
120 }
121 }
122
123 let index = match existing {
124 Some(index) => index,
125 None => unsafe {
126 let ptr = av_mallocz(size_of::<AVChapter>()).as_mut().ok_or(Error::Bug)?;
127 let mut nb_chapters = (*self.as_ptr()).nb_chapters as i32;
128
129 av_dynarray_add(&mut (*self.as_mut_ptr()).chapters as *mut _ as *mut libc::c_void, &mut nb_chapters, ptr);
131
132 if nb_chapters > 0 {
133 (*self.as_mut_ptr()).nb_chapters = nb_chapters as u32;
134 let index = (*self.ctx.as_ptr()).nb_chapters - 1;
135 index as usize
136 } else {
137 av_freep(ptr);
139 return Err(Error::Bug);
140 }
141 },
142 };
143
144 let mut chapter = self.chapter_mut(index).ok_or(Error::Bug)?;
145
146 chapter.set_id(id);
147 chapter.set_time_base(time_base);
148 chapter.set_start(start);
149 chapter.set_end(end);
150 chapter.set_metadata("title", title);
151
152 Ok(chapter)
153 }
154
155 pub fn set_metadata(&mut self, dictionary: Dictionary) {
156 unsafe {
157 (*self.as_mut_ptr()).metadata = dictionary.disown();
158 }
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(ctx.as_ptr() as *mut _, index, url.unwrap_or_else(|| CString::new("").unwrap()).as_ptr(), 1);
181 }
182}