1use std::sync::{
2 Arc,
3 atomic::{AtomicUsize, Ordering},
4};
5
6use crate::{
7 common::{AnyResult, AviUtl2Info, FileFilter, Rational32, Win32WindowHandle, load_wide_string},
8 output::video_frame::FromRawVideoFrame,
9};
10use aviutl2_sys::output2::OUTPUT_INFO;
11
12#[derive(Debug, Clone)]
14pub struct OutputPluginTable {
15 pub name: String,
17 pub information: String,
20 pub output_type: OutputType,
22
23 pub file_filters: Vec<FileFilter>,
25
26 pub can_config: bool,
28}
29
30#[derive(Debug, Clone)]
32pub enum OutputType {
33 Video,
35 Audio,
37 Both,
39}
40
41impl OutputType {
42 pub(crate) fn to_bits(&self) -> i32 {
43 match self {
44 OutputType::Video => 1,
45 OutputType::Audio => 2,
46 OutputType::Both => 3,
47 }
48 }
49}
50
51#[derive(Debug, Clone)]
53pub struct OutputInfo {
54 pub video: Option<VideoOutputInfo>,
56 pub audio: Option<AudioOutputInfo>,
58 pub path: std::path::PathBuf,
60
61 pub(crate) internal: *mut OUTPUT_INFO,
62 pub(crate) last_frame_id: Arc<AtomicUsize>,
63}
64
65unsafe impl Send for OutputInfo {}
66unsafe impl Sync for OutputInfo {}
67
68#[derive(Debug, Clone)]
70pub struct VideoOutputInfo {
71 pub width: u32,
73 pub height: u32,
75 pub fps: Rational32,
77 pub num_frames: u32,
79}
80
81#[derive(Debug, Clone)]
83pub struct AudioOutputInfo {
84 pub sample_rate: u32,
86 pub num_samples: u32,
88 pub num_channels: u32,
90}
91
92pub trait OutputPlugin: Send + Sync + Sized {
95 fn new(info: AviUtl2Info) -> AnyResult<Self>;
97
98 fn plugin_info(&self) -> OutputPluginTable;
100
101 fn output(&self, info: OutputInfo) -> AnyResult<()>;
103
104 fn config(&self, _hwnd: Win32WindowHandle) -> AnyResult<()> {
106 Ok(())
107 }
108
109 fn config_text(&self) -> AnyResult<String> {
112 Ok(String::new())
113 }
114
115 fn with_instance<R>(f: impl FnOnce(&Self) -> R) -> R
121 where
122 Self: crate::output::__bridge::OutputSingleton,
123 {
124 <Self as crate::output::__bridge::OutputSingleton>::with_instance(f)
125 }
126
127 fn with_instance_mut<R>(f: impl FnOnce(&mut Self) -> R) -> R
133 where
134 Self: crate::output::__bridge::OutputSingleton,
135 {
136 <Self as crate::output::__bridge::OutputSingleton>::with_instance_mut(f)
137 }
138}
139
140pub trait FromRawAudioSamples: Sized + Send + Sync + Copy {
143 const FORMAT: u32;
145
146 unsafe fn from_raw(length: i32, num_channels: u32, audio_data_ptr: *const u8) -> Vec<Self>;
151}
152
153impl OutputInfo {
154 pub(crate) fn from_raw(oip: *mut aviutl2_sys::output2::OUTPUT_INFO) -> Self {
155 let raw = unsafe { &*oip };
156
157 Self {
158 video: if raw.flag & aviutl2_sys::output2::OUTPUT_INFO::FLAG_VIDEO != 0 {
159 Some(VideoOutputInfo {
160 width: raw.w as u32,
161 height: raw.h as u32,
162 fps: Rational32::new(raw.rate, raw.scale),
163 num_frames: raw.n as u32,
164 })
165 } else {
166 None
167 },
168 audio: if raw.flag & aviutl2_sys::output2::OUTPUT_INFO::FLAG_AUDIO != 0 {
169 Some(AudioOutputInfo {
170 sample_rate: raw.audio_rate as u32,
171 num_samples: raw.audio_n as u32,
172 num_channels: raw.audio_ch as u32,
173 })
174 } else {
175 None
176 },
177
178 path: std::path::PathBuf::from(unsafe { load_wide_string(raw.savefile) }),
179
180 internal: oip,
181 last_frame_id: Arc::new(AtomicUsize::new(0)),
182 }
183 }
184
185 pub fn get_video_frame<F: FromRawVideoFrame>(&self, frame: i32) -> Option<F> {
187 if let Some(video) = &self.video {
188 if F::check(video).is_err() {
189 return None;
190 }
191 if frame < 0 || frame >= video.num_frames as i32 {
192 return None;
193 }
194 unsafe { self.get_video_frame_unchecked::<F>(frame) }
195 } else {
196 None
197 }
198 }
199
200 pub unsafe fn get_video_frame_unchecked<F: FromRawVideoFrame>(&self, frame: i32) -> Option<F> {
208 let frame_ptr = unsafe { self.internal.as_mut().and_then(|oip| oip.func_get_video) }?;
209 let frame_data_ptr = frame_ptr(frame, F::FORMAT) as *mut u8;
210 let video = self.video.as_ref()?;
211 let current_frame_id = self.last_frame_id.fetch_add(1, Ordering::SeqCst) + 1;
212 let frame = unsafe {
213 F::from_raw(
214 video,
215 frame_data_ptr,
216 Arc::clone(&self.last_frame_id),
217 current_frame_id,
218 )
219 };
220 Some(frame)
221 }
222
223 pub fn get_video_frames_iter<F: FromRawVideoFrame>(&self) -> VideoFramesIterator<'_, F> {
225 VideoFramesIterator::new(self)
226 }
227
228 pub fn get_audio_samples<F: FromRawAudioSamples>(
230 &self,
231 start: i32,
232 length: i32,
233 ) -> Option<(Vec<F>, u32)> {
234 let audio = self.audio.as_ref()?;
235 let audio_ptr = unsafe { self.internal.as_mut().and_then(|oip| oip.func_get_audio) }?;
236 let mut readed = 0;
237 let audio_data_ptr = audio_ptr(start, length, &mut readed, F::FORMAT) as *mut u8;
238
239 let samples = unsafe { F::from_raw(length, audio.num_channels, audio_data_ptr) };
240
241 Some((samples, audio.num_channels))
242 }
243
244 pub fn get_mono_audio_samples<F: FromRawAudioSamples>(
247 &self,
248 start: i32,
249 length: i32,
250 ) -> Option<Vec<F>> {
251 let (samples, num_channels) = self.get_audio_samples(start, length)?;
252 if num_channels == 1 {
253 Some(samples)
254 } else {
255 Some(
256 samples
257 .chunks(num_channels as usize)
258 .map(|chunk| chunk[0])
259 .collect(),
260 )
261 }
262 }
263
264 pub fn get_mono_audio_samples_iter<F: FromRawAudioSamples>(
269 &'_ self,
270 length: i32,
271 ) -> MonoAudioSamplesIterator<'_, F> {
272 MonoAudioSamplesIterator::new(self, length)
273 }
274
275 pub fn get_stereo_audio_samples<F: FromRawAudioSamples>(
278 &self,
279 start: i32,
280 length: i32,
281 ) -> Option<Vec<(F, F)>> {
282 let (samples, num_channels) = self.get_audio_samples(start, length)?;
283 if num_channels == 2 {
284 Some(
285 samples
286 .chunks(num_channels as usize)
287 .map(|chunk| (chunk[0], chunk[1]))
288 .collect(),
289 )
290 } else {
291 None
292 }
293 }
294
295 pub fn get_stereo_audio_samples_iter<F: FromRawAudioSamples>(
300 &'_ self,
301 length: i32,
302 ) -> StereoAudioSamplesIterator<'_, F> {
303 StereoAudioSamplesIterator::new(self, length)
304 }
305
306 pub fn is_aborted(&self) -> bool {
308 let is_abort_func = unsafe { self.internal.as_mut().and_then(|oip| oip.func_is_abort) };
309 is_abort_func.is_none_or(|f| f())
310 }
311
312 pub fn update_display(&self, current_frame: i32, total_frames: i32) {
314 if let Some(func) = unsafe {
315 self.internal
316 .as_mut()
317 .and_then(|oip| oip.func_rest_time_disp)
318 } {
319 func(current_frame, total_frames);
320 }
321 }
322
323 pub fn set_buffer_size(&self, video_size: i32, audio_size: i32) {
326 if let Some(func) = unsafe {
327 self.internal
328 .as_mut()
329 .and_then(|oip| oip.func_set_buffer_size)
330 } {
331 func(video_size, audio_size);
332 }
333 }
334}
335
336impl Drop for OutputInfo {
337 fn drop(&mut self) {
338 self.last_frame_id.store(usize::MAX, Ordering::SeqCst);
339 }
340}
341
342#[derive(Debug, Clone)]
347pub struct VideoFramesIterator<'a, F: FromRawVideoFrame> {
348 output_info: &'a OutputInfo,
349 current_frame: i32,
350 total_frames: i32,
351 last_updated_time: std::time::Instant,
352 check_result: bool,
353 _marker: std::marker::PhantomData<F>,
354}
355
356impl<'a, F: FromRawVideoFrame> VideoFramesIterator<'a, F> {
357 pub(crate) fn new(output_info: &'a OutputInfo) -> Self {
358 let total_frames = output_info
359 .video
360 .as_ref()
361 .map_or(0, |v| v.num_frames as i32);
362 Self {
363 output_info,
364 current_frame: 0,
365 total_frames,
366 last_updated_time: std::time::Instant::now(),
367 check_result: output_info
368 .video
369 .as_ref()
370 .is_some_and(|v| F::check(v).is_ok()),
371 _marker: std::marker::PhantomData,
372 }
373 }
374}
375
376impl<'a, F: FromRawVideoFrame> Iterator for VideoFramesIterator<'a, F> {
377 type Item = (i32, F);
378
379 fn next(&mut self) -> Option<Self::Item> {
380 if !self.check_result {
381 return None;
382 }
383 if self.current_frame >= self.total_frames {
384 return None;
385 }
386
387 if self.output_info.is_aborted() {
388 return None;
389 }
390
391 let frame = unsafe {
392 self.output_info
393 .get_video_frame_unchecked(self.current_frame)
394 };
395 if let Some(frame_data) = frame {
396 let current_frame = self.current_frame;
397 self.current_frame += 1;
398 if self.last_updated_time.elapsed().as_secs_f32() > 0.1 {
399 self.output_info
400 .update_display(current_frame, self.total_frames);
401 self.last_updated_time = std::time::Instant::now();
402 }
403 Some((current_frame, frame_data))
404 } else {
405 None
406 }
407 }
408}
409
410duplicate::duplicate! {
411 [
412 Name method IterType Doc Also;
413 [MonoAudioSamplesIterator] [get_mono_audio_samples] [F] ["モノラル音声サンプルのイテレータ。"] ["[`OutputInfo::get_mono_audio_samples_iter`]"];
414 [StereoAudioSamplesIterator] [get_stereo_audio_samples] [(F, F)] ["ステレオ音声サンプルのイテレータ。"] ["[`OutputInfo::get_stereo_audio_samples_iter`]"];
415 ]
416
417 #[doc = Doc]
418 #[doc = Also]
421 #[derive(Debug, Clone)]
422 pub struct Name<'a, F: FromRawAudioSamples> {
423 output_info: &'a OutputInfo,
424 length: i32,
425 total_length: i32,
426 readed: i32,
427 _marker: std::marker::PhantomData<F>,
428 }
429
430 impl<'a, F: FromRawAudioSamples> Name<'a, F> {
431 pub(crate) fn new(output_info: &'a OutputInfo, length: i32) -> Self {
432 Self {
433 output_info,
434 length,
435 total_length: output_info.audio.as_ref().map_or(0, |a| a.num_samples as i32),
436 readed: 0,
437 _marker: std::marker::PhantomData,
438 }
439 }
440 }
441
442 impl<'a, F: FromRawAudioSamples> Iterator for Name<'a, F> {
443 type Item = (usize, Vec<IterType>);
444
445 fn next(&mut self) -> Option<Self::Item> {
446 if self.readed >= self.total_length {
447 return None;
448 }
449 if self.output_info.is_aborted() {
450 return None;
451 }
452
453 let length_to_read = self.length.min(self.total_length - self.readed);
454 let samples = self.output_info.method(self.readed, length_to_read);
455 if let Some(samples) = samples {
456 let start_frame = self.readed;
457 self.readed += samples.len() as i32;
458 Some((start_frame as usize, samples))
459 } else {
460 None
461 }
462 }
463 }
464}