ffmpeg_the_third/software/scaling/
context.rs

1use std::ptr;
2
3use super::Flags;
4use crate::ffi::*;
5use crate::util::format;
6use crate::{frame, Error};
7use libc::c_int;
8
9#[derive(Eq, PartialEq, Copy, Clone, Debug)]
10pub struct Definition {
11    pub format: format::Pixel,
12    pub width: u32,
13    pub height: u32,
14}
15
16pub struct Context {
17    ptr: *mut SwsContext,
18
19    input: Definition,
20    output: Definition,
21}
22
23impl Context {
24    #[inline(always)]
25    pub unsafe fn as_ptr(&self) -> *const SwsContext {
26        self.ptr as *const _
27    }
28
29    #[inline(always)]
30    pub unsafe fn as_mut_ptr(&mut self) -> *mut SwsContext {
31        self.ptr
32    }
33}
34
35impl Context {
36    pub fn get(
37        src_format: format::Pixel,
38        src_w: u32,
39        src_h: u32,
40        dst_format: format::Pixel,
41        dst_w: u32,
42        dst_h: u32,
43        flags: Flags,
44    ) -> Result<Self, Error> {
45        unsafe {
46            let ptr = sws_getContext(
47                src_w as c_int,
48                src_h as c_int,
49                src_format.into(),
50                dst_w as c_int,
51                dst_h as c_int,
52                dst_format.into(),
53                flags.bits(),
54                ptr::null_mut(),
55                ptr::null_mut(),
56                ptr::null_mut(),
57            );
58
59            if !ptr.is_null() {
60                Ok(Context {
61                    ptr,
62
63                    input: Definition {
64                        format: src_format,
65                        width: src_w,
66                        height: src_h,
67                    },
68
69                    output: Definition {
70                        format: dst_format,
71                        width: dst_w,
72                        height: dst_h,
73                    },
74                })
75            } else {
76                Err(Error::InvalidData)
77            }
78        }
79    }
80
81    #[allow(clippy::too_many_arguments)]
82    pub fn cached(
83        &mut self,
84        src_format: format::Pixel,
85        src_w: u32,
86        src_h: u32,
87        dst_format: format::Pixel,
88        dst_w: u32,
89        dst_h: u32,
90        flags: Flags,
91    ) {
92        self.input = Definition {
93            format: src_format,
94            width: src_w,
95            height: src_h,
96        };
97
98        self.output = Definition {
99            format: dst_format,
100            width: dst_w,
101            height: dst_h,
102        };
103
104        unsafe {
105            self.ptr = sws_getCachedContext(
106                self.as_mut_ptr(),
107                src_w as c_int,
108                src_h as c_int,
109                src_format.into(),
110                dst_w as c_int,
111                dst_h as c_int,
112                dst_format.into(),
113                flags.bits(),
114                ptr::null_mut(),
115                ptr::null_mut(),
116                ptr::null(),
117            );
118        }
119    }
120
121    #[inline]
122    pub fn input(&self) -> &Definition {
123        &self.input
124    }
125
126    #[inline]
127    pub fn output(&self) -> &Definition {
128        &self.output
129    }
130
131    pub fn run(&mut self, input: &frame::Video, output: &mut frame::Video) -> Result<(), Error> {
132        if input.format() != self.input.format
133            || input.width() != self.input.width
134            || input.height() != self.input.height
135        {
136            return Err(Error::InputChanged);
137        }
138
139        unsafe {
140            if output.is_empty() {
141                output.alloc(self.output.format, self.output.width, self.output.height);
142            }
143        }
144
145        if output.format() != self.output.format
146            || output.width() != self.output.width
147            || output.height() != self.output.height
148        {
149            return Err(Error::OutputChanged);
150        }
151
152        unsafe {
153            sws_scale(
154                self.as_mut_ptr(),
155                (*input.as_ptr()).data.as_ptr() as *const *const _,
156                (*input.as_ptr()).linesize.as_ptr() as *const _,
157                0,
158                self.input.height as c_int,
159                (*output.as_mut_ptr()).data.as_ptr() as *const *mut _,
160                (*output.as_mut_ptr()).linesize.as_ptr() as *mut _,
161            );
162        }
163
164        Ok(())
165    }
166}
167
168impl Drop for Context {
169    fn drop(&mut self) {
170        unsafe {
171            sws_freeContext(self.as_mut_ptr());
172        }
173    }
174}