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