Skip to main content

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: &crate::output::VideoOutputInfo) -> Result<(), String>;
22
23    /// 動画フレームを生のポインタから取得する。
24    ///
25    /// # Safety
26    /// func_get_videoの戻り値のポインタのみが許容される。
27    unsafe fn from_raw(
28        video: &crate::output::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        let _ = video;
186        Ok(())
187    }
188    unsafe fn from_raw(
189        video: &VideoOutputInfo,
190        frame_data_ptr: *const u8,
191        last_frame_id: Arc<AtomicUsize>,
192        frame_id: usize,
193    ) -> Self {
194        let _ = (last_frame_id, frame_id);
195        let mut frame_buffer = Vec::with_capacity((video.width * video.height) as usize);
196        let frame_data_writer = frame_buffer.spare_capacity_mut();
197        for y in 0..video.height as usize {
198            for x in 0..video.width as usize {
199                let i = y * video.width as usize + x;
200                // Each pixel is represented by 3 bytes (BGR)
201                let pixel_r = unsafe { *frame_data_ptr.add(i * 3 + 2) };
202                let pixel_g = unsafe { *frame_data_ptr.add(i * 3 + 1) };
203                let pixel_b = unsafe { *frame_data_ptr.add(i * 3) };
204                frame_data_writer[(video.height as usize - 1 - y) * video.width as usize + x]
205                    .write((pixel_r, pixel_g, pixel_b));
206            }
207        }
208        unsafe {
209            frame_buffer.set_len((video.width * video.height) as usize);
210        }
211
212        Self { data: frame_buffer }
213    }
214}
215impl FromRawVideoFrame for Yuy2VideoFrame {
216    const FORMAT: u32 = aviutl2_sys::common::BI_YUY2;
217
218    fn check(video: &VideoOutputInfo) -> Result<(), String> {
219        if !video.width.is_multiple_of(2) || !video.height.is_multiple_of(2) {
220            return Err("YUY2 format requires even width and height".to_string());
221        }
222        Ok(())
223    }
224    unsafe fn from_raw(
225        video: &VideoOutputInfo,
226        frame_data_ptr: *const u8,
227        last_frame_id: Arc<AtomicUsize>,
228        frame_id: usize,
229    ) -> Self {
230        let _ = (last_frame_id, frame_id);
231        let mut frame_buffer = Vec::with_capacity((video.width * video.height / 2) as usize);
232        let frame_data_writer = frame_buffer.spare_capacity_mut();
233        for y in 0..video.height as usize {
234            for x in 0..(video.width / 2) as usize {
235                let i = y * video.width as usize + x;
236                // Each pixel is represented by 4 bytes (YUY2)
237                let d_y1 = unsafe { *frame_data_ptr.add(i * 4) };
238                let d_u = unsafe { *frame_data_ptr.add(i * 4 + 1) };
239                let d_y2 = unsafe { *frame_data_ptr.add(i * 4 + 2) };
240                let d_v = unsafe { *frame_data_ptr.add(i * 4 + 3) };
241
242                frame_data_writer[y * (video.width as usize / 2) + x].write((d_y1, d_u, d_y2, d_v));
243            }
244        }
245        unsafe {
246            frame_buffer.set_len((video.width * video.height * 2) as usize);
247        }
248
249        Self { data: frame_buffer }
250    }
251}
252
253impl FromRawVideoFrame for Hf64VideoFrame {
254    const FORMAT: u32 = aviutl2_sys::common::BI_HF64;
255
256    fn check(video: &VideoOutputInfo) -> Result<(), String> {
257        let _ = video;
258        Ok(())
259    }
260    unsafe fn from_raw(
261        video: &VideoOutputInfo,
262        frame_data_ptr: *const u8,
263        last_frame_id: Arc<AtomicUsize>,
264        frame_id: usize,
265    ) -> Self {
266        let _ = (last_frame_id, frame_id);
267        let mut frame_buffer = Vec::with_capacity((video.width * video.height) as usize);
268        let frame_data_writer = frame_buffer.spare_capacity_mut();
269        let frame_data_ptr = frame_data_ptr as *const u16;
270        for y in 0..video.height as usize {
271            for x in 0..video.width as usize {
272                let i = y * video.width as usize + x;
273                // Each pixel is represented by 8 bytes (RGBA)
274                let pixel_r = unsafe { *frame_data_ptr.add(i * 4) };
275                let pixel_g = unsafe { *frame_data_ptr.add(i * 4 + 1) };
276                let pixel_b = unsafe { *frame_data_ptr.add(i * 4 + 2) };
277                let pixel_a = unsafe { *frame_data_ptr.add(i * 4 + 3) };
278                frame_data_writer[y * video.width as usize + x].write((
279                    f16::from_bits(pixel_r),
280                    f16::from_bits(pixel_g),
281                    f16::from_bits(pixel_b),
282                    f16::from_bits(pixel_a),
283                ));
284            }
285        }
286        unsafe {
287            frame_buffer.set_len((video.width * video.height) as usize);
288        }
289
290        Self { data: frame_buffer }
291    }
292}
293impl FromRawVideoFrame for Yc48VideoFrame {
294    const FORMAT: u32 = aviutl2_sys::common::BI_YC48;
295
296    fn check(video: &VideoOutputInfo) -> Result<(), String> {
297        let _ = video;
298        Ok(())
299    }
300    unsafe fn from_raw(
301        video: &VideoOutputInfo,
302        frame_data_ptr: *const u8,
303        last_frame_id: Arc<AtomicUsize>,
304        frame_id: usize,
305    ) -> Self {
306        let _ = (last_frame_id, frame_id);
307        let mut frame_buffer = Vec::with_capacity((video.width * video.height) as usize);
308        let frame_data_writer = frame_buffer.spare_capacity_mut();
309        let frame_data_ptr = frame_data_ptr as *const i16;
310        for y in 0..video.height as usize {
311            for x in 0..video.width as usize {
312                let i = y * video.width as usize + x;
313                // Each pixel is represented by 6 bytes (YCbCr)
314                let pixel_y = unsafe { *frame_data_ptr.add(i * 3) };
315                let pixel_cr = unsafe { *frame_data_ptr.add(i * 3 + 1) };
316                let pixel_cb = unsafe { *frame_data_ptr.add(i * 3 + 2) };
317                frame_data_writer[y * video.width as usize + x].write(Yc48 {
318                    y: pixel_y,
319                    cr: pixel_cr,
320                    cb: pixel_cb,
321                });
322            }
323        }
324        unsafe {
325            frame_buffer.set_len((video.width * video.height) as usize);
326        }
327
328        Self { data: frame_buffer }
329    }
330}
331impl FromRawVideoFrame for Pa64VideoFrame {
332    const FORMAT: u32 = aviutl2_sys::common::BI_PA64;
333
334    fn check(video: &VideoOutputInfo) -> Result<(), String> {
335        let _ = video;
336        Ok(())
337    }
338    unsafe fn from_raw(
339        video: &VideoOutputInfo,
340        frame_data_ptr: *const u8,
341        last_frame_id: Arc<AtomicUsize>,
342        frame_id: usize,
343    ) -> Self {
344        let _ = (last_frame_id, frame_id);
345        let mut frame_buffer = Vec::with_capacity((video.width * video.height) as usize);
346        let frame_data_writer = frame_buffer.spare_capacity_mut();
347        let frame_data_ptr = frame_data_ptr as *const u16;
348        for y in 0..video.height as usize {
349            for x in 0..video.width as usize {
350                let i = y * video.width as usize + x;
351                // Each pixel is represented by 8 bytes (RGBA)
352                let pixel_r = unsafe { *frame_data_ptr.add(i * 4) };
353                let pixel_g = unsafe { *frame_data_ptr.add(i * 4 + 1) };
354                let pixel_b = unsafe { *frame_data_ptr.add(i * 4 + 2) };
355                let pixel_a = unsafe { *frame_data_ptr.add(i * 4 + 3) };
356                frame_data_writer[y * video.width as usize + x]
357                    .write((pixel_r, pixel_g, pixel_b, pixel_a));
358            }
359        }
360        unsafe {
361            frame_buffer.set_len((video.width * video.height) as usize);
362        }
363
364        Self { data: frame_buffer }
365    }
366}
367
368#[duplicate::duplicate_item(
369    Name                Type  elms FMT;
370    [RawBgrVideoFrame]  [u8]  [3]  [aviutl2_sys::common::BI_RGB];
371    [RawYuy2VideoFrame] [u8]  [2]  [aviutl2_sys::common::BI_YUY2];
372    [RawHf64VideoFrame] [f16] [4]  [aviutl2_sys::common::BI_HF64];
373    [RawYc48VideoFrame] [i16] [3]  [aviutl2_sys::common::BI_YC48];
374    [RawPa64VideoFrame] [u16] [4]  [aviutl2_sys::common::BI_PA64];
375)]
376impl FromRawVideoFrame for Name {
377    const FORMAT: u32 = FMT;
378
379    fn check(video: &VideoOutputInfo) -> Result<(), String> {
380        let _ = video;
381        Ok(())
382    }
383    unsafe fn from_raw(
384        video: &VideoOutputInfo,
385        frame_data_ptr: *const u8,
386        last_frame_id: Arc<AtomicUsize>,
387        frame_id: usize,
388    ) -> Self {
389        let _ = (last_frame_id, frame_id);
390        let frame_buffer = unsafe {
391            #[allow(clippy::unnecessary_cast)]
392            std::slice::from_raw_parts(
393                frame_data_ptr as *const Type,
394                (video.width * video.height * elms) as usize,
395            )
396            .to_owned()
397        };
398
399        Self { data: frame_buffer }
400    }
401}
402
403#[duplicate::duplicate_item(
404    Name                        Type  elms FMT;
405    [BorrowedRawBgrVideoFrame]  [u8]  [3]  [aviutl2_sys::common::BI_RGB];
406    [BorrowedRawYuy2VideoFrame] [u8]  [2]  [aviutl2_sys::common::BI_YUY2];
407    [BorrowedRawHf64VideoFrame] [f16] [4]  [aviutl2_sys::common::BI_HF64];
408    [BorrowedRawYc48VideoFrame] [i16] [3]  [aviutl2_sys::common::BI_YC48];
409    [BorrowedRawPa64VideoFrame] [u16] [4]  [aviutl2_sys::common::BI_PA64];
410)]
411impl FromRawVideoFrame for Name {
412    const FORMAT: u32 = FMT;
413
414    fn check(video: &VideoOutputInfo) -> Result<(), String> {
415        let _ = video;
416        Ok(())
417    }
418    unsafe fn from_raw(
419        video: &VideoOutputInfo,
420        frame_data_ptr: *const u8,
421        last_frame_id: Arc<AtomicUsize>,
422        frame_id: usize,
423    ) -> Self {
424        let length = (video.width * video.height * elms) as usize;
425
426        Self {
427            data: frame_data_ptr as _,
428            length,
429            info: video.clone(),
430            last_frame_id,
431            frame_id,
432        }
433    }
434}
435
436#[cfg(feature = "image")]
437impl FromRawVideoFrame for image::RgbImage {
438    const FORMAT: u32 = aviutl2_sys::common::BI_RGB;
439
440    fn check(video: &VideoOutputInfo) -> Result<(), String> {
441        let _ = video;
442        Ok(())
443    }
444    unsafe fn from_raw(
445        video: &VideoOutputInfo,
446        frame_data_ptr: *const u8,
447        last_frame_id: Arc<AtomicUsize>,
448        frame_id: usize,
449    ) -> Self {
450        let _ = (last_frame_id, frame_id);
451        let mut buffer = unsafe {
452            std::slice::from_raw_parts(frame_data_ptr, (video.width * video.height * 3) as usize)
453                .to_owned()
454        };
455        crate::utils::bgr_to_rgb_bytes(&mut buffer);
456        crate::utils::flip_vertical(&mut buffer, video.width as usize * 3, video.height as usize);
457        image::RgbImage::from_raw(video.width, video.height, buffer).unwrap()
458    }
459}
460
461#[cfg(feature = "image")]
462impl FromRawVideoFrame for image::ImageBuffer<image::Rgba<u16>, Vec<u16>> {
463    const FORMAT: u32 = aviutl2_sys::common::BI_PA64;
464
465    fn check(video: &VideoOutputInfo) -> Result<(), String> {
466        let _ = video;
467        Ok(())
468    }
469    unsafe fn from_raw(
470        video: &VideoOutputInfo,
471        frame_data_ptr: *const u8,
472        last_frame_id: Arc<AtomicUsize>,
473        frame_id: usize,
474    ) -> Self {
475        let _ = (last_frame_id, frame_id);
476        let frame_data_ptr = frame_data_ptr as *const u16;
477        let buffer = unsafe {
478            std::slice::from_raw_parts(frame_data_ptr, (video.width * video.height * 4) as usize)
479                .to_owned()
480        };
481        image::ImageBuffer::from_raw(video.width, video.height, buffer).unwrap()
482    }
483}
484
485#[cfg(feature = "image")]
486impl FromRawVideoFrame for image::Rgba32FImage {
487    const FORMAT: u32 = aviutl2_sys::common::BI_HF64;
488
489    fn check(video: &VideoOutputInfo) -> Result<(), String> {
490        let _ = video;
491        Ok(())
492    }
493    unsafe fn from_raw(
494        video: &VideoOutputInfo,
495        frame_data_ptr: *const u8,
496        last_frame_id: Arc<AtomicUsize>,
497        frame_id: usize,
498    ) -> Self {
499        let _ = (last_frame_id, frame_id);
500        let frame_data_ptr = frame_data_ptr as *const f16;
501        let buffer = unsafe {
502            std::slice::from_raw_parts(frame_data_ptr, (video.width * video.height * 4) as usize)
503                .iter()
504                .map(|&v| v.to_f32())
505                .collect::<Vec<_>>()
506        };
507        image::ImageBuffer::from_raw(video.width, video.height, buffer).unwrap()
508    }
509}