software/scaling: add software scaling feature

This commit is contained in:
meh 2015-05-28 18:15:52 +02:00
parent 6c8a8f2edd
commit 8ceac13065
12 changed files with 485 additions and 9 deletions

View File

@ -5,16 +5,16 @@ authors = ["meh. <meh@schizofreni.co>"]
license = "WTFPL" license = "WTFPL"
[features] [features]
default = ["codec", "device", "filter", "format", "resample", "postprocessing", "software-resample", "software-scaling"] default = ["codec", "device", "filter", "format", "resampling", "postprocessing", "software-resampling", "software-scaling"]
codec = ["ffmpeg-sys/avcodec"] codec = ["ffmpeg-sys/avcodec"]
device = ["ffmpeg-sys/avdevice", "format"] device = ["ffmpeg-sys/avdevice", "format"]
filter = ["ffmpeg-sys/avfilter"] filter = ["ffmpeg-sys/avfilter"]
format = ["ffmpeg-sys/avformat", "codec"] format = ["ffmpeg-sys/avformat", "codec"]
resample = ["ffmpeg-sys/avresample"] resampling = ["ffmpeg-sys/avresample"]
postprocessing = ["ffmpeg-sys/postproc"] postprocessing = ["ffmpeg-sys/postproc"]
software-resample = ["ffmpeg-sys/swresample"] software-resampling = ["ffmpeg-sys/swresample"]
software-scaling = ["ffmpeg-sys/swscale"] software-scaling = ["ffmpeg-sys/swscale", "codec"]
[dependencies] [dependencies]
libc = "0.1" libc = "0.1"

View File

@ -47,6 +47,8 @@ pub use codec::threading;
#[cfg(feature = "device")] #[cfg(feature = "device")]
pub mod device; pub mod device;
pub mod software;
fn init_error() { fn init_error() {
util::error::register_all(); util::error::register_all();
} }

2
src/software/mod.rs Normal file
View File

@ -0,0 +1,2 @@
#[cfg(feature = "software-scaling")]
pub mod scaling;

View File

@ -0,0 +1,14 @@
use libc::c_uint;
use ffi::*;
bitflags! {
flags Capabilities: c_uint {
const MMX = SWS_CPU_CAPS_MMX,
const MMXEXT = SWS_CPU_CAPS_MMXEXT,
const MMX2 = SWS_CPU_CAPS_MMX2,
const _3DNOW = SWS_CPU_CAPS_3DNOW,
const ALTIVEC = SWS_CPU_CAPS_ALTIVEC,
const BFIN = SWS_CPU_CAPS_BFIN,
const SSE2 = SWS_CPU_CAPS_SSE2,
}
}

View File

@ -0,0 +1,41 @@
use libc::c_int;
use ffi::*;
#[derive(Eq, PartialEq, Clone, Copy, Debug)]
pub enum ColorSpace {
Default,
ITU709,
FCC,
ITU601,
ITU624,
SMPTE170M,
SMPTE240M,
}
impl From<c_int> for ColorSpace {
fn from(value: c_int) -> ColorSpace {
match value {
SWS_CS_ITU709 => ColorSpace::ITU709,
SWS_CS_FCC => ColorSpace::FCC,
SWS_CS_DEFAULT => ColorSpace::Default,
SWS_CS_SMPTE240M => ColorSpace::SMPTE240M,
_ => ColorSpace::Default
}
}
}
impl Into<c_int> for ColorSpace {
fn into(self) -> c_int {
match self {
ColorSpace::Default => SWS_CS_DEFAULT,
ColorSpace::ITU709 => SWS_CS_ITU709,
ColorSpace::FCC => SWS_CS_FCC,
ColorSpace::ITU601 => SWS_CS_ITU601,
ColorSpace::ITU624 => SWS_CS_ITU624,
ColorSpace::SMPTE170M => SWS_CS_SMPTE170M,
ColorSpace::SMPTE240M => SWS_CS_SMPTE240M
}
}
}

View File

