libde265_rs/
image.rs

1use std::ffi::CStr;
2use std::os::raw::{c_char, c_int, c_void};
3use std::ptr;
4use std::ptr::NonNull;
5
6use libde265_sys::*;
7
8use crate::DecoderContext;
9
10#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
11pub enum Channel {
12    Y,
13    Cb,
14    Cr,
15}
16
17impl Channel {
18    pub(crate) fn index(&self) -> c_int {
19        match self {
20            Channel::Y => 0,
21            Channel::Cb => 1,
22            Channel::Cr => 2,
23        }
24    }
25}
26
27#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
28pub enum ChromaFormat {
29    Mono,
30    C420,
31    C422,
32    C444,
33}
34
35#[derive(Debug, Copy, Clone)]
36pub struct NalHeader {
37    pub unit_type: u8,
38    pub unit_name: &'static CStr,
39    pub layer_id: u8,
40    pub temporal_id: u8,
41}
42
43pub struct Image<'a> {
44    inner: *const de265_image,
45    decoder: &'a DecoderContext,
46}
47
48impl<'a> Drop for Image<'a> {
49    fn drop(&mut self) {
50        unsafe { de265_release_next_picture(self.decoder.inner) };
51    }
52}
53
54impl<'a> Image<'a> {
55    pub(crate) fn new(decoder: &'a DecoderContext, ptr: NonNull<de265_image>) -> Self {
56        Self {
57            inner: ptr.as_ptr(),
58            decoder,
59        }
60    }
61
62    pub fn chroma_format(&self) -> ChromaFormat {
63        match unsafe { de265_get_chroma_format(self.inner) } {
64            de265_chroma::de265_chroma_mono => ChromaFormat::Mono,
65            de265_chroma::de265_chroma_420 => ChromaFormat::C420,
66            de265_chroma::de265_chroma_422 => ChromaFormat::C422,
67            de265_chroma::de265_chroma_444 => ChromaFormat::C444,
68            _ => unreachable!(),
69        }
70    }
71
72    pub fn width(&self, channel: Channel) -> u32 {
73        let value = unsafe { de265_get_image_width(self.inner, channel.index()) };
74        value.max(0) as u32
75    }
76
77    pub fn height(&self, channel: Channel) -> u32 {
78        let value = unsafe { de265_get_image_height(self.inner, channel.index()) };
79        value.max(0) as u32
80    }
81
82    pub fn bits_per_pixel(&self, channel: Channel) -> u32 {
83        let value = unsafe { de265_get_bits_per_pixel(self.inner, channel.index()) };
84        value.max(0) as u32
85    }
86
87    /// Returns the plane data and bytes per line (stride).
88    pub fn plane(&self, channel: Channel) -> (&[u8], usize) {
89        let mut stride: c_int = 0;
90        let buf = unsafe { de265_get_image_plane(self.inner, channel.index(), &mut stride) };
91        if buf.is_null() {
92            return (&[], 0);
93        }
94        let stride = stride.max(0) as usize;
95        let size = stride * self.height(channel) as usize;
96        (unsafe { std::slice::from_raw_parts(buf, size) }, stride)
97    }
98
99    pub fn plane_user_data(&self, channel: Channel) -> *mut c_void {
100        unsafe { de265_get_image_plane_user_data(self.inner, channel.index()) }
101    }
102
103    pub fn user_data(&self) -> usize {
104        let ptr = unsafe { de265_get_image_user_data(self.inner) };
105        ptr as usize
106    }
107
108    /// The presentation time stamp in microseconds.
109    pub fn pts(&self) -> i64 {
110        let value = unsafe { de265_get_image_PTS(self.inner) };
111        value as i64
112    }
113
114    /// Get NAL-header information of this frame.
115    pub fn nal_header(&self) -> NalHeader {
116        let mut unit_type: c_int = 0;
117        let mut unit_name: *const c_char = ptr::null();
118        let mut layer_id: c_int = 0;
119        let mut temporal_id: c_int = 0;
120
121        unsafe {
122            de265_get_image_NAL_header(
123                self.inner,
124                &mut unit_type,
125                &mut unit_name,
126                &mut layer_id,
127                &mut temporal_id,
128            )
129        }
130
131        let unit_name = if unit_name.is_null() {
132            c""
133        } else {
134            unsafe { CStr::from_ptr(unit_name) }
135        };
136
137        NalHeader {
138            unit_type: c_int_to_u8(unit_type),
139            unit_name,
140            layer_id: c_int_to_u8(layer_id),
141            temporal_id: c_int_to_u8(temporal_id),
142        }
143    }
144
145    pub fn full_range(&self) -> bool {
146        let value = unsafe { de265_get_image_full_range_flag(self.inner) };
147        value != 0
148    }
149
150    pub fn colour_primaries(&self) -> u8 {
151        let value = unsafe { de265_get_image_colour_primaries(self.inner) };
152        c_int_to_u8(value)
153    }
154
155    pub fn transfer_characteristics(&self) -> u8 {
156        let value = unsafe { de265_get_image_transfer_characteristics(self.inner) };
157        c_int_to_u8(value)
158    }
159
160    pub fn matrix_coefficients(&self) -> u8 {
161        let value = unsafe { de265_get_image_matrix_coefficients(self.inner) };
162        c_int_to_u8(value)
163    }
164}
165
166#[inline(always)]
167fn c_int_to_u8(value: c_int) -> u8 {
168    debug_assert!((0..=255).contains(&value));
169    value.max(0).min(u8::MAX as _) as u8
170}