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#[no_mangle]
38pub extern "C" fn wmv2_decoder_create(
39    width: u32,
40    height: u32,
41    extradata: *const u8,
42    extradata_len: usize,
43) -> *mut c_void {
44    let extra = unsafe {
45        if extradata.is_null() || extradata_len == 0 {
46            &[][..]
47        } else {
48            std::slice::from_raw_parts(extradata, extradata_len)
49        }
50    };
51
52    let dec = Wmv2Decoder::new(width, height, extra);
53    let opaque = Box::new(Opaque { dec, has_frame: false });
54    Box::into_raw(opaque) as *mut c_void
55}
56
57#[no_mangle]
58pub extern "C" fn wmv2_decoder_destroy(handle: *mut c_void) {
59    if handle.is_null() {
60        return;
61    }
62    unsafe {
63        let _ = Box::from_raw(handle as *mut Opaque);
64    }
65}
66
67/// Decode one assembled WMV2 frame payload.
68///
69/// Returns:
70///   1  = decoded frame available
71///   0  = no frame (header not found)
72///  -1  = invalid arguments
73///  -2  = decode error
74#[no_mangle]
75pub extern "C" fn wmv2_decoder_decode(
76    handle: *mut c_void,
77    payload: *const u8,
78    payload_len: usize,
79    is_key_frame: i32,
80) -> i32 {
81    if handle.is_null() {
82        return -1;
83    }
84    if payload.is_null() || payload_len == 0 {
85        return -1;
86    }
87
88    let opaque = unsafe { &mut *(handle as *mut Opaque) };
89    let data = unsafe { std::slice::from_raw_parts(payload, payload_len) };
90
91    match opaque.dec.decode_frame(data, is_key_frame != 0) {
92        Ok(Some(_)) => {
93            opaque.has_frame = true;
94            1
95        }
96        Ok(None) => {
97            opaque.has_frame = false;
98            0
99        }
100        Err(_) => {
101            opaque.has_frame = false;
102            -2
103        }
104    }
105}
106
107/// Get the most recently decoded frame view.
108///
109/// The returned pointers remain valid until the next successful decode call.
110///
111/// Returns:
112///   1  = success
113///   0  = no decoded frame available
114///  -1  = invalid arguments
115#[no_mangle]
116pub extern "C" fn wmv2_decoder_get_frame(handle: *mut c_void, out: *mut Wmv2FrameView) -> i32 {
117    if handle.is_null() || out.is_null() {
118        return -1;
119    }
120
121    let opaque = unsafe { &mut *(handle as *mut Opaque) };
122    if !opaque.has_frame {
123        return 0;
124    }
125
126    let f = opaque.dec.current_frame();
127    let y_stride = f.width as usize;
128    let uv_stride = (f.width as usize) / 2;
129
130    unsafe {
131        *out = Wmv2FrameView {
132            width: f.width,
133            height: f.height,
134            y_ptr: f.y.as_ptr(),
135            y_len: f.y.len(),
136            y_stride,
137            cb_ptr: f.cb.as_ptr(),
138            cb_len: f.cb.len(),
139            cb_stride: uv_stride,
140            cr_ptr: f.cr.as_ptr(),
141            cr_len: f.cr.len(),
142            cr_stride: uv_stride,
143        };
144    }
145
146    1
147}