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