basis_universal/transcoding/
transcoder.rs1use super::*;
2use crate::UserData;
3use basis_universal_sys as sys;
4
5pub struct Transcoder(*mut sys::Transcoder);
8
9#[derive(Default, Debug, Copy, Clone)]
11pub struct ImageLevelDescription {
12 pub original_width: u32,
13 pub original_height: u32,
14 pub block_count: u32,
15}
16
17pub type ImageInfo = sys::basist_basisu_image_info;
19
20pub type ImageLevelInfo = sys::basist_basisu_image_level_info;
22
23pub type FileInfo = sys::FileInfo;
25
26#[derive(Default, Debug, Clone)]
28pub struct TranscodeParameters {
29 pub image_index: u32,
31 pub level_index: u32,
33 pub decode_flags: Option<DecodeFlags>,
35 pub output_row_pitch_in_blocks_or_pixels: Option<u32>,
37 pub output_rows_in_pixels: Option<u32>,
39}
40
41#[derive(Debug, Copy, Clone)]
43pub enum TranscodeError {
44 TranscodeFormatNotSupported,
45 ImageLevelNotFound,
46 TranscodeFailed,
47}
48
49impl Default for Transcoder {
50 fn default() -> Self {
51 Self::new()
52 }
53}
54
55impl Transcoder {
56 pub fn new() -> Transcoder {
58 unsafe { Transcoder(sys::transcoder_new()) }
59 }
60
61 pub fn validate_file_checksums(
63 &self,
64 data: &[u8],
65 full_validation: bool,
66 ) -> bool {
67 unsafe {
68 sys::transcoder_validate_file_checksums(
69 self.0,
70 data.as_ptr() as _,
71 data.len() as u32,
72 full_validation,
73 )
74 }
75 }
76
77 pub fn validate_header(
79 &self,
80 data: &[u8],
81 ) -> bool {
82 unsafe { sys::transcoder_validate_header(self.0, data.as_ptr() as _, data.len() as u32) }
83 }
84
85 pub fn basis_texture_type(
87 &self,
88 data: &[u8],
89 ) -> BasisTextureType {
90 unsafe {
91 sys::transcoder_get_texture_type(self.0, data.as_ptr() as _, data.len() as u32).into()
92 }
93 }
94
95 pub fn basis_texture_format(
97 &self,
98 data: &[u8],
99 ) -> BasisTextureFormat {
100 unsafe {
101 sys::transcoder_get_tex_format(self.0, data.as_ptr() as _, data.len() as u32).into()
102 }
103 }
104
105 pub fn user_data(
106 &self,
107 data: &[u8],
108 ) -> Result<UserData, ()> {
109 let mut userdata = UserData::default();
110 let result = unsafe {
111 sys::transcoder_get_userdata(
112 self.0,
113 data.as_ptr() as _,
114 data.len() as u32,
115 &mut userdata.userdata0,
116 &mut userdata.userdata1,
117 )
118 };
119
120 if result {
121 Ok(userdata)
122 } else {
123 Err(())
124 }
125 }
126
127 pub fn image_count(
129 &self,
130 data: &[u8],
131 ) -> u32 {
132 unsafe { sys::transcoder_get_total_images(self.0, data.as_ptr() as _, data.len() as u32) }
133 }
134
135 pub fn image_level_count(
137 &self,
138 data: &[u8],
139 image_index: u32,
140 ) -> u32 {
141 unsafe {
142 sys::transcoder_get_total_image_levels(
143 self.0,
144 data.as_ptr() as _,
145 data.len() as u32,
146 image_index,
147 )
148 }
149 }
150
151 pub fn image_level_description(
153 &self,
154 data: &[u8],
155 image_index: u32,
156 level_index: u32,
157 ) -> Option<ImageLevelDescription> {
158 let mut description = ImageLevelDescription::default();
159 unsafe {
160 if sys::transcoder_get_image_level_desc(
161 self.0,
162 data.as_ptr() as _,
163 data.len() as u32,
164 image_index,
165 level_index,
166 &mut description.original_width,
167 &mut description.original_height,
168 &mut description.block_count,
169 ) {
170 Some(description)
171 } else {
172 None
173 }
174 }
175 }
176
177 pub fn image_info(
179 &self,
180 data: &[u8],
181 image_index: u32,
182 ) -> Option<ImageInfo> {
183 let mut image_info = unsafe { std::mem::zeroed::<ImageInfo>() };
184 unsafe {
185 if sys::transcoder_get_image_info(
186 self.0,
187 data.as_ptr() as _,
188 data.len() as u32,
189 &mut image_info,
190 image_index,
191 ) {
192 Some(image_info)
193 } else {
194 None
195 }
196 }
197 }
198
199 pub fn image_level_info(
201 &self,
202 data: &[u8],
203 image_index: u32,
204 level_index: u32,
205 ) -> Option<ImageLevelInfo> {
206 let mut image_level_info = unsafe { std::mem::zeroed::<ImageLevelInfo>() };
207 unsafe {
208 if sys::transcoder_get_image_level_info(
209 self.0,
210 data.as_ptr() as _,
211 data.len() as u32,
212 &mut image_level_info,
213 image_index,
214 level_index,
215 ) {
216 Some(image_level_info)
217 } else {
218 None
219 }
220 }
221 }
222
223 pub fn file_info(
225 &self,
226 data: &[u8],
227 ) -> Option<FileInfo> {
228 let mut file_info = unsafe { std::mem::zeroed::<FileInfo>() };
229 unsafe {
230 if sys::transcoder_get_file_info(
231 self.0,
232 data.as_ptr() as _,
233 data.len() as u32,
234 &mut file_info,
235 ) {
236 Some(file_info)
237 } else {
238 None
239 }
240 }
241 }
242
243 pub fn prepare_transcoding(
247 &mut self,
248 data: &[u8],
249 ) -> Result<(), ()> {
250 transcoder_init();
251 unsafe {
252 if sys::transcoder_start_transcoding(self.0, data.as_ptr() as _, data.len() as u32) {
253 Ok(())
254 } else {
255 Err(())
256 }
257 }
258 }
259
260 pub fn end_transcoding(&mut self) {
262 unsafe {
263 let result = sys::transcoder_stop_transcoding(self.0);
264 debug_assert!(result);
266 }
267 }
268
269 pub fn is_prepared_to_transcode(&self) -> bool {
271 unsafe { sys::transcoder_get_ready_to_transcode(self.0) }
272 }
273
274 pub fn transcode_image_level(
286 &self,
287 data: &[u8],
288 transcode_format: TranscoderTextureFormat,
289 transcode_parameters: TranscodeParameters,
290 ) -> Result<Vec<u8>, TranscodeError> {
291 let image_index = transcode_parameters.image_index;
292 let level_index = transcode_parameters.level_index;
293
294 let basis_format = self.basis_texture_format(data);
298 if !basis_format.can_transcode_to_format(transcode_format) {
299 return Err(TranscodeError::TranscodeFormatNotSupported);
300 }
301
302 let description = self
306 .image_level_description(data, image_index, level_index)
307 .ok_or(TranscodeError::ImageLevelNotFound)?;
308 let required_buffer_bytes = transcode_format.calculate_minimum_output_buffer_bytes(
309 description.original_width,
310 description.original_height,
311 description.block_count,
312 transcode_parameters.output_row_pitch_in_blocks_or_pixels,
313 transcode_parameters.output_rows_in_pixels,
314 ) as usize;
315
316 let decode_flags = transcode_parameters
320 .decode_flags
321 .unwrap_or_else(DecodeFlags::empty);
322 let output_row_pitch_in_blocks_or_pixels = transcode_parameters
323 .output_row_pitch_in_blocks_or_pixels
324 .unwrap_or(0);
325 let output_rows_in_pixels = transcode_parameters.output_rows_in_pixels.unwrap_or(0);
326 let transcoder_state = std::ptr::null_mut();
327
328 let mut output = vec![0_u8; required_buffer_bytes];
332 let success = unsafe {
333 sys::transcoder_transcode_image_level(
334 self.0,
335 data.as_ptr() as _,
336 data.len() as u32,
337 image_index,
338 level_index,
339 output.as_mut_ptr() as _,
340 output.len() as u32,
341 transcode_format.into(),
342 decode_flags.bits(),
343 output_row_pitch_in_blocks_or_pixels,
344 transcoder_state,
345 output_rows_in_pixels,
346 )
347 };
348
349 if success {
350 Ok(output)
351 } else {
352 Err(TranscodeError::TranscodeFailed)
353 }
354 }
355
356 }
380
381impl Drop for Transcoder {
382 fn drop(&mut self) {
383 unsafe {
384 sys::transcoder_delete(self.0);
385 }
386 }
387}
388
389pub struct LowLevelUastcTranscoder(*mut sys::LowLevelUastcTranscoder);
390
391impl Default for LowLevelUastcTranscoder {
392 fn default() -> Self {
393 Self::new()
394 }
395}
396
397#[derive(Debug)]
398pub struct SliceParametersUastc {
399 pub num_blocks_x: u32,
400 pub num_blocks_y: u32,
401 pub has_alpha: bool,
402 pub original_width: u32,
403 pub original_height: u32,
404}
405
406impl LowLevelUastcTranscoder {
407 pub fn new() -> LowLevelUastcTranscoder {
409 transcoder_init();
410 unsafe { LowLevelUastcTranscoder(sys::low_level_uastc_transcoder_new()) }
411 }
412
413 pub fn transcode_slice(
414 &self,
415 data: &[u8],
416 slice_parameters: SliceParametersUastc,
417 decode_flags: DecodeFlags,
418 transcode_block_format: TranscoderBlockFormat,
419 ) -> Result<Vec<u8>, TranscodeError> {
420 let bc1_allow_threecolor_blocks = false;
421 let transcoder_state = std::ptr::null_mut();
422 let channel0 = 0;
423 let channel1 = 3;
424
425 let output_row_pitch_in_blocks_or_pixels =
426 (slice_parameters.original_width + transcode_block_format.block_width() - 1)
427 / transcode_block_format.block_width();
428 let output_rows_in_pixels = slice_parameters.original_height;
429 let total_slice_blocks = slice_parameters.num_blocks_x * slice_parameters.num_blocks_y;
430 let required_buffer_bytes = transcode_block_format.calculate_minimum_output_buffer_bytes(
431 slice_parameters.original_width,
432 slice_parameters.original_height,
433 total_slice_blocks,
434 Some(output_row_pitch_in_blocks_or_pixels),
435 Some(output_rows_in_pixels),
436 ) as usize;
437
438 let output_block_or_pixel_stride_in_bytes =
439 transcode_block_format.bytes_per_block_or_pixel();
440
441 let mut output = vec![0_u8; required_buffer_bytes];
442 let success = unsafe {
443 sys::low_level_uastc_transcoder_transcode_slice(
444 self.0,
445 output.as_mut_ptr() as _,
446 slice_parameters.num_blocks_x,
447 slice_parameters.num_blocks_y,
448 data.as_ptr() as _,
449 data.len() as u32,
450 transcode_block_format.into(),
451 output_block_or_pixel_stride_in_bytes,
452 bc1_allow_threecolor_blocks,
453 slice_parameters.has_alpha,
454 slice_parameters.original_width,
455 slice_parameters.original_height,
456 output_row_pitch_in_blocks_or_pixels,
457 transcoder_state,
458 output_rows_in_pixels,
459 channel0,
460 channel1,
461 decode_flags.bits(),
462 )
463 };
464
465 if success {
466 Ok(output)
467 } else {
468 Err(TranscodeError::TranscodeFailed)
469 }
470 }
471}
472
473impl Drop for LowLevelUastcTranscoder {
474 fn drop(&mut self) {
475 unsafe {
476 sys::low_level_uastc_transcoder_delete(self.0);
477 }
478 }
479}