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(feature = "ffmpeg_8_1")]
14use crate::format::AlphaMode;
15
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 #[cfg(feature = "ffmpeg_8_1")]
108 pub fn alpha_mode(&self) -> AlphaMode {
109 unsafe { (*self.as_ptr()).alpha_mode.into() }
110 }
111
112 pub fn set_threading(&mut self, config: threading::Config) {
113 unsafe {
114 (*self.as_mut_ptr()).thread_type = config.kind.into();
115 (*self.as_mut_ptr()).thread_count = config.count as c_int;
116 #[cfg(not(feature = "ffmpeg_6_0"))]
117 {
118 (*self.as_mut_ptr()).thread_safe_callbacks = i32::from(config.safe);
119 }
120 }
121 }
122
123 pub fn threading(&self) -> threading::Config {
124 unsafe {
125 threading::Config {
126 kind: threading::Type::from((*self.as_ptr()).active_thread_type),
127 count: (*self.as_ptr()).thread_count as usize,
128 #[cfg(not(feature = "ffmpeg_6_0"))]
129 safe: (*self.as_ptr()).thread_safe_callbacks != 0,
130 }
131 }
132 }
133
134 pub fn set_parameters<P: AsPtr<AVCodecParameters>>(
135 &mut self,
136 parameters: P,
137 ) -> Result<(), Error> {
138 unsafe {
139 match avcodec_parameters_to_context(self.as_mut_ptr(), parameters.as_ptr()) {
140 e if e < 0 => Err(Error::from(e)),
141 _ => Ok(()),
142 }
143 }
144 }
145}
146
147impl Default for Context {
148 fn default() -> Self {
149 Self::new()
150 }
151}
152
153impl Drop for Context {
154 fn drop(&mut self) {
155 unsafe {
156 if self.owner.is_none() {
157 avcodec_free_context(&mut self.ptr);
158 }
159 }
160 }
161}
162
163impl AsPtr<AVCodecContext> for Context {
165 fn as_ptr(&self) -> *const AVCodecContext {
166 self.ptr as *const _
167 }
168}
169
170impl AsMutPtr<AVCodecContext> for Context {
171 fn as_mut_ptr(&mut self) -> *mut AVCodecContext {
172 self.ptr as *mut _
173 }
174}
175
176impl option::Settable<AVCodecContext> for Context {}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181 use crate::codec::{decoder, Id};
182
183 #[test]
186 fn open_and_drop_pgs_decoder_does_not_segfault() {
187 let pgs = decoder::find(Id::HDMV_PGS_SUBTITLE)
189 .expect("PGS decoder must be available in linked FFmpeg");
190
191 let ctx = Context::new();
192 let _opened = ctx.decoder().open_as(pgs).expect("can open PGS decoder");
193
194 }
196}