wmv_decoder/ffi.rs
1//! Minimal C ABI for WMV2 decoding.
2//!
3//! This module is behind the `ffi` feature.
4//! It decodes one assembled WMV2 frame payload at a time and exposes the internal
5//! YUV420p planes.
6
7use std::ffi::c_void;
8
9use crate::api::Wmv2Decoder;
10
11#[repr(C)]
12pub struct Wmv2FrameView {
13 pub width: u32,
14 pub height: u32,
15
16 pub y_ptr: *const u8,
17 pub y_len: usize,
18 pub y_stride: usize,
19
20 pub cb_ptr: *const u8,
21 pub cb_len: usize,
22 pub cb_stride: usize,
23
24 pub cr_ptr: *const u8,
25 pub cr_len: usize,
26 pub cr_stride: usize,
27}
28
29struct Opaque {
30 dec: Wmv2Decoder,
31 has_frame: bool,
32}
33
34/// Create a WMV2 decoder.
35///
36/// `extradata` is copied.
37///
38/// # Safety
39///
40/// If `extradata` is non-null and `extradata_len` is nonzero, it must point to
41/// `extradata_len` initialized bytes in one allocation, readable and unchanged
42/// for this call. The length must not exceed `isize::MAX`.
43#[unsafe(no_mangle)]
44pub unsafe extern "C" fn wmv2_decoder_create(
45 width: u32,
46 height: u32,
47 extradata: *const u8,
48 extradata_len: usize,
49) -> *mut c_void {
50 let extra = unsafe {
51 if extradata.is_null() || extradata_len == 0 {
52 &[][..]
53 } else {
54 std::slice::from_raw_parts(extradata, extradata_len)
55 }
56 };
57
58 let dec = Wmv2Decoder::new(width, height, extra);
59 let opaque = Box::new(Opaque {
60 dec,
61 has_frame: false,
62 });
63 Box::into_raw(opaque) as *mut c_void
64}
65
66/// Destroy a WMV2 decoder. A null handle is ignored.
67///
68/// # Safety
69///
70/// A non-null `handle` must be a live handle returned by `wmv2_decoder_create`.
71/// No other call may use it concurrently. After this call, neither the handle
72/// nor any frame pointers obtained from it may be used.
73#[unsafe(no_mangle)]
74pub unsafe extern "C" fn wmv2_decoder_destroy(handle: *mut c_void) {
75 if handle.is_null() {
76 return;
77 }
78 unsafe {
79 let _ = Box::from_raw(handle as *mut Opaque);
80 }
81}
82
83/// Decode one assembled WMV2 frame payload.
84///
85/// Returns:
86/// 1 = decoded frame available
87/// 0 = no frame (header not found)
88/// -1 = invalid arguments
89/// -2 = decode error
90///
91/// # Safety
92///
93/// A non-null `handle` must be a live handle returned by `wmv2_decoder_create`,
94/// with exclusive access for this call. When all arguments pass the null and
95/// length checks, `payload` must point to `payload_len` initialized bytes in
96/// one allocation, readable and unchanged for this call. The length must not
97/// exceed `isize::MAX`, and the payload must not overlap decoder-owned memory.
98/// Previously returned frame pointers must not be accessed during this call.
99#[unsafe(no_mangle)]
100pub unsafe extern "C" fn wmv2_decoder_decode(
101 handle: *mut c_void,
102 payload: *const u8,
103 payload_len: usize,
104 is_key_frame: i32,
105) -> i32 {
106 if handle.is_null() {
107 return -1;
108 }
109 if payload.is_null() || payload_len == 0 {
110 return -1;
111 }
112
113 let opaque = unsafe { &mut *(handle as *mut Opaque) };
114 let data = unsafe { std::slice::from_raw_parts(payload, payload_len) };
115
116 match opaque.dec.decode_frame(data, is_key_frame != 0) {
117 Ok(Some(_)) => {
118 opaque.has_frame = true;
119 1
120 }
121 Ok(None) => {
122 opaque.has_frame = false;
123 0
124 }
125 Err(_) => {
126 opaque.has_frame = false;
127 -2
128 }
129 }
130}
131
132/// Get the most recently decoded frame view.
133///
134/// The returned pointers may be read until the next decode or destroy call.
135/// They must not be used to modify the frame data.
136///
137/// Returns:
138/// 1 = success
139/// 0 = no decoded frame available
140/// -1 = invalid arguments
141///
142/// # Safety
143///
144/// A non-null `handle` must be a live handle returned by `wmv2_decoder_create`,
145/// with exclusive access for this call. If both pointers are non-null, `out`
146/// must be aligned and valid for writing one `Wmv2FrameView`, and must not
147/// overlap decoder-owned memory. No other access to `out` may occur during
148/// this call.
149#[unsafe(no_mangle)]
150pub unsafe extern "C" fn wmv2_decoder_get_frame(
151 handle: *mut c_void,
152 out: *mut Wmv2FrameView,
153) -> i32 {
154 if handle.is_null() || out.is_null() {
155 return -1;
156 }
157
158 let opaque = unsafe { &mut *(handle as *mut Opaque) };
159 if !opaque.has_frame {
160 return 0;
161 }
162
163 let f = opaque.dec.current_frame();
164 let y_stride = f.width as usize;
165 let uv_stride = (f.width as usize) / 2;
166
167 unsafe {
168 *out = Wmv2FrameView {
169 width: f.width,
170 height: f.height,
171 y_ptr: f.y.as_ptr(),
172 y_len: f.y.len(),
173 y_stride,
174 cb_ptr: f.cb.as_ptr(),
175 cb_len: f.cb.len(),
176 cb_stride: uv_stride,
177 cr_ptr: f.cr.as_ptr(),
178 cr_len: f.cr.len(),
179 cr_stride: uv_stride,
180 };
181 }
182
183 1
184}