blaze-rs 1.0.3

A Rustified OpenCL Experience
Documentation
use std::{alloc::{GlobalAlloc, Allocator}, ptr::{NonNull, addr_of_mut}};
use ffmpeg_sys_next::{av_malloc, av_free, AVFrame, av_frame_alloc, av_image_fill_arrays, av_image_get_linesize};
use crate::{buffer::rect::Rect2D, image::channel::RawPixel};
use super::error::{Error, ErrorKind};

pub type FfmpegBox<T> = Box<T, Ffmpeg>;
pub type FfmpegVec<T> = Vec<T, Ffmpeg>;

pub struct Ffmpeg;

unsafe impl Allocator for Ffmpeg {
    fn allocate(&self, layout: std::alloc::Layout) -> Result<std::ptr::NonNull<[u8]>, std::alloc::AllocError> {
        unsafe {
            if layout.size() == 0 {
                let slice = core::slice::from_raw_parts_mut(core::ptr::from_exposed_addr_mut(layout.align()), layout.size());
                return Ok(NonNull::new(slice).unwrap_unchecked());
            }

            match NonNull::new(self.alloc(layout)) {
                Some(x) => {
                    let slice = core::slice::from_raw_parts_mut(x.as_ptr(), layout.size());
                    Ok(NonNull::new_unchecked(slice))
                },

                None => Err(std::alloc::AllocError)
            }
        }
    }

    #[inline(always)]
    unsafe fn deallocate(&self, ptr: std::ptr::NonNull<u8>, layout: std::alloc::Layout) {
        if layout.size() == 0 { return; }
        self.dealloc(ptr.as_ptr(), layout)
    }
}

unsafe impl GlobalAlloc for Ffmpeg {
    #[inline(always)]
    unsafe fn alloc(&self, layout: std::alloc::Layout) -> *mut u8 {
        av_malloc(layout.size()).cast()
    }

    #[inline(always)]
    unsafe fn dealloc(&self, ptr: *mut u8, _layout: std::alloc::Layout) {
        av_free(ptr.cast())
    }
}

#[inline(always)]
pub fn new_frame () -> FfmpegBox<AVFrame> {
    unsafe {
        let alloc = av_frame_alloc();
        assert!(!alloc.is_null());
        Box::from_raw_in(alloc, Ffmpeg)
    }
}

pub fn frame_to_rect<P: RawPixel> (frame: &AVFrame) -> super::error::Result<Rect2D<P, Ffmpeg>> {
    let mut ffmpeg_pixel = P::FFMPEG.ok_or_else(|| Error::new(ErrorKind::InvalidData, "Invalid pixel format"))?;
    ffmpeg_pixel.update_id();

    let mut rect = Rect2D::<P, _>::new_uninit_in(
        usize::try_from(frame.width).unwrap(),
        usize::try_from(frame.width).unwrap(),
        Ffmpeg
    ).ok_or_else(|| Error::new(ErrorKind::InvalidData, "Invalid size"))?;

    let mut ptr = rect.as_mut_ptr() as *mut u8;
    let mut linesize = unsafe {
        av_image_get_linesize(ffmpeg_pixel.id, frame.width, 0)
    };

    unsafe {
        ffmpeg_tri!(av_image_fill_arrays (
            addr_of_mut!(ptr),
            addr_of_mut!(linesize),
            frame.data[0],
            ffmpeg_pixel.id,
            frame.width,
            frame.height,
            0
        ));

        Ok(rect.assume_init())
    }
}