Skip to main content

ffmpeg_the_third/format/context/
output.rs

1use 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        // avpriv_new_chapter is private (libavformat/internal.h)
102
103        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                // chapters array will be freed by `avformat_free_context`
124                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                    // failed to add the chapter
136                    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}