Skip to main content

ffmpeg_next/format/context/
destructor.rs

1use super::StreamIo;
2use crate::ffi::*;
3use crate::util::interrupt::InterruptGuard;
4
5#[derive(Debug)]
6pub enum Mode {
7    Input,
8    Output,
9    InputCustomIo(StreamIo),
10    OutputCustomIo(StreamIo),
11}
12
13pub struct Destructor {
14    ptr: *mut AVFormatContext,
15    mode: Mode,
16    // Keep-alive for a boxed `AVIOInterruptCB` closure installed on the  context.
17    // Never read directly - its only job is to run `InterruptGuard::drop` at the
18    // right time (freeing the boxed closure), which the field's own drop does.
19    #[allow(dead_code)]
20    interrupt_guard: Option<InterruptGuard>,
21}
22
23impl Destructor {
24    pub unsafe fn new(ptr: *mut AVFormatContext, mode: Mode) -> Self {
25        Destructor {
26            ptr,
27            mode,
28            interrupt_guard: None,
29        }
30    }
31
32    pub unsafe fn new_with_interrupt(
33        ptr: *mut AVFormatContext,
34        mode: Mode,
35        guard: InterruptGuard,
36    ) -> Self {
37        Destructor {
38            ptr,
39            mode,
40            interrupt_guard: Some(guard),
41        }
42    }
43}
44
45// SAFETY: `Destructor` owns the `AVFormatContext` and, in the custom-IO
46// modes, the `StreamIo` keep-alive (itself `Send`). `Drop` runs exactly once,
47// with exclusive ownership, on whichever thread releases the last `Arc`;
48// closing the context and dropping the `StreamIo` (which flushes the user
49// stream) are safe from any thread because `StreamIo` and the wrapped stream
50// are `Send` — hence `Send`. There are no `&self` methods and the fields are
51// private, so a shared `&Destructor` gives another thread no way to touch the
52// pointer or the embedded (non-`Sync`) `StreamIo` — hence `Sync`.
53unsafe impl Send for Destructor {}
54unsafe impl Sync for Destructor {}
55
56impl Drop for Destructor {
57    fn drop(&mut self) {
58        unsafe {
59            match self.mode {
60                Mode::InputCustomIo(_) => {
61                    // AVFMT_FLAG_CUSTOM_IO is set, so this leaves `pb` alone
62                    // (demuxers' read_close() may still use it); the StreamIo
63                    // in `mode` frees it when dropped after this body.
64                    avformat_close_input(&mut self.ptr);
65                }
66                Mode::OutputCustomIo(_) => {
67                    avformat_free_context(self.ptr);
68                    // The StreamIo in `mode` is dropped afterwards; its Drop
69                    // flushes buffered data to the stream before freeing the
70                    // AVIOContext.
71                }
72                Mode::Input => avformat_close_input(&mut self.ptr),
73
74                Mode::Output => {
75                    avio_close((*self.ptr).pb);
76                    avformat_free_context(self.ptr);
77                }
78            }
79        }
80    }
81}