use super::{Decodable, DecodedFrame};
use crate::frame::FrameBuffer;
use std::ffi::c_void;
use std::ptr;
use std::sync::mpsc::{self, Sender};
use std::thread::{self, JoinHandle};
use vpx_sys::{
vpx_codec_ctx_t, vpx_codec_dec_init_ver, vpx_codec_decode, vpx_codec_destroy,
vpx_codec_get_frame, vpx_codec_vp9_dx, VPX_CODEC_OK, VPX_DECODER_ABI_VERSION,
};
struct Vp9Decoder {
context: vpx_codec_ctx_t,
}
impl Vp9Decoder {
fn new() -> Result<Self, String> {
let mut context = unsafe { std::mem::zeroed() };
let ret = unsafe {
vpx_codec_dec_init_ver(
&mut context,
vpx_codec_vp9_dx(),
ptr::null_mut(),
0,
VPX_DECODER_ABI_VERSION as i32,
)
};
if ret != VPX_CODEC_OK {
return Err(format!("Failed to initialize VP9 decoder: {:?}", ret));
}
Ok(Self { context })
}
}
impl Drop for Vp9Decoder {
fn drop(&mut self) {
unsafe {
vpx_codec_destroy(&mut self.context);
}
}
}
struct SendableVp9Decoder(Vp9Decoder);
unsafe impl Send for SendableVp9Decoder {}
struct MockDecoder;
impl MockDecoder {
fn new() -> Self {
Self
}
}
trait ThreadDecodable: Send {
fn decode_frame(&mut self, frame_buffer: &FrameBuffer) -> Result<Vec<DecodedFrame>, String>;
}
impl ThreadDecodable for SendableVp9Decoder {
fn decode_frame(&mut self, frame_buffer: &FrameBuffer) -> Result<Vec<DecodedFrame>, String> {
let mut decoded_frames = Vec::new();
let ret = unsafe {
vpx_codec_decode(
&mut self.0.context,
frame_buffer.frame.data.as_ptr(),
frame_buffer.frame.data.len() as u32,
ptr::null_mut(),
0,
)
};
if ret != VPX_CODEC_OK {
let error_msg = unsafe {
let error_cstr = vpx_sys::vpx_codec_err_to_string(ret);
if error_cstr.is_null() {
"Unknown codec error".to_string()
} else {
std::ffi::CStr::from_ptr(error_cstr)
.to_string_lossy()
.into_owned()
}
};
return Err(format!("VPX Decode failed: {}", error_msg));
}
let mut iter = ptr::null_mut::<c_void>();
loop {
let img = unsafe {
vpx_codec_get_frame(
&mut self.0.context,
&mut iter as *mut _ as *mut *const c_void,
)
};
if img.is_null() {
break;
}
let image_data = unsafe {
let width = (*img).d_w as usize;
let height = (*img).d_h as usize;
let uv_width = width / 2;
let uv_height = height / 2;
let mut buffer = Vec::with_capacity(width * height + 2 * uv_width * uv_height);
copy_plane_to_buffer(
(*img).planes[0],
(*img).stride[0],
width,
height,
&mut buffer,
);
copy_plane_to_buffer(
(*img).planes[1],
(*img).stride[1],
uv_width,
uv_height,
&mut buffer,
);
copy_plane_to_buffer(
(*img).planes[2],
(*img).stride[2],
uv_width,
uv_height,
&mut buffer,
);
buffer
};
decoded_frames.push(DecodedFrame {
sequence_number: frame_buffer.sequence_number(),
width: 0,
height: 0,
data: image_data,
});
}
Ok(decoded_frames)
}
}
unsafe fn copy_plane_to_buffer(
plane: *const u8,
stride: i32,
width: usize,
height: usize,
buffer: &mut Vec<u8>,
) {
let mut current_ptr = plane;
for _ in 0..height {
buffer.extend_from_slice(std::slice::from_raw_parts(current_ptr, width));
current_ptr = current_ptr.offset(stride as isize);
}
}
impl ThreadDecodable for MockDecoder {
fn decode_frame(&mut self, frame_buffer: &FrameBuffer) -> Result<Vec<DecodedFrame>, String> {
println!(
"[MOCK_DECODER] Pretending to decode frame {}",
frame_buffer.sequence_number()
);
Ok(Vec::new())
}
}
enum DecoderMessage {
Frame(FrameBuffer),
Shutdown,
}
pub struct NativeDecoder {
thread_handle: Option<JoinHandle<()>>,
sender: Sender<DecoderMessage>,
}
impl Decodable for NativeDecoder {
type Frame = DecodedFrame;
fn new(
codec: crate::decoder::VideoCodec,
on_decoded_frame: Box<dyn Fn(Self::Frame) + Send + Sync>,
) -> Self {
let (sender, receiver) = mpsc::channel();
let thread_handle = Some(thread::spawn(move || {
let mut decoder: Box<dyn ThreadDecodable> = match codec {
crate::decoder::VideoCodec::Vp9Profile0Level10Bit8 => Box::new(SendableVp9Decoder(
Vp9Decoder::new().expect("Failed to create Vp9Decoder"),
)),
crate::decoder::VideoCodec::Vp8 => {
Box::new(SendableVp9Decoder(
Vp9Decoder::new().expect("Failed to create Vp9Decoder"),
))
}
crate::decoder::VideoCodec::Mock => Box::new(MockDecoder::new()),
crate::decoder::VideoCodec::Unspecified => {
panic!("Cannot create decoder for unspecified codec")
}
};
while let Ok(message) = receiver.recv() {
match message {
DecoderMessage::Frame(frame_buffer) => {
println!(
"[DECODER_THREAD] Decoding frame {}",
frame_buffer.sequence_number()
);
match decoder.decode_frame(&frame_buffer) {
Ok(images) => {
for img in images {
on_decoded_frame(img);
}
}
Err(e) => {
eprintln!("[DECODER_THREAD] Decode error: {}", e);
}
}
}
DecoderMessage::Shutdown => {
println!("[DECODER_THREAD] Shutting down.");
break;
}
}
}
}));
NativeDecoder {
thread_handle,
sender,
}
}
fn decode(&self, frame: FrameBuffer) {
if let Err(e) = self.sender.send(DecoderMessage::Frame(frame)) {
eprintln!(
"[NativeDecoder] Failed to send frame to decoder thread: {}",
e
);
}
}
}
impl Drop for NativeDecoder {
fn drop(&mut self) {
println!("[NativeDecoder] Dropping decoder. Signaling shutdown.");
if self.sender.send(DecoderMessage::Shutdown).is_err() {
eprintln!("[NativeDecoder] Decoder thread already shut down.");
}
if let Some(handle) = self.thread_handle.take() {
handle.join().expect("Decoder thread failed to join");
}
}
}