aviutl2\output/
video_frame.rs

1//! 動画フレームのフォーマットを表すトレイトと型。
2
3use crate::{
4    common::f16,
5    output::{VideoOutputInfo, Yc48},
6};
7use std::{
8    ops::Deref,
9    sync::{Arc, atomic::AtomicUsize},
10};
11
12/// 動画フレームを表すトレイト。
13/// aviutl2-rsでは、このトレイトを実装した型で動画フレームのフォーマットを指定します。
14pub trait FromRawVideoFrame {
15    /// 動画フレームのフォーマットを表す定数。
16    const FORMAT: u32;
17
18    /// 動画フレームのフォーマットが出力情報に適合するかをチェックする。
19    /// 例えば、[`Yuy2VideoFrame`](YUV
20    /// 4:2:2)を使用する場合は、出力情報の幅と高さが偶数であることを確認します。
21    fn check(video: &VideoOutputInfo) -> Result<(), String>;
22
23    /// 動画フレームを生のポインタから取得する。
24    ///
25    /// # Safety
26    /// func_get_videoの戻り値のポインタのみが許容される。
27    unsafe fn from_raw(
28        video: &VideoOutputInfo,
29        frame_data_ptr: *const u8,
30        last_frame_id: Arc<AtomicUsize>,
31        frame_id: usize,
32    ) -> Self;
33}
34
35duplicate::duplicate! {
36    [
37        Name                Type                   Doc;
38        [RgbVideoFrame]     [(u8, u8, u8)]         ["(u8, u8, u8) で表されるRGBの動画フレーム。"];
39        [Yuy2VideoFrame]    [(u8, u8, u8, u8)]     ["(u8, u8, u8, u8) で表されるYUV 4:2:2の動画フレーム。"];
40        [Hf64VideoFrame]    [(f16, f16, f16, f16)] ["(f16, f16, f16, f16) で表されるRGBAの動画フレーム。"];
41        [Yc48VideoFrame]    [Yc48]                 ["YC48形式の動画フレーム。"];
42        [Pa64VideoFrame]    [(u16, u16, u16, u16)] ["(u16, u16, u16, u16) で表されるRGBAの動画フレーム。"];
43
44        [RawBgrVideoFrame]  [u8]                   ["生のBGR24形式の動画フレームデータ。"];
45        [RawYuy2VideoFrame] [u8]                   ["生のYUV 4:2:2形式の動画フレームデータ。"];
46        [RawHf64VideoFrame] [f16]                  ["生のDXGI_FORMAT_R16G16B16A16_FLOAT(乗算済みα)形式の動画フレームデータ。"];
47        [RawYc48VideoFrame] [i16]                  ["生のYC48形式の動画フレームデータ。"];
48        [RawPa64VideoFrame] [u16]                  ["生のDXGI_FORMAT_R16G16B16A16_UNORM(乗算済みα)形式の動画フレームデータ。"];
49    ]
50    #[doc = Doc]
51    #[derive(Debug, Clone)]
52    pub struct Name {
53        pub data: Vec<Type>,
54    }
55    impl Deref for Name {
56        type Target = [Type];
57
58        fn deref(&self) -> &Self::Target {
59            &self.data
60        }
61    }
62}
63
64duplicate::duplicate! {
65    [
66        Name                        OwnedName           ParsedName       Type                   Doc;
67        [BorrowedRawBgrVideoFrame]  [RawBgrVideoFrame]  [RgbVideoFrame]  [u8]                   ["生のBGR24形式の動画フレームデータ。"];
68        [BorrowedRawYuy2VideoFrame] [RawYuy2VideoFrame] [Yuy2VideoFrame] [u8]                   ["生のYUV 4:2:2形式の動画フレームデータ。"];
69        [BorrowedRawHf64VideoFrame] [RawHf64VideoFrame] [Hf64VideoFrame] [f16]                  ["生のDXGI_FORMAT_R16G16B16A16_FLOAT(乗算済みα)形式の動画フレームデータ。"];
70        [BorrowedRawYc48VideoFrame] [RawYc48VideoFrame] [Yc48VideoFrame] [i16]                  ["生のYC48形式の動画フレームデータ。"];
71        [BorrowedRawPa64VideoFrame] [RawPa64VideoFrame] [Pa64VideoFrame] [u16]                  ["生のDXGI_FORMAT_R16G16B16A16_UNORM(乗算済みα)形式の動画フレームデータ。"];
72    ]
73    #[doc = Doc]
74    #[doc = concat!("[`", stringify!(OwnedName), "`]や[`", stringify!(ParsedName), "`]とは違い、フレームデータを所有しません。")]
75    #[derive(Debug)]
76    pub struct Name {
77        data: *const Type,
78        length: usize,
79
80        last_frame_id: Arc<AtomicUsize>,
81        frame_id: usize,
82
83        info: VideoOutputInfo,
84    }
85    impl Name {
86        /// この型が参照するデータの長さを返します。
87        pub fn len(&self) -> usize {
88            self.length
89        }
90
91        /// この型が参照するデータが空かどうかを返します。
92        ///
93        /// # Note
94        ///
95        /// 常に`false`を返します。
96        pub fn is_empty(&self) -> bool {
97            false
98        }
99
100        /// この型の内部のポインタを返します。
101        pub fn as_ptr(&self) -> *const Type {
102            self.data
103        }
104
105        /// この型がまだ有効かどうかを返します。
106        pub fn is_valid(&self) -> bool {
107            self.last_frame_id.load(std::sync::atomic::Ordering::SeqCst) == self.frame_id
108        }
109
110        /// この型の持っているデータをスライスとして返します。
111        ///
112        /// # Panics
113        ///
114        /// 次のフレーム取得が行われた後や、[`OutputInfo`][`super::OutputInfo`]が破棄された後に呼び出すとパニックになります。
115        pub fn as_slice(&self) -> &[Type] {
116            assert!(
117                self.is_valid(),
118                "The frame data has been invalidated. This can happen if a new frame is fetched"
119            );
120            unsafe { self.as_slice_unchecked() }
121        }
122
123        /// この型の持っているデータをスライスとして返します。
124        ///
125        /// # Safety
126        ///
127        /// 次のフレーム取得が行われた後や、[`OutputInfo`][`super::OutputInfo`]が破棄された後に呼び出すと未定義動作になります。
128        pub unsafe fn as_slice_unchecked(&self) -> &[Type] {
129            unsafe { std::slice::from_raw_parts(self.data, self.length) }
130        }
131
132        /// この型の持っているデータを所有する型に変換します。
133        ///
134        /// # Panics
135        ///
136        /// 次のフレーム取得が行われた後や、[`OutputInfo`][`super::OutputInfo`]が破棄された後に呼び出すとパニックになります。
137        pub fn to_owned(&self) -> OwnedName {
138            assert!(
139                self.is_valid(),
140                "The frame data has been invalidated. This can happen if a new frame is fetched"
141            );
142            unsafe { self.to_owned_unchecked() }
143        }
144
145        /// この型の持っているデータを所有する型に変換します。
146        ///
147        /// # Safety
148        ///
149        /// 次のフレーム取得が行われた後や、[`OutputInfo`][`super::OutputInfo`]が破棄された後に呼び出すと未定義動作になります。
150        pub unsafe fn to_owned_unchecked(&self) -> OwnedName {
151            OwnedName {
152                data: unsafe { std::slice::from_raw_parts(self.data, self.length).to_vec() },
153            }
154        }
155
156        /// この型の持っているデータを解析した型に変換します。
157        ///
158        /// # Panics
159        ///
160        /// 次のフレーム取得が行われた後や、[`OutputInfo`][`super::OutputInfo`]が破棄された後に呼び出すとパニックになります。
161        pub fn to_parsed(&self) -> ParsedName {
162            assert!(
163                self.is_valid(),
164                "The frame data has been invalidated. This can happen if a new frame is fetched"
165            );
166            unsafe { self.to_parsed_unchecked() }
167        }
168
169        /// この型の持っているデータを解析した型に変換します。
170        ///
171        /// # Safety
172        ///
173        /// 次のフレーム取得が行われた後や、[`OutputInfo`][`super::OutputInfo`]が破棄された後に呼び出すと未定義動作になります。
174        pub unsafe fn to_parsed_unchecked(&self) -> ParsedName {
175            #[allow(clippy::unnecessary_cast)]
176            unsafe { ParsedName::from_raw(&self.info, self.data as *const u8, self.last_frame_id.clone(), self.frame_id)}
177        }
178    }
179}
180
181impl FromRawVideoFrame for RgbVideoFrame {
182    const FORMAT: u32 = aviutl2_sys::common::BI_RGB;
183
184    fn check(_video: &VideoOutputInfo) -> Result<(), String> {
185        Ok(())
186    }
187    unsafe fn from_raw(
188        video: &VideoOutputInfo,
189        frame_data_ptr: *const u8,
190        _last_frame_id: Arc<AtomicUsize>,
191        _frame_id: usize,
192    ) -> Self {
193        let mut frame_buffer = Vec::with_capacity((video.width * video.height) as usize);
194        let frame_data_writer = frame_buffer.spare_capacity_mut();
195        for y in 0..video.height as usize {
196            for x in 0..video.width as usize {
197                let i = y * video.width as usize + x;
198                // Each pixel is represented by 3 bytes (BGR)
199                let pixel_r = unsafe { *frame_data_ptr.add(i * 3 + 2) };
200                let pixel_g = unsafe { *frame_data_ptr.add(i * 3 + 1) };
201                let pixel_b = unsafe { *frame_data_ptr.add(i * 3) };
202                frame_data_writer[(video.height as usize - 1 - y) * video.width as usize + x]
203                    .write((pixel_r, pixel_g, pixel_b));
204            }
205        }
206        unsafe {
207            frame_buffer.set_len((video.width * video.height) as usize);
208        }
209
210        Self { data: frame_buffer }
211    }
212}
213impl FromRawVideoFrame for Yuy2VideoFrame {
214    const FORMAT: u32 = aviutl2_sys::common::BI_YUY2;
215
216    fn check(video: &VideoOutputInfo) -> Result<(), String> {
217        if !video.width.is_multiple_of(2) || !video.height.is_multiple_of(2) {
218            return Err("YUY2 format requires even width and height".to_string());
219        }
220        Ok(())
221    }
222    unsafe fn from_raw(
223        video: &VideoOutputInfo,
224        frame_data_ptr: *const u8,
225        _last_frame_id: Arc<AtomicUsize>,
226        _frame_id: usize,
227    ) -> Self {
228        let mut frame_buffer = Vec::with_capacity((video.width * video.height / 2) as usize);
229        let frame_data_writer = frame_buffer.spare_capacity_mut();
230        for y in 0..video.height as usize {
231            for x in 0..(video.width / 2) as usize {
232                let i = y * video.width as usize + x;
233                // Each pixel is represented by 4 bytes (YUY2)
234                let d_y1 = unsafe { *frame_data_ptr.add(i * 4) };
235                let d_u = unsafe { *frame_data_ptr.add(i * 4 + 1) };
236                let d_y2 = unsafe { *frame_data_ptr.add(i * 4 + 2) };
237                let d_v = unsafe { *frame_data_ptr.add(i * 4 + 3) };
238
239                frame_data_writer[(video.height as usize - 1 - y) * video.width as usize + x]
240                    .write((d_y1, d_u, d_y2, d_v));
241            }
242        }
243        unsafe {
244            frame_buffer.set_len((video.width * video.height * 2) as usize);
245        }
246
247        Self { data: frame_buffer }
248    }
249}
250
251impl FromRawVideoFrame for Hf64VideoFrame {
252    const FORMAT: u32 = aviutl2_sys::common::BI_HF64;
253
254    fn check(_video: &VideoOutputInfo) -> Result<(), String> {
255        Ok(())
256    }
257    unsafe fn from_raw(
258        video: &VideoOutputInfo,
259        frame_data_ptr: *const u8,
260        _last_frame_id: Arc<AtomicUsize>,
261        _frame_id: usize,
262    ) -> Self {
263        let mut frame_buffer = Vec::with_capacity((video.width * video.height) as usize);
264        let frame_data_writer = frame_buffer.spare_capacity_mut();
265        let frame_data_ptr = frame_data_ptr as *const u16;
266        for y in 0..video.height as usize {
267            for x in 0..video.width as usize {
268                let i = y * video.width as usize + x;
269                // Each pixel is represented by 8 bytes (RGBA)
270                let pixel_r = unsafe { *frame_data_ptr.add(i * 4) };
271                let pixel_g = unsafe { *frame_data_ptr.add(i * 4 + 1) };
272                let pixel_b = unsafe { *frame_data_ptr.add(i * 4 + 2) };
273                let pixel_a = unsafe { *frame_data_ptr.add(i * 4 + 3) };
274                frame_data_writer[(video.height as usize - 1 - y) * video.width as usize + x]
275                    .write((
276                        f16::from_bits(pixel_r),
277                        f16::from_bits(pixel_g),
278                        f16::from_bits(pixel_b),
279                        f16::from_bits(pixel_a),
280                    ));
281            }
282        }
283        unsafe {
284            frame_buffer.set_len((video.width * video.height) as usize);
285        }
286
287        Self { data: frame_buffer }
288    }
289}
290impl FromRawVideoFrame for Yc48VideoFrame {
291    const FORMAT: u32 = aviutl2_sys::common::BI_YC48;
292
293    fn check(_video: &VideoOutputInfo) -> Result<(), String> {
294        Ok(())
295    }
296    unsafe fn from_raw(
297        video: &VideoOutputInfo,
298        frame_data_ptr: *const u8,
299        _last_frame_id: Arc<AtomicUsize>,
300        _frame_id: usize,
301    ) -> Self {
302        let mut frame_buffer = Vec::with_capacity((video.width * video.height) as usize);
303        let frame_data_writer = frame_buffer.spare_capacity_mut();
304        let frame_data_ptr = frame_data_ptr as *const i16;
305        for y in 0..video.height as usize {
306            for x in 0..video.width as usize {
307                let i = y * video.width as usize + x;
308                // Each pixel is represented by 6 bytes (YCbCr)
309                let pixel_y = unsafe { *frame_data_ptr.add(i * 3) };
310                let pixel_cr = unsafe { *frame_data_ptr.add(i * 3 + 1) };
311                let pixel_cb = unsafe { *frame_data_ptr.add(i * 3 + 2) };
312                frame_data_writer[(video.height as usize - 1 - y) * video.width as usize + x]
313                    .write(Yc48 {
314                        y: pixel_y,
315                        cr: pixel_cr,
316                        cb: pixel_cb,
317                    });
318            }
319        }
320        unsafe {
321            frame_buffer.set_len((video.width * video.height) as usize);
322        }
323
324        Self { data: frame_buffer }
325    }
326}
327impl FromRawVideoFrame for Pa64VideoFrame {
328    const FORMAT: u32 = aviutl2_sys::common::BI_PA64;
329
330    fn check(_video: &VideoOutputInfo) -> Result<(), String> {
331        Ok(())
332    }
333    unsafe fn from_raw(
334        video: &VideoOutputInfo,
335        frame_data_ptr: *const u8,
336        _last_frame_id: Arc<AtomicUsize>,
337        _frame_id: usize,
338    ) -> Self {
339        let mut frame_buffer = Vec::with_capacity((video.width * video.height) as usize);
340        let frame_data_writer = frame_buffer.spare_capacity_mut();
341        let frame_data_ptr = frame_data_ptr as *const u16;
342        for y in 0..video.height as usize {
343            for x in 0..video.width as usize {
344                let i = y * video.width as usize + x;
345                // Each pixel is represented by 8 bytes (RGBA)
346                let pixel_r = unsafe { *frame_data_ptr.add(i * 4) };
347                let pixel_g = unsafe { *frame_data_ptr.add(i * 4 + 1) };
348                let pixel_b = unsafe { *frame_data_ptr.add(i * 4 + 2) };
349                let pixel_a = unsafe { *frame_data_ptr.add(i * 4 + 3) };
350                frame_data_writer[(video.height as usize - 1 - y) * video.width as usize + x]
351                    .write((pixel_r, pixel_g, pixel_b, pixel_a));
352            }
353        }
354        unsafe {
355            frame_buffer.set_len((video.width * video.height) as usize);
356        }
357
358        Self { data: frame_buffer }
359    }
360}
361
362#[duplicate::duplicate_item(
363    Name                Type  elms FMT;
364    [RawBgrVideoFrame]  [u8]  [3]  [aviutl2_sys::common::BI_RGB];
365    [RawYuy2VideoFrame] [u8]  [2]  [aviutl2_sys::common::BI_YUY2];
366    [RawHf64VideoFrame] [f16] [4]  [aviutl2_sys::common::BI_HF64];
367    [RawYc48VideoFrame] [i16] [3]  [aviutl2_sys::common::BI_YC48];
368    [RawPa64VideoFrame] [u16] [4]  [aviutl2_sys::common::BI_PA64];
369)]
370impl FromRawVideoFrame for Name {
371    const FORMAT: u32 = FMT;
372
373    fn check(_video: &VideoOutputInfo) -> Result<(), String> {
374        Ok(())
375    }
376    unsafe fn from_raw(
377        video: &VideoOutputInfo,
378        frame_data_ptr: *const u8,
379        _last_frame_id: Arc<AtomicUsize>,
380        _frame_id: usize,
381    ) -> Self {
382        let frame_buffer = unsafe {
383            #[allow(clippy::unnecessary_cast)]
384            std::slice::from_raw_parts(
385                frame_data_ptr as *const Type,
386                (video.width * video.height * elms) as usize,
387            )
388            .to_owned()
389        };
390
391        Self { data: frame_buffer }
392    }
393}
394
395#[duplicate::duplicate_item(
396    Name                        Type  elms FMT;
397    [BorrowedRawBgrVideoFrame]  [u8]  [3]  [aviutl2_sys::common::BI_RGB];
398    [BorrowedRawYuy2VideoFrame] [u8]  [2]  [aviutl2_sys::common::BI_YUY2];
399    [BorrowedRawHf64VideoFrame] [f16] [4]  [aviutl2_sys::common::BI_HF64];
400    [BorrowedRawYc48VideoFrame] [i16] [3]  [aviutl2_sys::common::BI_YC48];
401    [BorrowedRawPa64VideoFrame] [u16] [4]  [aviutl2_sys::common::BI_PA64];
402)]
403impl FromRawVideoFrame for Name {
404    const FORMAT: u32 = FMT;
405
406    fn check(_video: &VideoOutputInfo) -> Result<(), String> {
407        Ok(())
408    }
409    unsafe fn from_raw(
410        video: &VideoOutputInfo,
411        frame_data_ptr: *const u8,
412        last_frame_id: Arc<AtomicUsize>,
413        frame_id: usize,
414    ) -> Self {
415        let length = (video.width * video.height * elms) as usize;
416
417        Self {
418            data: frame_data_ptr as _,
419            length,
420            info: video.clone(),
421            last_frame_id,
422            frame_id,
423        }
424    }
425}
426
427#[cfg(feature = "image")]
428impl FromRawVideoFrame for image::RgbImage {
429    const FORMAT: u32 = aviutl2_sys::common::BI_RGB;
430
431    fn check(_video: &VideoOutputInfo) -> Result<(), String> {
432        Ok(())
433    }
434    unsafe fn from_raw(
435        video: &VideoOutputInfo,
436        frame_data_ptr: *const u8,
437        _last_frame_id: Arc<AtomicUsize>,
438        _frame_id: usize,
439    ) -> Self {
440        let mut buffer = unsafe {
441            std::slice::from_raw_parts(frame_data_ptr, (video.width * video.height * 3) as usize)
442                .to_owned()
443        };
444        crate::utils::bgr_to_rgb_bytes(&mut buffer);
445        crate::utils::flip_vertical(&mut buffer, video.width as usize * 3, video.height as usize);
446        image::RgbImage::from_raw(video.width, video.height, buffer).unwrap()
447    }
448}
449
450#[cfg(feature = "image")]
451impl FromRawVideoFrame for image::ImageBuffer<image::Rgba<u16>, Vec<u16>> {
452    const FORMAT: u32 = aviutl2_sys::common::BI_PA64;
453
454    fn check(_video: &VideoOutputInfo) -> Result<(), String> {
455        Ok(())
456    }
457    unsafe fn from_raw(
458        video: &VideoOutputInfo,
459        frame_data_ptr: *const u8,
460        _last_frame_id: Arc<AtomicUsize>,
461        _frame_id: usize,
462    ) -> Self {
463        let frame_data_ptr = frame_data_ptr as *const u16;
464        let buffer = unsafe {
465            std::slice::from_raw_parts(frame_data_ptr, (video.width * video.height * 4) as usize)
466                .to_owned()
467        };
468        image::ImageBuffer::from_raw(video.width, video.height, buffer).unwrap()
469    }
470}
471
472#[cfg(feature = "image")]
473impl FromRawVideoFrame for image::Rgba32FImage {
474    const FORMAT: u32 = aviutl2_sys::common::BI_HF64;
475
476    fn check(_video: &VideoOutputInfo) -> Result<(), String> {
477        Ok(())
478    }
479    unsafe fn from_raw(
480        video: &VideoOutputInfo,
481        frame_data_ptr: *const u8,
482        _last_frame_id: Arc<AtomicUsize>,
483        _frame_id: usize,
484    ) -> Self {
485        let frame_data_ptr = frame_data_ptr as *const f16;
486        let buffer = unsafe {
487            std::slice::from_raw_parts(frame_data_ptr, (video.width * video.height * 4) as usize)
488                .iter()
489                .map(|&v| v.to_f32())
490                .collect::<Vec<_>>()
491        };
492        image::ImageBuffer::from_raw(video.width, video.height, buffer).unwrap()
493    }
494}