Skip to content

Commit 6f3f010

Browse files
committed
add basic test
1 parent c2169f4 commit 6f3f010

File tree

2 files changed

+160
-12
lines changed

2 files changed

+160
-12
lines changed

src/lib.rs

Lines changed: 120 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ use std::{
55

66
use vvenc_sys::*;
77

8-
#[derive(Debug, Clone)]
8+
#[derive(Debug)]
99
pub struct Encoder {
1010
inner: Arc<Mutex<InnerEncoder>>,
11+
au: AccessUnit,
1112
}
1213

1314
#[derive(Debug)]
@@ -29,25 +30,85 @@ impl Encoder {
2930
return Err(Error::Initialize);
3031
};
3132
let ret = unsafe { vvenc_encoder_open(encoder.as_ptr(), &mut config.inner) };
33+
#[allow(non_upper_case_globals)]
3234
match ret {
3335
ErrorCodes_VVENC_OK => Ok(Self {
3436
inner: Arc::new(Mutex::new(InnerEncoder { encoder })),
37+
au: AccessUnit::new(&config),
3538
}),
3639
_ => Err(Error::new(ret)),
3740
}
3841
}
3942

40-
fn with_config(config: &mut vvenc_config) -> Result<Self, Error> {
41-
let Some(encoder) = ptr::NonNull::new(unsafe { vvenc_encoder_create() }) else {
42-
return Err(Error::Initialize);
43+
pub fn encode<'a>(&mut self, frame: Frame<'a>) -> Result<Option<&AccessUnit>, Error> {
44+
let mut yuv_buffer = vvencYUVBuffer {
45+
planes: [
46+
vvencYUVPlane {
47+
ptr: frame.planes[0].data.as_ptr() as *mut i16,
48+
width: frame.planes[0].width,
49+
height: frame.planes[0].height,
50+
stride: frame.planes[0].stride,
51+
},
52+
vvencYUVPlane {
53+
ptr: frame.planes[1].data.as_ptr() as *mut i16,
54+
width: frame.planes[1].width,
55+
height: frame.planes[1].height,
56+
stride: frame.planes[1].stride,
57+
},
58+
vvencYUVPlane {
59+
ptr: frame.planes[2].data.as_ptr() as *mut i16,
60+
width: frame.planes[2].width,
61+
height: frame.planes[2].height,
62+
stride: frame.planes[2].stride,
63+
},
64+
],
65+
sequenceNumber: frame.sequence_number,
66+
cts: frame.cts.unwrap_or(0),
67+
ctsValid: frame.cts.is_some(),
4368
};
44-
let ret = unsafe { vvenc_encoder_open(encoder.as_ptr(), config) };
45-
match ret {
46-
ErrorCodes_VVENC_OK => Ok(Self {
47-
inner: Arc::new(Mutex::new(InnerEncoder { encoder })),
48-
}),
49-
_ => Err(Error::new(ret)),
69+
70+
let mut encode_done = false;
71+
let ret = unsafe {
72+
vvenc_encode(
73+
self.inner.lock().unwrap().encoder.as_ptr(),
74+
&mut yuv_buffer,
75+
&mut self.au.inner,
76+
&mut encode_done,
77+
)
78+
};
79+
80+
if ret != ErrorCodes_VVENC_OK {
81+
return Err(Error::new(ret));
5082
}
83+
84+
// TODO: double check if encode_done handling is correct or if we lose a frame like that
85+
if self.au.inner.payloadUsedSize == 0 {
86+
return Ok(None);
87+
}
88+
89+
Ok(Some(&self.au))
90+
}
91+
92+
pub fn flush(&mut self) -> Result<Option<&AccessUnit>, Error> {
93+
let mut encode_done = false;
94+
let ret = unsafe {
95+
vvenc_encode(
96+
self.inner.lock().unwrap().encoder.as_ptr(),
97+
std::ptr::null_mut(),
98+
&mut self.au.inner,
99+
&mut encode_done,
100+
)
101+
};
102+
103+
if ret != ErrorCodes_VVENC_OK {
104+
return Err(Error::new(ret));
105+
}
106+
107+
if self.au.inner.payloadUsedSize == 0 {
108+
return Ok(None);
109+
}
110+
111+
Ok(Some(&self.au))
51112
}
52113
}
53114

@@ -147,3 +208,52 @@ impl Error {
147208
}
148209
}
149210
}
211+
212+
#[derive(Debug)]
213+
pub struct Frame<'a> {
214+
pub planes: [Plane<'a>; 3],
215+
pub sequence_number: u64,
216+
pub cts: Option<u64>,
217+
}
218+
219+
#[derive(Debug)]
220+
pub struct Plane<'a> {
221+
pub data: &'a [i16],
222+
pub width: i32,
223+
pub height: i32,
224+
pub stride: i32,
225+
}
226+
227+
#[derive(Debug)]
228+
pub struct AccessUnit {
229+
// FIXME: make inner private
230+
pub inner: vvencAccessUnit,
231+
}
232+
233+
impl AccessUnit {
234+
fn new(config: &Config) -> Self {
235+
// Allocate enough space for the AU payloads from the given config. Same as in EncApp.cpp from libvvenc
236+
#[allow(non_upper_case_globals)]
237+
let au_size_scale = match config.inner.m_internChromaFormat {
238+
vvencChromaFormat_VVENC_CHROMA_400 | vvencChromaFormat_VVENC_CHROMA_420 => 2,
239+
_ => 3,
240+
};
241+
let payload_size =
242+
au_size_scale * config.inner.m_SourceHeight * config.inner.m_SourceWidth + 1024;
243+
let inner = unsafe {
244+
let mut inner = std::mem::zeroed();
245+
vvenc_accessUnit_default(&mut inner);
246+
vvenc_accessUnit_alloc_payload(&mut inner, payload_size);
247+
inner
248+
};
249+
Self { inner }
250+
}
251+
}
252+
253+
impl Drop for AccessUnit {
254+
fn drop(&mut self) {
255+
unsafe {
256+
vvenc_accessUnit_free_payload(&mut self.inner);
257+
}
258+
}
259+
}

