Skip to main content

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