1use std::{ffi::c_void, path::Path, sync::Arc};
8
9use num_rational::Rational32;
10use parking_lot::lock_api::RawRwLock;
11
12use crate::{common::CWString, filter::RgbaPixel};
13
14struct InternalCacheHandle(*mut aviutl2_sys::cache2::CACHE_HANDLE);
15unsafe impl Send for InternalCacheHandle {}
16
17static CACHE_HANDLE: std::sync::OnceLock<std::sync::Mutex<InternalCacheHandle>> =
18 std::sync::OnceLock::new();
19
20static CACHE_LOCKS: std::sync::LazyLock<dashmap::DashMap<usize, Arc<parking_lot::RawRwLock>>> =
21 std::sync::LazyLock::new(dashmap::DashMap::new);
22
23#[doc(hidden)]
24pub struct GlobalCacheHandle;
25
26pub const GLOBAL_CACHE_HANDLE: GlobalCacheHandle = GlobalCacheHandle;
28
29impl AsCacheIdentifier for GlobalCacheHandle {
30 fn as_cache_identifier(&self) -> *mut c_void {
31 with_cache_handle(|handle| handle as *mut c_void).expect("Cache handle is not initialized")
32 }
33}
34
35#[doc(hidden)]
36pub fn __initialize_cache(handle: *mut aviutl2_sys::cache2::CACHE_HANDLE) {
37 CACHE_HANDLE
38 .set(std::sync::Mutex::new(InternalCacheHandle(handle)))
39 .ok()
40 .expect("Cache handle is already initialized");
41}
42
43#[doc(hidden)]
44pub fn __initialize_cache_unwind(handle: *mut aviutl2_sys::cache2::CACHE_HANDLE) {
45 if let Err(panic_info) = crate::__catch_unwind_with_panic_info(|| __initialize_cache(handle)) {
46 tracing::error!("Panic occurred during InitializeCache: {}", panic_info);
47 let _ = crate::logger::write_error_log(&panic_info);
48 }
49}
50
51#[derive(Debug, thiserror::Error)]
53pub enum CacheError {
54 #[error("api call failed")]
55 ApiCallFailed,
56 #[error("input utf-16 string contains null byte")]
57 InputCwstrContainsNull(#[from] crate::common::NullByteError),
58 #[error("value is out of range")]
59 ValueOutOfRange,
60 #[error("invalid audio channel")]
61 InvalidAudioChannel,
62}
63
64pub trait AsCacheIdentifier {
66 fn as_cache_identifier(&self) -> *mut c_void;
67}
68
69impl AsCacheIdentifier for *mut c_void {
70 fn as_cache_identifier(&self) -> *mut c_void {
71 *self
72 }
73}
74
75impl AsCacheIdentifier for *const c_void {
76 fn as_cache_identifier(&self) -> *mut c_void {
77 *self as *mut c_void
78 }
79}
80
81impl AsCacheIdentifier for usize {
82 fn as_cache_identifier(&self) -> *mut c_void {
83 *self as *mut c_void
84 }
85}
86
87enum CacheAccessMode {
88 Read,
89 Write,
90}
91
92struct CacheAccessGuard {
93 lock: Arc<parking_lot::RawRwLock>,
94 mode: CacheAccessMode,
95}
96
97impl CacheAccessGuard {
98 fn read(key: usize) -> Self {
99 let lock = CACHE_LOCKS
100 .entry(key)
101 .or_insert_with(|| Arc::new(parking_lot::RawRwLock::INIT))
102 .clone();
103 lock.lock_shared();
104 Self {
105 lock,
106 mode: CacheAccessMode::Read,
107 }
108 }
109
110 fn write(key: usize) -> Self {
111 let lock = CACHE_LOCKS
112 .entry(key)
113 .or_insert_with(|| Arc::new(parking_lot::RawRwLock::INIT))
114 .clone();
115 lock.lock_exclusive();
116 Self {
117 lock,
118 mode: CacheAccessMode::Write,
119 }
120 }
121}
122
123impl Drop for CacheAccessGuard {
124 fn drop(&mut self) {
125 unsafe {
126 match self.mode {
127 CacheAccessMode::Read => self.lock.unlock_shared(),
128 CacheAccessMode::Write => self.lock.unlock_exclusive(),
129 }
130 }
131 }
132}
133
134pub struct CacheImageReadGuard {
136 _access: CacheAccessGuard,
137 raw: aviutl2_sys::cache2::CACHE_IMAGE,
138 len: usize,
139}
140
141pub struct CacheImageWriteGuard {
143 _access: CacheAccessGuard,
144 raw: aviutl2_sys::cache2::CACHE_IMAGE,
145 len: usize,
146}
147
148pub struct CacheAudioReadGuard {
150 _access: CacheAccessGuard,
151 raw: aviutl2_sys::cache2::CACHE_AUDIO,
152 len: usize,
153}
154
155pub struct CacheAudioWriteGuard {
157 _access: CacheAccessGuard,
158 raw: aviutl2_sys::cache2::CACHE_AUDIO,
159 len: usize,
160}
161
162pub struct CacheFileImageReadGuard {
164 _access: CacheAccessGuard,
165 raw: aviutl2_sys::cache2::CACHE_FILE_IMAGE,
166 byte_len: usize,
167}
168
169unsafe impl Send for CacheImageReadGuard {}
170unsafe impl Send for CacheImageWriteGuard {}
171unsafe impl Send for CacheAudioReadGuard {}
172unsafe impl Send for CacheAudioWriteGuard {}
173unsafe impl Send for CacheFileImageReadGuard {}
174
175#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
177pub enum CacheImagePixelFormat {
178 Rgba,
180 Bgra,
182 Bgr,
184 Pa64,
186 Hf64,
188 Yuy2,
190 Yc48,
192}
193
194impl From<aviutl2_sys::filter2::INPUT_PIXEL_FORMAT> for CacheImagePixelFormat {
195 fn from(value: aviutl2_sys::filter2::INPUT_PIXEL_FORMAT) -> Self {
196 match value {
197 aviutl2_sys::filter2::INPUT_PIXEL_FORMAT::RGBA => Self::Rgba,
198 aviutl2_sys::filter2::INPUT_PIXEL_FORMAT::BGRA => Self::Bgra,
199 aviutl2_sys::filter2::INPUT_PIXEL_FORMAT::BGR => Self::Bgr,
200 aviutl2_sys::filter2::INPUT_PIXEL_FORMAT::PA64 => Self::Pa64,
201 aviutl2_sys::filter2::INPUT_PIXEL_FORMAT::HF64 => Self::Hf64,
202 aviutl2_sys::filter2::INPUT_PIXEL_FORMAT::YUY2 => Self::Yuy2,
203 aviutl2_sys::filter2::INPUT_PIXEL_FORMAT::YC48 => Self::Yc48,
204 }
205 }
206}
207
208#[derive(Debug, Clone, Copy, PartialEq)]
210pub struct VideoFileInfo {
211 pub total_time: f64,
213 pub frame_num: usize,
215 pub track_num: usize,
217 pub width: usize,
219 pub height: usize,
221 pub fps: Rational32,
223}
224
225#[derive(Debug, Clone, Copy, PartialEq)]
227pub struct AudioFileInfo {
228 pub total_time: f64,
230 pub sample_num: usize,
232 pub track_num: usize,
234 pub rate: i32,
236 pub channel: usize,
238}
239
240impl CacheImageReadGuard {
241 pub fn width(&self) -> usize {
243 self.raw.width as usize
244 }
245
246 pub fn height(&self) -> usize {
248 self.raw.height as usize
249 }
250
251 pub fn as_slice(&self) -> &[RgbaPixel] {
253 unsafe { std::slice::from_raw_parts(self.raw.buffer as *const RgbaPixel, self.len) }
254 }
255
256 pub fn as_ptr(&self) -> *const RgbaPixel {
258 self.raw.buffer as *const RgbaPixel
259 }
260
261 pub fn as_u8_slice(&self) -> &[u8] {
263 unsafe {
264 std::slice::from_raw_parts(
265 self.raw.buffer as *const u8,
266 self.len * std::mem::size_of::<RgbaPixel>(),
267 )
268 }
269 }
270
271 pub fn as_u8_ptr(&self) -> *const u8 {
273 self.raw.buffer as *const u8
274 }
275}
276
277impl CacheImageWriteGuard {
278 pub fn width(&self) -> usize {
280 self.raw.width as usize
281 }
282
283 pub fn height(&self) -> usize {
285 self.raw.height as usize
286 }
287
288 pub fn as_slice(&self) -> &[RgbaPixel] {
290 unsafe { std::slice::from_raw_parts(self.raw.buffer as *const RgbaPixel, self.len) }
291 }
292
293 pub fn as_slice_mut(&mut self) -> &mut [RgbaPixel] {
295 unsafe { std::slice::from_raw_parts_mut(self.raw.buffer as *mut RgbaPixel, self.len) }
296 }
297
298 pub fn as_mut_ptr(&mut self) -> *mut RgbaPixel {
300 self.raw.buffer as *mut RgbaPixel
301 }
302
303 pub fn as_u8_slice(&self) -> &[u8] {
305 unsafe {
306 std::slice::from_raw_parts(
307 self.raw.buffer as *const u8,
308 self.len * std::mem::size_of::<RgbaPixel>(),
309 )
310 }
311 }
312
313 pub fn as_u8_slice_mut(&mut self) -> &mut [u8] {
315 unsafe {
316 std::slice::from_raw_parts_mut(
317 self.raw.buffer as *mut u8,
318 self.len * std::mem::size_of::<RgbaPixel>(),
319 )
320 }
321 }
322
323 pub fn as_mut_u8_ptr(&mut self) -> *mut u8 {
325 self.raw.buffer as *mut u8
326 }
327}
328
329impl CacheAudioReadGuard {
330 pub fn sample_num(&self) -> usize {
332 self.len
333 }
334
335 pub fn channel_num(&self) -> usize {
337 self.raw.channel_num as usize
338 }
339
340 pub fn channel(&self, channel: crate::filter::AudioChannel) -> Option<&[f32]> {
342 let buffer = self.channel_ptr(channel)?;
343 Some(unsafe { std::slice::from_raw_parts(buffer, self.len) })
344 }
345
346 fn channel_ptr(&self, channel: crate::filter::AudioChannel) -> Option<*const f32> {
347 match i32::from(channel) {
348 0 if !self.raw.buffer0.is_null() => Some(self.raw.buffer0),
349 1 if self.raw.channel_num >= 2 && !self.raw.buffer1.is_null() => Some(self.raw.buffer1),
350 _ => None,
351 }
352 }
353}
354
355impl CacheAudioWriteGuard {
356 pub fn sample_num(&self) -> usize {
358 self.len
359 }
360
361 pub fn channel_num(&self) -> usize {
363 self.raw.channel_num as usize
364 }
365
366 pub fn channel(&self, channel: crate::filter::AudioChannel) -> Option<&[f32]> {
368 let buffer = self.channel_ptr(channel)?;
369 Some(unsafe { std::slice::from_raw_parts(buffer, self.len) })
370 }
371
372 pub fn channel_mut(&mut self, channel: crate::filter::AudioChannel) -> Option<&mut [f32]> {
374 let buffer = self.channel_ptr_mut(channel)?;
375 Some(unsafe { std::slice::from_raw_parts_mut(buffer, self.len) })
376 }
377
378 fn channel_ptr(&self, channel: crate::filter::AudioChannel) -> Option<*const f32> {
379 match i32::from(channel) {
380 0 if !self.raw.buffer0.is_null() => Some(self.raw.buffer0),
381 1 if self.raw.channel_num >= 2 && !self.raw.buffer1.is_null() => Some(self.raw.buffer1),
382 _ => None,
383 }
384 }
385
386 fn channel_ptr_mut(&mut self, channel: crate::filter::AudioChannel) -> Option<*mut f32> {
387 match i32::from(channel) {
388 0 if !self.raw.buffer0.is_null() => Some(self.raw.buffer0),
389 1 if self.raw.channel_num >= 2 && !self.raw.buffer1.is_null() => Some(self.raw.buffer1),
390 _ => None,
391 }
392 }
393}
394
395impl CacheFileImageReadGuard {
396 pub fn width(&self) -> usize {
398 self.raw.width as usize
399 }
400
401 pub fn height(&self) -> usize {
403 self.raw.height as usize
404 }
405
406 pub fn pitch(&self) -> usize {
408 self.raw.pitch as usize
409 }
410
411 pub fn format(&self) -> CacheImagePixelFormat {
413 self.raw.format.into()
414 }
415
416 pub fn as_u8_slice(&self) -> &[u8] {
418 unsafe { std::slice::from_raw_parts(self.raw.buffer as *const u8, self.byte_len) }
419 }
420
421 pub fn as_ptr(&self) -> *const c_void {
423 self.raw.buffer
424 }
425}
426
427pub fn get_image_cache(
429 identifier: &impl AsCacheIdentifier,
430 name: &str,
431) -> Result<Option<CacheImageReadGuard>, CacheError> {
432 let wide_name = CWString::new(name)?;
433 let identifier = identifier.as_cache_identifier();
434 let raw = with_cache_handle(|handle| unsafe {
435 ((*handle).get_image_cache)(identifier, wide_name.as_ptr())
436 })?;
437 if raw.buffer.is_null() {
438 Ok(None)
439 } else {
440 Ok(Some(image_read_guard(raw)?))
441 }
442}
443
444pub fn get_image_cache_mut(
446 identifier: &impl AsCacheIdentifier,
447 name: &str,
448) -> Result<Option<CacheImageWriteGuard>, CacheError> {
449 let wide_name = CWString::new(name)?;
450 let identifier = identifier.as_cache_identifier();
451 let raw = with_cache_handle(|handle| unsafe {
452 ((*handle).get_image_cache)(identifier, wide_name.as_ptr())
453 })?;
454 if raw.buffer.is_null() {
455 Ok(None)
456 } else {
457 Ok(Some(image_write_guard(raw)?))
458 }
459}
460
461pub fn create_image_cache(
463 identifier: &impl AsCacheIdentifier,
464 name: &str,
465 width: usize,
466 height: usize,
467) -> Result<CacheImageWriteGuard, CacheError> {
468 let wide_name = CWString::new(name)?;
469 let width = i32::try_from(width).map_err(|_| CacheError::ValueOutOfRange)?;
470 let height = i32::try_from(height).map_err(|_| CacheError::ValueOutOfRange)?;
471 let identifier = identifier.as_cache_identifier();
472 let raw = with_cache_handle(|handle| unsafe {
473 ((*handle).create_image_cache)(identifier, wide_name.as_ptr(), width, height)
474 })?;
475 image_write_guard(raw)
476}
477
478pub fn get_audio_cache(
480 identifier: &impl AsCacheIdentifier,
481 name: &str,
482) -> Result<Option<CacheAudioReadGuard>, CacheError> {
483 let wide_name = CWString::new(name)?;
484 let identifier = identifier.as_cache_identifier();
485 let raw = with_cache_handle(|handle| unsafe {
486 ((*handle).get_audio_cache)(identifier, wide_name.as_ptr())
487 })?;
488 if raw.buffer0.is_null() {
489 Ok(None)
490 } else {
491 Ok(Some(audio_read_guard(raw)?))
492 }
493}
494
495pub fn get_audio_cache_mut(
497 identifier: &impl AsCacheIdentifier,
498 name: &str,
499) -> Result<Option<CacheAudioWriteGuard>, CacheError> {
500 let wide_name = CWString::new(name)?;
501 let identifier = identifier.as_cache_identifier();
502 let raw = with_cache_handle(|handle| unsafe {
503 ((*handle).get_audio_cache)(identifier, wide_name.as_ptr())
504 })?;
505 if raw.buffer0.is_null() {
506 Ok(None)
507 } else {
508 Ok(Some(audio_write_guard(raw)?))
509 }
510}
511
512pub fn create_audio_cache(
514 identifier: &impl AsCacheIdentifier,
515 name: &str,
516 sample_num: usize,
517 channel_num: usize,
518) -> Result<CacheAudioWriteGuard, CacheError> {
519 if !(1..=2).contains(&channel_num) {
520 return Err(CacheError::InvalidAudioChannel);
521 }
522 let wide_name = CWString::new(name)?;
523 let sample_num = i32::try_from(sample_num).map_err(|_| CacheError::ValueOutOfRange)?;
524 let channel_num = i32::try_from(channel_num).map_err(|_| CacheError::ValueOutOfRange)?;
525 let identifier = identifier.as_cache_identifier();
526 let raw = with_cache_handle(|handle| unsafe {
527 ((*handle).create_audio_cache)(identifier, wide_name.as_ptr(), sample_num, channel_num)
528 })?;
529 audio_write_guard(raw)
530}
531
532pub fn clear_image_cache(
534 identifier: &impl AsCacheIdentifier,
535 name: &str,
536) -> Result<(), CacheError> {
537 let wide_name = CWString::new(name)?;
538 let identifier = identifier.as_cache_identifier();
539 with_cache_handle(|handle| unsafe {
540 ((*handle).clear_image_cache)(identifier, wide_name.as_ptr())
541 })?;
542 Ok(())
543}
544
545pub fn clear_audio_cache(
547 identifier: &impl AsCacheIdentifier,
548 name: &str,
549) -> Result<(), CacheError> {
550 let wide_name = CWString::new(name)?;
551 let identifier = identifier.as_cache_identifier();
552 with_cache_handle(|handle| unsafe {
553 ((*handle).clear_audio_cache)(identifier, wide_name.as_ptr())
554 })?;
555 Ok(())
556}
557
558pub fn get_video_file_info(path: impl AsRef<Path>) -> Result<Option<VideoFileInfo>, CacheError> {
560 let file = CWString::new(&path.as_ref().to_string_lossy())?;
561 let mut raw = std::mem::MaybeUninit::<aviutl2_sys::cache2::VIDEO_INFO>::uninit();
562 let success = with_cache_handle(|handle| unsafe {
563 ((*handle).get_video_file_info)(
564 file.as_ptr(),
565 raw.as_mut_ptr(),
566 std::mem::size_of::<aviutl2_sys::cache2::VIDEO_INFO>() as i32,
567 )
568 })?;
569 if !success {
570 return Ok(None);
571 }
572 let raw = unsafe { raw.assume_init() };
573 Ok(Some(VideoFileInfo {
574 total_time: raw.total_time,
575 frame_num: usize::try_from(raw.frame_num).map_err(|_| CacheError::ValueOutOfRange)?,
576 track_num: usize::try_from(raw.track_num).map_err(|_| CacheError::ValueOutOfRange)?,
577 width: usize::try_from(raw.width).map_err(|_| CacheError::ValueOutOfRange)?,
578 height: usize::try_from(raw.height).map_err(|_| CacheError::ValueOutOfRange)?,
579 fps: Rational32::new(raw.rate, raw.scale),
580 }))
581}
582
583pub fn get_audio_file_info(path: impl AsRef<Path>) -> Result<Option<AudioFileInfo>, CacheError> {
585 let file = CWString::new(&path.as_ref().to_string_lossy())?;
586 let mut raw = std::mem::MaybeUninit::<aviutl2_sys::cache2::AUDIO_INFO>::uninit();
587 let success = with_cache_handle(|handle| unsafe {
588 ((*handle).get_audio_file_info)(
589 file.as_ptr(),
590 raw.as_mut_ptr(),
591 std::mem::size_of::<aviutl2_sys::cache2::AUDIO_INFO>() as i32,
592 )
593 })?;
594 if !success {
595 return Ok(None);
596 }
597 let raw = unsafe { raw.assume_init() };
598 Ok(Some(AudioFileInfo {
599 total_time: raw.total_time,
600 sample_num: usize::try_from(raw.sample_num).map_err(|_| CacheError::ValueOutOfRange)?,
601 track_num: usize::try_from(raw.track_num).map_err(|_| CacheError::ValueOutOfRange)?,
602 rate: raw.rate,
603 channel: usize::try_from(raw.channel).map_err(|_| CacheError::ValueOutOfRange)?,
604 }))
605}
606
607pub fn get_image_file_cache(
609 path: impl AsRef<Path>,
610) -> Result<Option<CacheFileImageReadGuard>, CacheError> {
611 let file = CWString::new(&path.as_ref().to_string_lossy())?;
612 let raw =
613 with_cache_handle(|handle| unsafe { ((*handle).get_image_file_cache)(file.as_ptr()) })?;
614 if raw.buffer.is_null() {
615 Ok(None)
616 } else {
617 Ok(Some(file_image_read_guard(raw)?))
618 }
619}
620
621pub fn get_video_file_cache(
623 path: impl AsRef<Path>,
624 track: usize,
625 frame: usize,
626) -> Result<Option<CacheFileImageReadGuard>, CacheError> {
627 let file = CWString::new(&path.as_ref().to_string_lossy())?;
628 let track = i32::try_from(track).map_err(|_| CacheError::ValueOutOfRange)?;
629 let frame = i32::try_from(frame).map_err(|_| CacheError::ValueOutOfRange)?;
630 let raw = with_cache_handle(|handle| unsafe {
631 ((*handle).get_video_file_cache)(file.as_ptr(), track, frame)
632 })?;
633 if raw.buffer.is_null() {
634 Ok(None)
635 } else {
636 Ok(Some(file_image_read_guard(raw)?))
637 }
638}
639
640pub fn get_video_file_cache_by_time(
642 path: impl AsRef<Path>,
643 track: usize,
644 time: f64,
645) -> Result<Option<CacheFileImageReadGuard>, CacheError> {
646 let file = CWString::new(&path.as_ref().to_string_lossy())?;
647 let track = i32::try_from(track).map_err(|_| CacheError::ValueOutOfRange)?;
648 let raw = with_cache_handle(|handle| unsafe {
649 ((*handle).get_video_file_cache_by_time)(file.as_ptr(), track, time)
650 })?;
651 if raw.buffer.is_null() {
652 Ok(None)
653 } else {
654 Ok(Some(file_image_read_guard(raw)?))
655 }
656}
657
658pub fn get_audio_file_data(
668 path: impl AsRef<Path>,
669 track: usize,
670 sample_index: usize,
671 buffer0: &mut [f32],
672 buffer1: &mut [f32],
673) -> Result<usize, CacheError> {
674 assert_eq!(
675 buffer0.len(),
676 buffer1.len(),
677 "Audio buffers must have the same length"
678 );
679 let file = CWString::new(&path.as_ref().to_string_lossy())?;
680 let track = i32::try_from(track).map_err(|_| CacheError::ValueOutOfRange)?;
681 let sample_index = i64::try_from(sample_index).map_err(|_| CacheError::ValueOutOfRange)?;
682 let sample_num = i32::try_from(buffer0.len()).map_err(|_| CacheError::ValueOutOfRange)?;
683 let read = with_cache_handle(|handle| unsafe {
684 ((*handle).get_audio_file_data)(
685 file.as_ptr(),
686 track,
687 sample_index,
688 sample_num,
689 buffer0.as_mut_ptr(),
690 buffer1.as_mut_ptr(),
691 )
692 })?;
693 usize::try_from(read).map_err(|_| CacheError::ValueOutOfRange)
694}
695
696fn image_read_guard(
697 raw: aviutl2_sys::cache2::CACHE_IMAGE,
698) -> Result<CacheImageReadGuard, CacheError> {
699 let len = image_len(&raw)?;
700 let access = CacheAccessGuard::read(raw.buffer as usize);
701 Ok(CacheImageReadGuard {
702 _access: access,
703 raw,
704 len,
705 })
706}
707
708fn image_write_guard(
709 raw: aviutl2_sys::cache2::CACHE_IMAGE,
710) -> Result<CacheImageWriteGuard, CacheError> {
711 if raw.buffer.is_null() {
712 return Err(CacheError::ApiCallFailed);
713 }
714 let len = image_len(&raw)?;
715 let access = CacheAccessGuard::write(raw.buffer as usize);
716 Ok(CacheImageWriteGuard {
717 _access: access,
718 raw,
719 len,
720 })
721}
722
723fn audio_read_guard(
724 raw: aviutl2_sys::cache2::CACHE_AUDIO,
725) -> Result<CacheAudioReadGuard, CacheError> {
726 let len = audio_len(&raw)?;
727 let access = CacheAccessGuard::read(raw.buffer0 as usize);
728 Ok(CacheAudioReadGuard {
729 _access: access,
730 raw,
731 len,
732 })
733}
734
735fn audio_write_guard(
736 raw: aviutl2_sys::cache2::CACHE_AUDIO,
737) -> Result<CacheAudioWriteGuard, CacheError> {
738 if raw.buffer0.is_null() {
739 return Err(CacheError::ApiCallFailed);
740 }
741 let len = audio_len(&raw)?;
742 let access = CacheAccessGuard::write(raw.buffer0 as usize);
743 Ok(CacheAudioWriteGuard {
744 _access: access,
745 raw,
746 len,
747 })
748}
749
750fn file_image_read_guard(
751 raw: aviutl2_sys::cache2::CACHE_FILE_IMAGE,
752) -> Result<CacheFileImageReadGuard, CacheError> {
753 let byte_len = file_image_byte_len(&raw)?;
754 let access = CacheAccessGuard::read(raw.buffer as usize);
755 Ok(CacheFileImageReadGuard {
756 _access: access,
757 raw,
758 byte_len,
759 })
760}
761
762fn image_len(raw: &aviutl2_sys::cache2::CACHE_IMAGE) -> Result<usize, CacheError> {
763 let width = usize::try_from(raw.width).map_err(|_| CacheError::ValueOutOfRange)?;
764 let height = usize::try_from(raw.height).map_err(|_| CacheError::ValueOutOfRange)?;
765 width.checked_mul(height).ok_or(CacheError::ValueOutOfRange)
766}
767
768fn file_image_byte_len(raw: &aviutl2_sys::cache2::CACHE_FILE_IMAGE) -> Result<usize, CacheError> {
769 let pitch = usize::try_from(raw.pitch).map_err(|_| CacheError::ValueOutOfRange)?;
770 let height = usize::try_from(raw.height).map_err(|_| CacheError::ValueOutOfRange)?;
771 pitch.checked_mul(height).ok_or(CacheError::ValueOutOfRange)
772}
773
774fn audio_len(raw: &aviutl2_sys::cache2::CACHE_AUDIO) -> Result<usize, CacheError> {
775 usize::try_from(raw.sample_num).map_err(|_| CacheError::ValueOutOfRange)
776}
777
778fn with_cache_handle<T>(
779 f: impl FnOnce(*mut aviutl2_sys::cache2::CACHE_HANDLE) -> T,
780) -> Result<T, CacheError> {
781 let handle = CACHE_HANDLE.get().expect("Cache handle is not initialized");
782 let handle = handle.lock().unwrap();
783 if handle.0.is_null() {
784 panic!("Cache handle raw pointer is null");
785 }
786 Ok(f(handle.0))
787}