@ -0,0 +1,102 @@
use std::ptr;
use libc::{c_int};
use ffi::*;
use ::{Error, Picture};
use ::util::format;
use super::Flags;
pub struct Context {
pub ptr: *mut SwsContext,
input: Definition,
output: Definition,
}
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub struct Definition {
pub format: format::Pixel,
pub width: u32,
pub height: u32,
}
impl Context {
pub fn get(src_format: format::Pixel, src_w: u32, src_h: u32,
dst_format: format::Pixel, dst_w: u32, dst_h: u32,
flags: Flags) -> Result<Self, Error> {
unsafe {
let ptr = sws_getContext(src_w as c_int, src_h as c_int, src_format.into(),
dst_w as c_int, dst_h as c_int, dst_format.into(),
flags.bits(),
ptr::null_mut(), ptr::null_mut(), ptr::null_mut());
if ptr != ptr::null_mut() {
Ok(Context {
ptr: ptr,
input: Definition {
format: src_format,
width: src_w,
height: src_h,
},
output: Definition {
format: dst_format,
width: dst_w,
height: dst_h,
},
})
}
else {
Err(Error::InvalidData)
}
}
}
pub fn cached(&mut self,
src_format: format::Pixel, src_w: u32, src_h: u32,
dst_format: format::Pixel, dst_w: u32, dst_h: u32,
flags: Flags) {
unsafe {
self.ptr = sws_getCachedContext(self.ptr,
src_w as c_int, src_h as c_int, src_format.into(),
dst_w as c_int, dst_h as c_int, dst_format.into(),
flags.bits(), ptr::null_mut(), ptr::null_mut(), ptr::null());
}
}
pub fn input(&self) -> &Definition {
&self.input
}
pub fn output(&self) -> &Definition {
&self.output
}
pub fn run(&self, input: &Picture, output: &mut Picture) -> Result<(), Error> {
if input.format() != self.input.format || input.width() != self.input.width || input.height() != self.input.height {
return Err(Error::InputChanged);
}
if output.format() != self.output.format || output.width() != self.output.width || output.height() != self.output.height {
return Err(Error::OutputChanged);
}
unsafe {
sws_scale(self.ptr,
(*input.ptr).data.as_ptr() as *const *const _, (*input.ptr).linesize.as_ptr() as *const _,
0, self.output.height as c_int,
(*output.ptr).data.as_ptr() as *mut *mut _, (*output.ptr).linesize.as_ptr() as *mut _);
}
Ok(())
}
}
impl Drop for Context {
fn drop(&mut self) {
unsafe {
sws_freeContext(self.ptr);
}
}
}

View File

@ -0,0 +1,35 @@
use std::ops::Deref;
use libc::c_int;
use ffi::*;
use util::format;
use ::{Picture, decoder, Error};
use super::{Context, Flags, flag};
impl<'a> Picture<'a> {
pub fn scaler(&self, width: u32, height: u32, flags: Flags) -> Result<Context, Error> {
Context::get(self.format(), self.width(), self.height(),
self.format(), width, height,
flags)
}
pub fn converter(&self, format: format::Pixel) -> Result<Context, Error> {
Context::get(self.format(), self.width(), self.height(),
format, self.width(), self.height(),
flag::FAST_BILINEAR)
}
}
impl decoder::Video {
pub fn scaler(&self, width: u32, height: u32, flags: Flags) -> Result<Context, Error> {
Context::get(self.format(), self.width(), self.height(),
self.format(), width, height,
flags)
}
pub fn converter(&self, format: format::Pixel) -> Result<Context, Error> {
Context::get(self.format(), self.width(), self.height(),
format, self.width(), self.height(),
flag::FAST_BILINEAR)
}
}

View File

@ -0,0 +1,80 @@
use ffi::*;
use super::Vector;
pub struct Filter {
pub ptr: *mut SwsFilter,
}
impl Filter {
pub fn get(luma_g_blur: f32, chroma_g_blur: f32,
luma_sharpen: f32, chroma_sharpen: f32,
chroma_h_shift: f32, chroma_v_shift: f32) -> Self {
unsafe {
Filter {
ptr: sws_getDefaultFilter(luma_g_blur, chroma_g_blur,
luma_sharpen, chroma_sharpen,
chroma_h_shift, chroma_v_shift, 0)
}
}
}
pub fn new() -> Self {
Self::get(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
}
pub fn luma_horizontal(&self) -> Vector {
unsafe {
Vector::wrap((*self.ptr).lumH)
}
}
pub fn luma_horizontal_mut(&mut self) -> Vector {
unsafe {
Vector::wrap((*self.ptr).lumH)
}
}
pub fn luma_vertical(&self) -> Vector {
unsafe {
Vector::wrap((*self.ptr).lumV)
}
}
pub fn luma_vertical_mut(&mut self) -> Vector {
unsafe {
Vector::wrap((*self.ptr).lumV)
}
}
pub fn chroma_horizontal(&self) -> Vector {
unsafe {
Vector::wrap((*self.ptr).lumV)
}
}
pub fn chroma_horizontal_mut(&mut self) -> Vector {
unsafe {
Vector::wrap((*self.ptr).lumV)
}
}
pub fn chroma_vertical(&self) -> Vector {
unsafe {
Vector::wrap((*self.ptr).lumV)
}
}
pub fn chroma_vertical_mut(&mut self) -> Vector {
unsafe {
Vector::wrap((*self.ptr).lumV)
}
}
}
impl Drop for Filter {
fn drop(&mut self) {
unsafe {
sws_freeFilter(self.ptr);
}
}
}

View File

@ -0,0 +1,28 @@
use libc::c_int;
use ffi::*;
bitflags! {
flags Flags: c_int {
const FAST_BILINEAR = SWS_FAST_BILINEAR,
const BILINEAR = SWS_BILINEAR,
const BICUBIC = SWS_BICUBIC,
const X = SWS_X,
const POINT = SWS_POINT,
const AREA = SWS_AREA,
const BICUBLIN = SWS_BICUBLIN,
const GAUSS = SWS_GAUSS,
const SINC = SWS_SINC,
const LANCZOS = SWS_LANCZOS,
const SPLINE = SWS_SPLINE,
const SRC_V_CHR_DROP_MASK = SWS_SRC_V_CHR_DROP_MASK,
const SRC_V_CHR_DROP_SHIFT = SWS_SRC_V_CHR_DROP_SHIFT,
const PARAM_DEFAULT = SWS_PARAM_DEFAULT,
const PRINT_INFO = SWS_PRINT_INFO,
const FULL_CHR_H_INT = SWS_FULL_CHR_H_INT,
const FULL_CHR_H_INP = SWS_FULL_CHR_H_INP,
const DIRECT_BGR = SWS_DIRECT_BGR,
const ACCURATE_RND = SWS_ACCURATE_RND,
const BITEXACT = SWS_BITEXACT,
const ERROR_DIFFUSION = SWS_ERROR_DIFFUSION,
}
}

View File

@ -0,0 +1,44 @@
pub mod flag;
pub use self::flag::Flags;
pub mod capability;
pub use self::capability::Capabilities;
pub mod color_space;
pub use self::color_space::ColorSpace;
pub mod support;
pub mod vector;
pub use self::vector::Vector;
pub mod filter;
pub use self::filter::Filter;
pub mod context;
pub use self::context::Context;
mod extensions;
use std::ffi::CStr;
use std::str::from_utf8_unchecked;
use ffi::*;
pub fn version() -> u32 {
unsafe {
swscale_version()
}
}
pub fn configuration() -> &'static str {
unsafe {
from_utf8_unchecked(CStr::from_ptr(swscale_configuration()).to_bytes())
}
}
pub fn license() -> &'static str {
unsafe {
from_utf8_unchecked(CStr::from_ptr(swscale_license()).to_bytes())
}
}

