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 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 pub fn pts(&self) -> i64 {
110 let value = unsafe { de265_get_image_PTS(self.inner) };
111 value as i64
112 }
113
114 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}