1 | use std::ffi::{CStr, CString}; |
2 | use std::ops::Index; |
3 | use std::ptr; |
4 | use std::slice; |
5 | use std::str::from_utf8_unchecked; |
6 | |
7 | use ffi::AVSampleFormat::*; |
8 | use ffi::*; |
9 | use libc::{c_int, c_void}; |
10 | |
11 | #[derive (Eq, PartialEq, Copy, Clone, Debug)] |
12 | pub enum Sample { |
13 | None, |
14 | |
15 | U8(Type), |
16 | I16(Type), |
17 | I32(Type), |
18 | I64(Type), |
19 | F32(Type), |
20 | F64(Type), |
21 | } |
22 | |
23 | #[derive (Eq, PartialEq, Copy, Clone, Debug)] |
24 | pub enum Type { |
25 | Packed, |
26 | Planar, |
27 | } |
28 | |
29 | impl Sample { |
30 | #[inline ] |
31 | pub fn name(&self) -> &'static str { |
32 | unsafe { |
33 | from_utf8_unchecked(CStr::from_ptr(av_get_sample_fmt_name((*self).into())).to_bytes()) |
34 | } |
35 | } |
36 | |
37 | #[inline ] |
38 | pub fn packed(&self) -> Self { |
39 | unsafe { Sample::from(av_get_packed_sample_fmt((*self).into())) } |
40 | } |
41 | |
42 | #[inline ] |
43 | pub fn planar(&self) -> Self { |
44 | unsafe { Sample::from(av_get_planar_sample_fmt((*self).into())) } |
45 | } |
46 | |
47 | #[inline ] |
48 | pub fn is_planar(&self) -> bool { |
49 | unsafe { av_sample_fmt_is_planar((*self).into()) == 1 } |
50 | } |
51 | |
52 | #[inline ] |
53 | pub fn is_packed(&self) -> bool { |
54 | !self.is_planar() |
55 | } |
56 | |
57 | #[inline ] |
58 | pub fn bytes(&self) -> usize { |
59 | unsafe { av_get_bytes_per_sample((*self).into()) as usize } |
60 | } |
61 | |
62 | #[inline ] |
63 | pub fn buffer(&self, channels: u16, samples: usize, align: bool) -> Buffer { |
64 | Buffer::new(*self, channels, samples, align) |
65 | } |
66 | } |
67 | |
68 | impl From<AVSampleFormat> for Sample { |
69 | #[inline ] |
70 | fn from(value: AVSampleFormat) -> Self { |
71 | match value { |
72 | AV_SAMPLE_FMT_NONE => Sample::None, |
73 | |
74 | AV_SAMPLE_FMT_U8 => Sample::U8(Type::Packed), |
75 | AV_SAMPLE_FMT_S16 => Sample::I16(Type::Packed), |
76 | AV_SAMPLE_FMT_S32 => Sample::I32(Type::Packed), |
77 | AV_SAMPLE_FMT_S64 => Sample::I64(Type::Packed), |
78 | AV_SAMPLE_FMT_FLT => Sample::F32(Type::Packed), |
79 | AV_SAMPLE_FMT_DBL => Sample::F64(Type::Packed), |
80 | |
81 | AV_SAMPLE_FMT_U8P => Sample::U8(Type::Planar), |
82 | AV_SAMPLE_FMT_S16P => Sample::I16(Type::Planar), |
83 | AV_SAMPLE_FMT_S32P => Sample::I32(Type::Planar), |
84 | AV_SAMPLE_FMT_S64P => Sample::I64(Type::Planar), |
85 | AV_SAMPLE_FMT_FLTP => Sample::F32(Type::Planar), |
86 | AV_SAMPLE_FMT_DBLP => Sample::F64(Type::Planar), |
87 | |
88 | AV_SAMPLE_FMT_NB => Sample::None, |
89 | } |
90 | } |
91 | } |
92 | |
93 | impl From<&'static str> for Sample { |
94 | #[inline ] |
95 | fn from(value: &'static str) -> Self { |
96 | unsafe { |
97 | let value: CString = CString::new(value).unwrap(); |
98 | |
99 | Sample::from(av_get_sample_fmt(value.as_ptr())) |
100 | } |
101 | } |
102 | } |
103 | |
104 | impl From<Sample> for AVSampleFormat { |
105 | #[inline ] |
106 | fn from(value: Sample) -> AVSampleFormat { |
107 | match value { |
108 | Sample::None => AV_SAMPLE_FMT_NONE, |
109 | |
110 | Sample::U8(Type::Packed) => AV_SAMPLE_FMT_U8, |
111 | Sample::I16(Type::Packed) => AV_SAMPLE_FMT_S16, |
112 | Sample::I32(Type::Packed) => AV_SAMPLE_FMT_S32, |
113 | Sample::I64(Type::Packed) => AV_SAMPLE_FMT_S64, |
114 | Sample::F32(Type::Packed) => AV_SAMPLE_FMT_FLT, |
115 | Sample::F64(Type::Packed) => AV_SAMPLE_FMT_DBL, |
116 | |
117 | Sample::U8(Type::Planar) => AV_SAMPLE_FMT_U8P, |
118 | Sample::I16(Type::Planar) => AV_SAMPLE_FMT_S16P, |
119 | Sample::I32(Type::Planar) => AV_SAMPLE_FMT_S32P, |
120 | Sample::I64(Type::Planar) => AV_SAMPLE_FMT_S64P, |
121 | Sample::F32(Type::Planar) => AV_SAMPLE_FMT_FLTP, |
122 | Sample::F64(Type::Planar) => AV_SAMPLE_FMT_DBLP, |
123 | } |
124 | } |
125 | } |
126 | |
127 | pub struct Buffer { |
128 | pub format: Sample, |
129 | pub channels: u16, |
130 | pub samples: usize, |
131 | pub align: bool, |
132 | |
133 | buffer: *mut *mut u8, |
134 | size: c_int, |
135 | } |
136 | |
137 | impl Buffer { |
138 | #[inline ] |
139 | pub fn size(format: Sample, channels: u16, samples: usize, align: bool) -> usize { |
140 | unsafe { |
141 | av_samples_get_buffer_size( |
142 | ptr::null_mut(), |
143 | i32::from(channels), |
144 | samples as c_int, |
145 | format.into(), |
146 | !align as c_int, |
147 | ) as usize |
148 | } |
149 | } |
150 | |
151 | #[inline ] |
152 | pub fn new(format: Sample, channels: u16, samples: usize, align: bool) -> Self { |
153 | unsafe { |
154 | let mut buf = Buffer { |
155 | format, |
156 | channels, |
157 | samples, |
158 | align, |
159 | |
160 | buffer: ptr::null_mut(), |
161 | size: 0, |
162 | }; |
163 | |
164 | av_samples_alloc_array_and_samples( |
165 | &mut buf.buffer, |
166 | &mut buf.size, |
167 | i32::from(channels), |
168 | samples as c_int, |
169 | format.into(), |
170 | !align as c_int, |
171 | ); |
172 | |
173 | buf |
174 | } |
175 | } |
176 | } |
177 | |
178 | impl Index<usize> for Buffer { |
179 | type Output = [u8]; |
180 | |
181 | #[inline ] |
182 | fn index(&self, index: usize) -> &[u8] { |
183 | if index >= self.samples { |
184 | panic!("out of bounds" ); |
185 | } |
186 | |
187 | unsafe { slice::from_raw_parts(*self.buffer.add(index), self.size as usize) } |
188 | } |
189 | } |
190 | |
191 | impl Clone for Buffer { |
192 | #[inline ] |
193 | fn clone(&self) -> Self { |
194 | let mut buf: Buffer = Buffer::new(self.format, self.channels, self.samples, self.align); |
195 | buf.clone_from(self); |
196 | |
197 | buf |
198 | } |
199 | |
200 | #[inline ] |
201 | fn clone_from(&mut self, source: &Self) { |
202 | unsafe { |
203 | av_samples_copy( |
204 | self.buffer, |
205 | source.buffer as *const *mut u8, |
206 | 0, |
207 | 0, |
208 | source.samples as c_int, |
209 | i32::from(source.channels), |
210 | source.format.into(), |
211 | ); |
212 | } |
213 | } |
214 | } |
215 | |
216 | impl Drop for Buffer { |
217 | #[inline ] |
218 | fn drop(&mut self) { |
219 | unsafe { |
220 | av_freep(self.buffer as *mut c_void); |
221 | } |
222 | } |
223 | } |
224 | |