Skip to main content

lumen_ffmpeg/encode/
output.rs

1use std::ptr;
2
3use crate::ffi::{self, sys};
4use crate::{FfmpegError, Result};
5
6pub struct OutputContext {
7    path: String,
8    pub(crate) ptr: *mut sys::AVFormatContext,
9    opened_io: bool,
10}
11
12unsafe impl Send for OutputContext {}
13
14impl OutputContext {
15    pub fn create(path: impl Into<String>) -> Result<Self> {
16        ffi::init();
17        let path = path.into();
18        let c_path = ffi::cstring("avformat_alloc_output_context2", &path)?;
19        let mut ptr: *mut sys::AVFormatContext = ptr::null_mut();
20        unsafe {
21            ffi::check(
22                sys::avformat_alloc_output_context2(
23                    &mut ptr,
24                    ptr::null_mut(),
25                    ptr::null(),
26                    c_path.as_ptr(),
27                ),
28                "avformat_alloc_output_context2",
29            )
30            .map_err(|error| error.with_path(path.clone()))?;
31        }
32        if ptr.is_null() {
33            return Err(FfmpegError::new(
34                "avformat_alloc_output_context2",
35                "failed to allocate output context",
36            )
37            .with_path(path));
38        }
39        Ok(Self {
40            path,
41            ptr,
42            opened_io: false,
43        })
44    }
45
46    pub fn path(&self) -> &str {
47        &self.path
48    }
49
50    pub(crate) fn write_header(&mut self) -> Result<()> {
51        self.open_io()?;
52        unsafe {
53            ffi::check(
54                sys::avformat_write_header(self.ptr, ptr::null_mut()),
55                "avformat_write_header",
56            )
57            .map_err(|error| error.with_path(self.path.clone()))
58        }
59    }
60
61    pub(crate) fn write_trailer(&mut self) -> Result<()> {
62        unsafe {
63            ffi::check(sys::av_write_trailer(self.ptr), "av_write_trailer")
64                .map_err(|error| error.with_path(self.path.clone()))
65        }
66    }
67
68    fn open_io(&mut self) -> Result<()> {
69        unsafe {
70            if ((*(*self.ptr).oformat).flags & sys::AVFMT_NOFILE) == 0 {
71                let c_path = ffi::cstring("avio_open", &self.path)?;
72                ffi::check(
73                    sys::avio_open(&mut (*self.ptr).pb, c_path.as_ptr(), sys::AVIO_FLAG_WRITE),
74                    "avio_open",
75                )
76                .map_err(|error| error.with_path(self.path.clone()))?;
77                self.opened_io = true;
78            }
79        }
80        Ok(())
81    }
82}
83
84impl Drop for OutputContext {
85    fn drop(&mut self) {
86        unsafe {
87            if self.opened_io && !(*self.ptr).pb.is_null() {
88                sys::avio_closep(&mut (*self.ptr).pb);
89            }
90            sys::avformat_free_context(self.ptr);
91        }
92    }
93}