|
- use dav1d::Settings;
- use dora_node_api::{arrow::array::UInt8Array, DoraNode, Event, IntoArrow};
- use eyre::{Context, Result};
- use log::warn;
-
- fn yuv420_to_bgr(
- y_plane: &[u8],
- u_plane: &[u8],
- v_plane: &[u8],
- width: u32,
- height: u32,
- ) -> Vec<u8> {
- let width = width as usize;
- let height = height as usize;
- let mut rgb_data = vec![0u8; width * height * 3]; // Output RGB data buffer
-
- for j in 0..height {
- for i in 0..width {
- let y_idx = j * width + i; // Index in Y plane
- let uv_idx = (j / 2) * (width / 2) + (i / 2); // Index in U/V planes
-
- let y = y_plane[y_idx] as f32;
- let u = u_plane[uv_idx] as f32 - 128.0;
- let v = v_plane[uv_idx] as f32 - 128.0;
-
- // Convert YUV to RGB using BT.601 standard formula
- let r = (y + 1.402 * v).clamp(0.0, 255.0) as u8;
- let g = (y - 0.344136 * u - 0.714136 * v).clamp(0.0, 255.0) as u8;
- let b = (y + 1.772 * u).clamp(0.0, 255.0) as u8;
-
- // Set the RGB values in the output buffer
- let rgb_idx = y_idx * 3;
- rgb_data[rgb_idx] = b;
- rgb_data[rgb_idx + 1] = g;
- rgb_data[rgb_idx + 2] = r;
- }
- }
-
- rgb_data
- }
-
- pub fn lib_main() -> Result<()> {
- let mut settings = Settings::new();
- // settings.set_n_threads(16);
- settings.set_max_frame_delay(1);
- let mut dec =
- dav1d::Decoder::with_settings(&settings).expect("failed to create decoder instance");
-
- let (mut node, mut events) =
- DoraNode::init_from_env().context("Could not initialize dora node")?;
-
- loop {
- match events.recv() {
- Some(Event::Input {
- id,
- data,
- mut metadata,
- }) => {
- if let Some(data) = data.as_any().downcast_ref::<UInt8Array>() {
- let data = data.values().clone();
- match dec.send_data(data, None, None, None) {
- Err(e) => {
- warn!("Error sending data to the decoder: {}", e);
- }
- Ok(()) => {
- if let Ok(p) = dec.get_picture() {
- match p.pixel_layout() {
- dav1d::PixelLayout::I420 => {
- let y = p.plane(dav1d::PlanarImageComponent::Y);
- let u = p.plane(dav1d::PlanarImageComponent::U);
- let v = p.plane(dav1d::PlanarImageComponent::V);
- let y = yuv420_to_bgr(&y, &u, &v, p.width(), p.height());
- let arrow = y.into_arrow();
- metadata.parameters.insert(
- "encoding".to_string(),
- dora_node_api::Parameter::String("bgr8".to_string()),
- );
- node.send_output(id, metadata.parameters, arrow).unwrap();
- }
- dav1d::PixelLayout::I400 => {
- let y = p.plane(dav1d::PlanarImageComponent::Y);
- let vec16: Vec<u16> = bytemuck::cast_slice(&y).to_vec();
- let arrow = vec16.into_arrow();
- metadata.parameters.insert(
- "encoding".to_string(),
- dora_node_api::Parameter::String("mono16".to_string()),
- );
- node.send_output(id, metadata.parameters, arrow).unwrap();
- }
- _ => {
- warn!("Unsupported pixel layout");
- continue;
- }
- };
- }
- }
- }
- } else {
- warn!("Unsupported data type {}", data.data_type());
- continue;
- }
- }
- None => break,
- Some(_) => break,
- }
- }
- Ok(())
- }
-
- #[cfg(feature = "python")]
- use pyo3::{
- pyfunction, pymodule,
- types::{PyModule, PyModuleMethods},
- wrap_pyfunction, Bound, PyResult, Python,
- };
-
- #[cfg(feature = "python")]
- #[pyfunction]
- fn py_main(_py: Python) -> eyre::Result<()> {
- lib_main()
- }
-
- #[cfg(feature = "python")]
- #[pymodule]
- fn dora_dav1d(_py: Python, m: Bound<'_, PyModule>) -> PyResult<()> {
- m.add_function(wrap_pyfunction!(py_main, &m)?)?;
- m.add("__version__", env!("CARGO_PKG_VERSION"))?;
- Ok(())
- }
|