pub use anyhow::Result as AnyResult;
use zerocopy::{Immutable, IntoBytes};
pub use half::{self, f16};
pub use num_rational::{self, Rational32};
pub use raw_window_handle::{self, Win32WindowHandle};
#[derive(Debug, Clone)]
pub struct FileFilter {
pub name: String,
pub extensions: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, IntoBytes, Immutable)]
#[repr(C)]
pub struct Yc48 {
pub y: i16,
pub cb: i16,
pub cr: i16,
}
impl Yc48 {
pub fn from_yuy2(yuy2: (u8, u8, u8, u8)) -> (Self, Self) {
let (y1, u, y2, v) = yuy2;
let ny1 = ((y1 as u16 * 1197) >> 6) - 299;
let ny2 = ((y2 as u16 * 1197) >> 6) - 299;
let ncb = ((u as u16 - 128) * 4681 + 164) >> 8;
let ncr = ((v as u16 - 128) * 4681 + 164) >> 8;
(
Self {
y: ny1 as i16,
cb: ncb as i16,
cr: ncr as i16,
},
Self {
y: ((ny1 + ny2) >> 1) as i16,
cb: ncb as i16,
cr: ncr as i16,
},
)
}
pub fn to_yuy2(self, other: Yc48) -> (u8, u8, u8, u8) {
let y1 = ((self.y * 219 + 383) >> 12) + 16;
let y2 = ((other.y * 219 + 383) >> 12) + 16;
let u = (((self.cb + 2048) * 7 + 66) >> 7) + 16;
let v = (((self.cr + 2048) * 7 + 66) >> 7) + 16;
let y1 = y1.min(255) as u8;
let y2 = y2.min(255) as u8;
let u = u.min(255) as u8;
let v = v.min(255) as u8;
(y1, u, y2, v)
}
pub fn from_rgb(self, rgb: (u8, u8, u8)) -> Self {
let (r, g, b) = rgb;
let r = i16::from(r);
let g = i16::from(g);
let b = i16::from(b);
let y = ((4918 * r + 354) >> 10) + ((9655 * g + 585) >> 10) + ((1875 * b + 523) >> 10);
let cb = ((-2775 * r + 240) >> 10) + ((-5449 * g + 515) >> 10) + ((8224 * b + 256) >> 10);
let cr = ((8224 * r + 256) >> 10) + ((-6887 * g + 110) >> 10) + ((-1337 * b + 646) >> 10);
Yc48 { y, cb, cr }
}
pub fn to_rgb(self) -> (u8, u8, u8) {
let y = self.y as i32;
let cr = self.cr as i32;
let cb = self.cr as i32;
let r = (255 * y + ((((22881 * cr) >> 16) + 3) << 10)) >> 12;
let g = (255 * y + ((((-5616 * cb) >> 16) + ((-11655 * cr) >> 16) + 3) << 10)) >> 12;
let b = (255 * y + ((((28919 * cb) >> 16) + 3) << 10)) >> 12;
let r = r.min(255) as u8;
let g = g.min(255) as u8;
let b = b.min(255) as u8;
(r, g, b)
}
}
pub(crate) fn format_file_filters(file_filters: &[FileFilter]) -> String {
let mut file_filter = String::new();
for filter in file_filters {
if !file_filter.is_empty() {
file_filter.push('\x00');
}
let display = format!(
"{} ({})",
filter.name,
filter
.extensions
.iter()
.map(|ext| {
if ext.is_empty() {
"*".to_string()
} else {
ext.to_string()
}
})
.collect::<Vec<_>>()
.join(", "),
);
file_filter.push_str(&display);
file_filter.push('\x00');
file_filter.push_str(
&filter
.extensions
.iter()
.map(|ext| {
if ext.is_empty() {
"*".to_string()
} else {
format!("*.{ext}")
}
})
.collect::<Vec<_>>()
.join(";"),
);
file_filter.push('\x00');
}
file_filter
}
pub(crate) enum LeakedPtrType {
WideString,
BitmapInfoHeader,
WaveFormatEx,
}
pub(crate) struct LeakManager {
ptrs: std::sync::Mutex<Vec<(LeakedPtrType, usize)>>,
}
pub(crate) trait IntoLeakedPtr {
fn into_leaked_ptr(self) -> (LeakedPtrType, usize);
}
#[duplicate::duplicate_item(
OriginalType EnumValue;
[aviutl2_sys::input2::WAVEFORMATEX] [WaveFormatEx];
[aviutl2_sys::output2::BITMAPINFOHEADER] [BitmapInfoHeader];
)]
impl IntoLeakedPtr for OriginalType {
fn into_leaked_ptr(self) -> (LeakedPtrType, usize) {
let boxed = Box::new(self);
let ptr = Box::into_raw(boxed) as usize;
(LeakedPtrType::EnumValue, ptr)
}
}
impl LeakManager {
pub fn new() -> Self {
Self {
ptrs: std::sync::Mutex::new(Vec::new()),
}
}
pub fn leak<T: IntoLeakedPtr>(&self, value: T) -> *const T {
log::debug!("Leaking memory for type {}", std::any::type_name::<T>());
let mut ptrs = self.ptrs.lock().unwrap();
let leaked = value.into_leaked_ptr();
let ptr = leaked.1;
ptrs.push(leaked);
ptr as *const T
}
pub fn leak_as_wide_string(&self, s: &str) -> *const u16 {
log::debug!("Leaking wide string: {}", s);
let mut wide: Vec<u16> = s.encode_utf16().collect();
wide.push(0); let boxed = wide.into_boxed_slice();
let ptr = Box::into_raw(boxed) as *mut u16 as usize;
let mut ptrs = self.ptrs.lock().unwrap();
ptrs.push((LeakedPtrType::WideString, ptr));
ptr as *const u16
}
pub fn free_leaked_memory(&self) {
let mut ptrs = self.ptrs.lock().unwrap();
log::debug!("Freeing {} leaked pointers", ptrs.len());
for (ptr_type, ptr) in ptrs.drain(..) {
unsafe {
match ptr_type {
LeakedPtrType::WideString => {
let _ = Box::from_raw(ptr as *mut u16);
}
LeakedPtrType::BitmapInfoHeader => {
let _ = Box::from_raw(ptr as *mut aviutl2_sys::output2::BITMAPINFOHEADER);
}
LeakedPtrType::WaveFormatEx => {
let _ = Box::from_raw(ptr as *mut aviutl2_sys::input2::WAVEFORMATEX);
}
}
}
}
}
}
pub(crate) fn load_wide_string(ptr: *const u16) -> String {
if ptr.is_null() {
return String::new();
}
let mut len = 0;
while unsafe { *ptr.add(len) } != 0 {
len += 1;
}
unsafe { String::from_utf16_lossy(std::slice::from_raw_parts(ptr, len)) }
}
pub(crate) fn alert_error(error: &anyhow::Error) {
let _ = native_dialog::DialogBuilder::message()
.set_title("エラー")
.set_level(native_dialog::MessageLevel::Error)
.set_text(format!("エラーが発生しました: {error}"))
.alert()
.show();
}