ffmpeg_the_third/codec/
context.rs1use std::ptr;
2
3use super::decoder::Decoder;
4use super::encoder::Encoder;
5use super::{threading, Compliance, Debug, Flags, Id};
6use crate::ffi::*;
7use crate::media;
8use crate::option;
9use crate::{AsMutPtr, AsPtr};
10use crate::{Codec, Error};
11use libc::c_int;
12
13#[cfg(not(feature = "ffmpeg_5_0"))]
14type OwnerHolder = std::sync::Arc<dyn std::any::Any>;
15#[cfg(feature = "ffmpeg_5_0")]
16type OwnerHolder = ();
17
18pub struct Context {
19 ptr: *mut AVCodecContext,
20 owner: Option<OwnerHolder>,
21}
22
23unsafe impl Send for Context {}
24
25impl Context {
26 pub unsafe fn wrap(ptr: *mut AVCodecContext, owner: Option<OwnerHolder>) -> 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: AsPtr<AVCodecParameters>>(parameters: P) -> Result<Self, Error> {
59 let mut context = Self::new();
60
61 unsafe {
62 match avcodec_parameters_to_context(context.as_mut_ptr(), parameters.as_ptr()) {
63 e if e < 0 => Err(Error::from(e)),
64 _ => Ok(context),
65 }
66 }
67 }
68
69 pub fn decoder(self) -> Decoder {
70 Decoder(self)
71 }
72
73 pub fn encoder(self) -> Encoder {
74 Encoder(self)
75 }
76
77 pub fn codec(&self) -> Option<Codec> {
78 unsafe { Codec::from_raw((*self.as_ptr()).codec) }
79 }
80
81 pub fn medium(&self) -> media::Type {
82 unsafe { media::Type::from((*self.as_ptr()).codec_type) }
83 }
84
85 pub fn set_flags(&mut self, value: Flags) {
86 unsafe {
87 (*self.as_mut_ptr()).flags = value.bits() as c_int;
88 }
89 }
90
91 pub fn id(&self) -> Id {
92 unsafe { Id::from((*self.as_ptr()).codec_id) }
93 }
94
95 pub fn compliance(&mut self, value: Compliance) {
96 unsafe {
97 (*self.as_mut_ptr()).strict_std_compliance = value.into();
98 }
99 }
100
101 pub fn debug(&mut self, value: Debug) {
102 unsafe {
103 (*self.as_mut_ptr()).debug = value.bits();
104 }
105 }
106
107 pub fn set_threading(&mut self, config: threading::Config) {
108 unsafe {
109 (*self.as_mut_ptr()).thread_type = config.kind.into();
110 (*self.as_mut_ptr()).thread_count = config.count as c_int;
111 #[cfg(not(feature = "ffmpeg_6_0"))]
112 {
113 (*self.as_mut_ptr()).thread_safe_callbacks = i32::from(config.safe);
114 }
115 }
116 }
117
118 pub fn threading(&self) -> threading::Config {
119 unsafe {
120 threading::Config {
121 kind: threading::Type::from((*self.as_ptr()).active_thread_type),
122 count: (*self.as_ptr()).thread_count as usize,
123 #[cfg(not(feature = "ffmpeg_6_0"))]
124 safe: (*self.as_ptr()).thread_safe_callbacks != 0,
125 }
126 }
127 }
128
129 pub fn set_parameters<P: AsPtr<AVCodecParameters>>(
130 &mut self,
131 parameters: P,
132 ) -> Result<(), Error> {
133 unsafe {
134 match avcodec_parameters_to_context(self.as_mut_ptr(), parameters.as_ptr()) {
135 e if e < 0 => Err(Error::from(e)),
136 _ => Ok(()),
137 }
138 }
139 }
140}
141
142impl Default for Context {
143 fn default() -> Self {
144 Self::new()
145 }
146}
147
148impl Drop for Context {
149 fn drop(&mut self) {
150 unsafe {
151 if self.owner.is_none() {
152 avcodec_free_context(&mut self.ptr);
153 }
154 }
155 }
156}
157
158#[cfg(not(feature = "ffmpeg_5_0"))]
159impl Clone for Context {
160 fn clone(&self) -> Self {
161 let mut ctx = Context::new();
162 ctx.clone_from(self);
163
164 ctx
165 }
166
167 fn clone_from(&mut self, source: &Self) {
168 unsafe {
169 avcodec_copy_context(self.as_mut_ptr(), source.as_ptr());
171 }
172 }
173}
174
175impl AsPtr<AVCodecContext> for Context {
177 fn as_ptr(&self) -> *const AVCodecContext {
178 self.ptr as *const _
179 }
180}
181
182impl AsMutPtr<AVCodecContext> for Context {
183 fn as_mut_ptr(&mut self) -> *mut AVCodecContext {
184 self.ptr as *mut _
185 }
186}
187
188impl option::Settable<AVCodecContext> for Context {}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193 use crate::codec::{decoder, Id};
194
195 #[test]
198 fn open_and_drop_pgs_decoder_does_not_segfault() {
199 let pgs = decoder::find(Id::HDMV_PGS_SUBTITLE)
201 .expect("PGS decoder must be available in linked FFmpeg");
202
203 let ctx = Context::new();
204 let _opened = ctx.decoder().open_as(pgs).expect("can open PGS decoder");
205
206 }
208}