diff --git a/vidformer-py/vidformer/cv2/vf_cv2.py b/vidformer-py/vidformer/cv2/vf_cv2.py index c83b16b..4c48c4d 100644 --- a/vidformer-py/vidformer/cv2/vf_cv2.py +++ b/vidformer-py/vidformer/cv2/vf_cv2.py @@ -23,6 +23,7 @@ import uuid from fractions import Fraction from bisect import bisect_right +import zlib CAP_PROP_POS_MSEC = 0 CAP_PROP_POS_FRAMES = 1 @@ -218,15 +219,22 @@ def _inline_frame(arr): if arr.shape[2] != 3: raise Exception("To inline a frame, the array must have 3 channels") - # convert BGR to RGB arr = arr[:, :, ::-1] + if not arr.flags["C_CONTIGUOUS"]: + arr = np.ascontiguousarray(arr) width = arr.shape[1] height = arr.shape[0] pix_fmt = "rgb24" - f = _inline_mat(arr.tobytes(), width=width, height=height, pix_fmt=pix_fmt) + data_gzip = zlib.compress(memoryview(arr), level=1) + + f = _inline_mat( + data_gzip, width=width, height=height, pix_fmt=pix_fmt, compression="zlib" + ) fmt = {"width": width, "height": height, "pix_fmt": pix_fmt} + + # Return the resulting Frame object return Frame(f, fmt) diff --git a/vidformer-py/vidformer/igni/vf_igni.py b/vidformer-py/vidformer/igni/vf_igni.py index b816f48..3ca8ba7 100644 --- a/vidformer-py/vidformer/igni/vf_igni.py +++ b/vidformer-py/vidformer/igni/vf_igni.py @@ -1,6 +1,7 @@ from .. import vf import requests +import json from fractions import Fraction from urllib.parse import urlparse diff --git a/vidformer/Cargo.toml b/vidformer/Cargo.toml index 0e3d852..9dbc7ff 100644 --- a/vidformer/Cargo.toml +++ b/vidformer/Cargo.toml @@ -28,3 +28,4 @@ opendal = { version = "0.51", features = ["layers-blocking", "services-fs", "ser tokio = { version = "1", features = ["full"] } rmp-serde = "1.3.0" serde_bytes = "0.11" +flate2 = "1.0" diff --git a/vidformer/src/filter/builtin.rs b/vidformer/src/filter/builtin.rs index 58a5f14..e991563 100644 --- a/vidformer/src/filter/builtin.rs +++ b/vidformer/src/filter/builtin.rs @@ -794,11 +794,32 @@ impl super::Filter for InlineMat { _ => panic!("Expected int"), }; - let data = match &args[0] { + let compression = match kwargs.get("compression") { + Some(Val::String(s)) => Option::Some(s), + _ => Option::None, + }; + + let mut data = match &args[0] { Val::Bytes(b) => b, _ => panic!("Expected bytes"), }; + let mut decompressed: Vec = Vec::new(); + if let Some(compression) = compression { + assert_eq!(compression, "zlib"); + + let mut decoder = flate2::read::ZlibDecoder::new(&data[..]); + use std::io::Read; + decoder.read_to_end(&mut decompressed).unwrap(); + data = &decompressed; + if data.len() != width as usize * height as usize * 3 { + return Err(Error::InvalidFilterArgValue( + format!("{:?}", data.len()), + "Invalid data length".to_string(), + )); + } + } + let f = unsafe { ffi::av_frame_alloc() }; if f.is_null() { panic!("ERROR could not allocate frame"); @@ -858,6 +879,20 @@ impl super::Filter for InlineMat { _ => return Err(Error::MissingFilterArg), }; + let compression = match kwargs.get("compression") { + Some(Val::String(s)) => Option::Some(s), + _ => Option::None, + }; + + if let Some(compression) = compression { + if compression != "zlib" { + return Err(Error::InvalidFilterArgValue( + compression.clone(), + "Invalid compression".to_string(), + )); + } + } + if pix_fmt != "rgb24" { return Err(Error::InvalidFilterArgValue( pix_fmt.clone(), @@ -882,7 +917,7 @@ impl super::Filter for InlineMat { }; // check if data length matches width, height, and pix_fmt - if data.len() != width as usize * height as usize * 3 { + if compression.is_none() && data.len() != width as usize * height as usize * 3 { return Err(Error::InvalidFilterArgValue( format!("{:?}", data.len()), "Invalid data length".to_string(),