|
|
|
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<Frame, String> {
|
|
|
|
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<SwsContext> for Scaler {
|
|
|
|
fn as_ptr(&self) -> *const SwsContext {
|
|
|
|
self.ctx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsMutPtr<SwsContext> 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()) }
|
|
|
|
}
|
|
|
|
}
|