tests/basic.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,44 @@ use vvenc::*;
22

33
#[test]
44
fn basic() {
5-
let config = Config::new(160, 120, 24, 0, 32, Preset::Faster);
6-
let encoder = Encoder::new(config).unwrap();
5+
const WIDTH: i32 = 160;
6+
const HEIGHT: i32 = 120;
7+
let config = Config::new(WIDTH, HEIGHT, 24, 0, 32, Preset::Faster);
8+
let mut encoder = Encoder::new(config).unwrap();
9+
10+
let y_size = (WIDTH * HEIGHT) as usize;
11+
let uv_size = (WIDTH * HEIGHT / 4) as usize;
12+
let y = vec![0i16; y_size];
13+
let u = vec![0i16; uv_size];
14+
let v = vec![0i16; uv_size];
15+
16+
let frame = Frame {
17+
planes: [
18+
Plane {
19+
data: y.as_slice(),
20+
width: WIDTH,
21+
height: HEIGHT,
22+
stride: WIDTH,
23+
},
24+
Plane {
25+
data: u.as_slice(),
26+
width: WIDTH / 2,
27+
height: HEIGHT / 2,
28+
stride: WIDTH / 2,
29+
},
30+
Plane {
31+
data: v.as_slice(),
32+
width: WIDTH / 2,
33+
height: HEIGHT / 2,
34+
stride: WIDTH / 2,
35+
},
36+
],
37+
sequence_number: 0,
38+
cts: None,
39+
};
40+
41+
assert!(encoder.encode(frame).unwrap().is_none());
42+
let au = encoder.flush().unwrap().unwrap();
43+
assert!(au.inner.payloadUsedSize > 0);
44+
assert!(encoder.flush().unwrap_err() == Error::RestartRequired);
745
}

0 commit comments

Comments
 (0)