View File

@ -0,0 +1,20 @@
use ffi::*;
use ::util::format;
pub fn input(format: format::Pixel) -> bool {
unsafe {
sws_isSupportedInput(format.into()) != 0
}
}
pub fn output(format: format::Pixel) -> bool {
unsafe {
sws_isSupportedOutput(format.into()) != 0
}
}
pub fn endianness_conversion(format: format::Pixel) -> bool {
unsafe {
sws_isSupportedEndiannessConversion(format.into()) != 0
}
}

View File

@ -0,0 +1,108 @@
use std::marker::PhantomData;
use std::slice;
use libc::{c_int, c_double};
use ffi::*;
pub struct Vector<'a> {
pub ptr: *mut SwsVector,
_own: bool,
_marker: PhantomData<&'a ()>,
}
impl<'a> Vector<'a> {
pub fn wrap(ptr: *mut SwsVector) -> Self {
Vector { ptr: ptr, _own: false, _marker: PhantomData }
}
pub fn new(length: usize) -> Self {
unsafe {
Vector { ptr: sws_allocVec(length as c_int), _own: true, _marker: PhantomData }
}
}
pub fn gaussian(variance: f64, quality: f64) -> Self {
unsafe {
Vector { ptr: sws_getGaussianVec(variance as c_double, quality as c_double), _own: true, _marker: PhantomData }
}
}
pub fn value(value: f64, length: usize) -> Self {
unsafe {
Vector { ptr: sws_getConstVec(value as c_double, length as c_int), _own: true, _marker: PhantomData }
}
}
pub fn identity() -> Self {
unsafe {
Vector { ptr: sws_getIdentityVec(), _own: true, _marker: PhantomData }
}
}
pub fn scale(&mut self, scalar: f64) {
unsafe {
sws_scaleVec(self.ptr, scalar as c_double);
}
}
pub fn normalize(&mut self, height: f64) {
unsafe {
sws_normalizeVec(self.ptr, height as c_double);
}
}
pub fn conv(&mut self, other: &Vector) {
unsafe {
sws_convVec(self.ptr, other.ptr);
}
}
pub fn add(&mut self, other: &Vector) {
unsafe {
sws_addVec(self.ptr, other.ptr);
}
}
pub fn sub(&mut self, other: &Vector) {
unsafe {
sws_subVec(self.ptr, other.ptr);
}
}
pub fn shift(&mut self, value: usize) {
unsafe {
sws_shiftVec(self.ptr, value as c_int);
}
}
pub fn coefficients(&self) -> &[f64] {
unsafe {
slice::from_raw_parts((*self.ptr).coeff, (*self.ptr).length as usize)
}
}
pub fn coefficients_mut(&self) -> &[f64] {
unsafe {
slice::from_raw_parts_mut((*self.ptr).coeff, (*self.ptr).length as usize)
}
}
}
impl<'a> Clone for Vector<'a> {
fn clone(&self) -> Self {
unsafe {
Vector { ptr: sws_cloneVec(self.ptr), _own: true, _marker: PhantomData }
}
}
}
impl<'a> Drop for Vector<'a> {
fn drop(&mut self) {
unsafe {
if self._own {
sws_freeVec(self.ptr);
}
}
}
}