Skip to main content

ffmpeg_next/format/context/
output.rs

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 = url.map(|u| 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}