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}