Skip to main content

ffmpeg_next/codec/
context.rs

1use std::any::Any;
2use std::ptr;
3use std::sync::Arc;
4
5use super::decoder::Decoder;
6use super::encoder::Encoder;
7use super::{Compliance, Debug, Flags, Id, Parameters, threading};
8use crate::ffi::*;
9use crate::media;
10use crate::{Codec, Error, Rational};
11use libc::c_int;
12
13pub struct Context {
14    ptr: *mut AVCodecContext,
15    owner: Option<Arc<dyn Any + Send + Sync>>,
16}
17
18// SAFETY: the context either owns its `AVCodecContext` or keeps its owner
19// alive through an atomically refcounted, thread-safe handle.
20unsafe impl Send for Context {}
21
22impl Context {
23    pub unsafe fn wrap(
24        ptr: *mut AVCodecContext,
25        owner: Option<Arc<dyn Any + Send + Sync>>,
26    ) -> Self {
27        Context { ptr, owner }
28    }
29
30    pub unsafe fn as_ptr(&self) -> *const AVCodecContext {
31        self.ptr as *const _
32    }
33
34    pub unsafe fn as_mut_ptr(&mut self) -> *mut AVCodecContext {
35        self.ptr
36    }
37}
38
39impl Context {
40    pub fn new() -> Self {
41        unsafe {
42            Context {
43                ptr: avcodec_alloc_context3(ptr::null()),
44                owner: None,
45            }
46        }
47    }
48
49    pub fn new_with_codec(codec: Codec) -> Self {
50        unsafe {
51            Context {
52                ptr: avcodec_alloc_context3(codec.as_ptr()),
53                owner: None,
54            }
55        }
56    }
57
58    pub fn from_parameters<P: Into<Parameters>>(parameters: P) -> Result<Self, Error> {
59        let parameters = parameters.into();
60        let mut context = Self::new();
61
62        unsafe {
63            match avcodec_parameters_to_context(context.as_mut_ptr(), parameters.as_ptr()) {
64                e if e < 0 => Err(Error::from(e)),
65                _ => Ok(context),
66            }
67        }
68    }
69
70    pub fn decoder(self) -> Decoder {
71        Decoder(self)
72    }
73
74    pub fn encoder(self) -> Encoder {
75        Encoder(self)
76    }
77
78    pub fn codec(&self) -> Option<Codec> {
79        unsafe {
80            if (*self.as_ptr()).codec.is_null() {
81                None
82            } else {
83                Some(Codec::wrap((*self.as_ptr()).codec as *mut _))
84            }
85        }
86    }
87
88    pub fn medium(&self) -> media::Type {
89        unsafe { media::Type::from((*self.as_ptr()).codec_type) }
90    }
91
92    pub fn set_flags(&mut self, value: Flags) {
93        unsafe {
94            (*self.as_mut_ptr()).flags = value.bits() as c_int;
95        }
96    }
97
98    pub fn id(&self) -> Id {
99        unsafe { Id::from((*self.as_ptr()).codec_id) }
100    }
101
102    pub fn compliance(&mut self, value: Compliance) {
103        unsafe {
104            (*self.as_mut_ptr()).strict_std_compliance = value.into();
105        }
106    }
107
108    pub fn debug(&mut self, value: Debug) {
109        unsafe {
110            (*self.as_mut_ptr()).debug = value.bits();
111        }
112    }
113
114    pub fn set_threading(&mut self, config: threading::Config) {
115        unsafe {
116            (*self.as_mut_ptr()).thread_type = config.kind.into();
117            (*self.as_mut_ptr()).thread_count = config.count as c_int;
118            #[cfg(not(feature = "ffmpeg_6_0"))]
119            {
120                (*self.as_mut_ptr()).thread_safe_callbacks = if config.safe { 1 } else { 0 };
121            }
122        }
123    }
124
125    pub fn threading(&self) -> threading::Config {
126        unsafe {
127            threading::Config {
128                kind: threading::Type::from((*self.as_ptr()).active_thread_type),
129                count: (*self.as_ptr()).thread_count as usize,
130                #[cfg(not(feature = "ffmpeg_6_0"))]
131                safe: (*self.as_ptr()).thread_safe_callbacks != 0,
132            }
133        }
134    }
135
136    pub fn set_parameters<P: Into<Parameters>>(&mut self, parameters: P) -> Result<(), Error> {
137        let parameters = parameters.into();
138
139        unsafe {
140            match avcodec_parameters_to_context(self.as_mut_ptr(), parameters.as_ptr()) {
141                e if e < 0 => Err(Error::from(e)),
142                _ => Ok(()),
143            }
144        }
145    }
146
147    pub fn time_base(&self) -> Rational {
148        unsafe { Rational::from((*self.as_ptr()).time_base) }
149    }
150
151    pub fn set_time_base<R: Into<Rational>>(&mut self, value: R) {
152        unsafe {
153            (*self.as_mut_ptr()).time_base = value.into().into();
154        }
155    }
156
157    pub fn frame_rate(&self) -> Rational {
158        unsafe { Rational::from((*self.as_ptr()).framerate) }
159    }
160
161    pub fn set_frame_rate<R: Into<Rational>>(&mut self, value: Option<R>) {
162        unsafe {
163            if let Some(value) = value {
164                (*self.as_mut_ptr()).framerate = value.into().into();
165            } else {
166                (*self.as_mut_ptr()).framerate.num = 0;
167                (*self.as_mut_ptr()).framerate.den = 1;
168            }
169        }
170    }
171}
172
173impl Default for Context {
174    fn default() -> Self {
175        Self::new()
176    }
177}
178
179impl Drop for Context {
180    fn drop(&mut self) {
181        unsafe {
182            if self.owner.is_none() {
183                avcodec_free_context(&mut self.as_mut_ptr());
184            }
185        }
186    }
187}
188
189#[cfg(not(feature = "ffmpeg_5_0"))]
190impl Clone for Context {
191    fn clone(&self) -> Self {
192        let mut ctx = Context::new();
193        ctx.clone_from(self);
194
195        ctx
196    }
197
198    fn clone_from(&mut self, source: &Self) {
199        unsafe {
200            // Removed in ffmpeg >= 5.0.
201            avcodec_copy_context(self.as_mut_ptr(), source.as_ptr());
202        }
203    }
204}