Skip to main content

inset_rendering/
video_frame_view.rs

1//! A box that draws a video's newest frame: Flutter's `TextureBox`, over the reader a player or
2//! a camera hands out in place of a texture id.
3//!
4//! It adds a [`VideoLayer`] at its place in paint order, and whoever draws the scene takes
5//! the reader's newest frame then and draws it into the box, as part of the picture: what is
6//! painted above it lies above it, and the clips, transforms and opacity above it apply to it as
7//! to any drawing. It fills what it is given, the frame stretched to the box; keeping the video's
8//! aspect is its parent's. It always needs compositing, as Flutter's `TextureBox` does, so the
9//! layer it adds sits in the scene. The invariant: the layer added is the box, at the offset it is
10//! painted at, and it holds the reader, never a frame.
11
12use std::sync::Arc;
13
14use inset_embedder::{Offset, Size, VideoFrameReader};
15use inset_foundation::App;
16
17use crate::box_::{BoxConstraints, RenderBox, RenderBoxData};
18use crate::layer::{ErasedLayer, VideoLayer};
19use crate::object::{RenderHandle, RenderObject, RenderObjectData};
20use crate::painting_context::PaintingContext;
21
22/// Draws a video's frames in the box it is given.
23pub struct RenderVideoFrameView {
24    render_object: RenderObjectData,
25    render_box: RenderBoxData,
26    reader: Arc<dyn VideoFrameReader>,
27}
28
29impl RenderVideoFrameView {
30    pub fn new(
31        app: &mut App,
32        reader: Arc<dyn VideoFrameReader>,
33    ) -> RenderHandle<RenderVideoFrameView> {
34        RenderHandle::new_box(
35            app,
36            RenderVideoFrameView {
37                render_object: RenderObjectData::new(),
38                render_box: RenderBoxData::new(),
39                reader,
40            },
41        )
42    }
43
44    /// The reader whose frames are drawn.
45    pub fn reader(self: RenderHandle<Self>, app: &App) -> &Arc<dyn VideoFrameReader> {
46        &self.get(app).reader
47    }
48
49    /// Draws `reader`'s frames instead, from the next paint.
50    pub fn set_reader(self: RenderHandle<Self>, app: &mut App, reader: Arc<dyn VideoFrameReader>) {
51        if Arc::ptr_eq(&self.get(app).reader, &reader) {
52            return;
53        }
54        self.get_mut(app).reader = reader;
55        self.mark_needs_paint(app);
56    }
57}
58
59impl RenderObject for RenderVideoFrameView {
60    crate::render_object_accessors!();
61
62    fn always_needs_compositing(self: RenderHandle<Self>, _app: &App) -> bool {
63        true
64    }
65
66    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
67        let size = self.constraints(app).biggest();
68        self.set_size(app, size);
69    }
70
71    fn paint(
72        self: RenderHandle<Self>,
73        app: &mut App,
74        context: &mut PaintingContext,
75        offset: Offset,
76    ) {
77        let reader = Arc::clone(&self.get(app).reader);
78        let layer = VideoLayer::new(app, reader, offset & self.size(app));
79        context.add_layer(app, layer.as_layer());
80    }
81}
82
83impl RenderBox for RenderVideoFrameView {
84    crate::render_box_accessors!();
85
86    fn compute_dry_layout(
87        self: RenderHandle<Self>,
88        _app: &mut App,
89        constraints: BoxConstraints,
90    ) -> Size {
91        constraints.biggest()
92    }
93
94    /// A video takes a hit anywhere in its box, so a listener around it hears the pointer.
95    fn hit_test_self(self: RenderHandle<Self>, _app: &App, _position: Offset) -> bool {
96        true
97    }
98}