use crate::av::as_ptr::{AsMutPtr, AsPtr}; use crate::av::decoder::Decoder; use crate::av::encoder::Encoder; use crate::av::frame::Frame; use crate::av::verify_response; use crate::av::xcoder::XCoder; use ffmpeg_sys_next::{sws_freeContext, sws_getContext, sws_scale, AVPixelFormat, SwsContext}; use std::os::raw::c_int; use std::ptr::null_mut; #[derive(Debug)] pub struct Scaler { pub ctx: *mut SwsContext, flags: c_int, input: VideoInfo, output: VideoInfo, pass_through: bool, } #[derive(Eq, PartialEq, Debug)] struct VideoInfo { width: i32, height: i32, pixel_format: AVPixelFormat, } impl Scaler { pub fn new( from_pixel_format: AVPixelFormat, from_width: i32, from_height: i32, to_pixel_format: AVPixelFormat, to_width: i32, to_height: i32, flags: c_int, ) -> Scaler { unsafe { let ptr = sws_getContext( from_width, from_height, from_pixel_format, to_width, to_height, to_pixel_format, flags, null_mut(), null_mut(), null_mut(), ); let input = VideoInfo { width: from_width, height: from_height, pixel_format: from_pixel_format, }; let output = VideoInfo { width: to_width, height: to_height, pixel_format: to_pixel_format, }; Scaler { ctx: ptr, pass_through: input.eq(&output), flags, input, output, } } } pub fn from_coder(decoder: &Decoder, encoder: &Encoder, flags: i32) -> Scaler { Scaler::new( decoder.pixel_format(), decoder.width(), decoder.height(), encoder.pixel_format(), encoder.width(), encoder.height(), flags, ) } pub fn scale(&mut self, input: Frame) -> Result { if self.input.pixel_format != input.pixel_format() || self.input.width != input.width() || self.input.height != input.height() { self.input = VideoInfo { pixel_format: input.pixel_format(), width: input.width(), height: input.height(), }; self.pass_through = self.input == self.output; if !self.pass_through { unsafe { self.ctx = sws_getContext( self.input.width, self.input.height, self.input.pixel_format, self.output.width, self.output.height, self.output.pixel_format, self.flags, null_mut(), null_mut(), null_mut(), ); } } } if self.pass_through { return Ok(input); } let mut frame = Frame::alloc(); frame.allocate_video( self.output.pixel_format, self.output.width, self.output.height, )?; verify_response("Failed to scale frame", unsafe { sws_scale( self.as_mut_ptr(), (*input.as_ptr()).data.as_ptr() as *const *const _, (*input.as_mut_ptr()).linesize.as_ptr() as *const _, 0, self.input.height, (*frame.as_mut_ptr()).data.as_ptr() as *const *mut _, (*frame.as_mut_ptr()).linesize.as_ptr() as *mut _, ) })?; Ok(frame) } } impl AsPtr for Scaler { fn as_ptr(&self) -> *const SwsContext { self.ctx } } impl AsMutPtr for Scaler { fn as_mut_ptr(&self) -> *mut SwsContext { self.ctx } } impl Drop for Scaler { fn drop(&mut self) { unsafe { sws_freeContext(self.as_mut_ptr()) } } }