media_core/
frame_pool.rs

1use std::{
2    marker::PhantomData,
3    sync::{Arc, RwLock},
4};
5
6use crossbeam_queue::SegQueue;
7
8use crate::{
9    error::Error,
10    frame::{Frame, SharedFrame, SharedFrameInner},
11    FrameDescriptorSpec, Result,
12};
13
14pub trait FrameCreator<D: FrameDescriptorSpec>: Send + Sync {
15    fn create_frame(&self, desc: D) -> Result<Frame<'static, D>>;
16}
17
18pub type GenericFrameCreator<D> = dyn FrameCreator<D>;
19
20pub struct DefaultFrameCreator<D: FrameDescriptorSpec> {
21    _phantom: PhantomData<D>,
22}
23
24impl<D: FrameDescriptorSpec> Default for DefaultFrameCreator<D> {
25    fn default() -> Self {
26        Self {
27            _phantom: PhantomData,
28        }
29    }
30}
31
32impl<D: FrameDescriptorSpec> FrameCreator<D> for DefaultFrameCreator<D> {
33    fn create_frame(&self, desc: D) -> Result<Frame<'static, D>> {
34        desc.create_frame()
35    }
36}
37
38impl<D: FrameDescriptorSpec> From<DefaultFrameCreator<D>> for Arc<dyn FrameCreator<D>>
39where
40    DefaultFrameCreator<D>: FrameCreator<D>,
41{
42    fn from(creator: DefaultFrameCreator<D>) -> Self {
43        Arc::new(creator)
44    }
45}
46
47pub struct FramePoolConfig<D: FrameDescriptorSpec> {
48    pub desc: Option<D>,
49    pub creator: Arc<dyn FrameCreator<D>>,
50}
51
52pub struct FramePool<F: SharedFrameInner = RwLock<Frame<'static>>> {
53    queue: SegQueue<SharedFrame<F>>,
54    config: Arc<RwLock<FramePoolConfig<F::Descriptor>>>,
55}
56
57impl<F: SharedFrameInner> FramePool<F> {
58    pub fn new() -> Arc<Self>
59    where
60        DefaultFrameCreator<F::Descriptor>: FrameCreator<F::Descriptor>,
61    {
62        Arc::new(Self {
63            queue: SegQueue::new(),
64            config: Arc::new(RwLock::new(FramePoolConfig {
65                desc: None,
66                creator: DefaultFrameCreator::<F::Descriptor>::default().into(),
67            })),
68        })
69    }
70
71    pub fn new_with_creator(desc: F::Descriptor, creator: Box<GenericFrameCreator<F::Descriptor>>) -> Arc<Self> {
72        Arc::new(Self {
73            queue: SegQueue::new(),
74            config: Arc::new(RwLock::new(FramePoolConfig {
75                desc: Some(desc),
76                creator: Arc::from(creator),
77            })),
78        })
79    }
80
81    pub fn available(&self) -> usize {
82        self.queue.len()
83    }
84
85    pub fn configure(&self, desc: Option<F::Descriptor>, creator: Option<Box<GenericFrameCreator<F::Descriptor>>>) {
86        let need_clear = {
87            let mut config = self.config.write().unwrap();
88
89            let desc_changed = desc.is_some_and(|desc| {
90                if config.desc.as_ref() != Some(&desc) {
91                    config.desc = Some(desc);
92                    true
93                } else {
94                    false
95                }
96            });
97
98            let creator_changed = creator.is_some_and(|creator| {
99                config.creator = Arc::from(creator);
100                true
101            });
102
103            desc_changed || creator_changed
104        };
105
106        if need_clear {
107            self.clear();
108        }
109    }
110
111    pub fn recycle_frame(&self, frame: SharedFrame<F>) {
112        self.queue.push(frame);
113    }
114
115    fn clear(&self) {
116        while self.queue.pop().is_some() {}
117    }
118
119    fn get_frame_internal<G, N>(self: &Arc<Self>, get_frame_desc: G, new_shared_frame: N) -> Result<SharedFrame<F>>
120    where
121        G: Fn(&SharedFrame<F>) -> F::Descriptor,
122        N: Fn(Frame<'static, F::Descriptor>) -> SharedFrame<F>,
123    {
124        let (desc, creator) = {
125            let config = self.config.read().unwrap();
126
127            if let Some(desc) = config.desc.clone() {
128                (desc, config.creator.clone())
129            } else {
130                return Err(Error::Invalid("frame descriptor".to_string()));
131            }
132        };
133
134        if let Some(mut frame) = self.queue.pop() {
135            if get_frame_desc(&frame) == desc {
136                frame.pool = Some(Arc::downgrade(self));
137                return Ok(frame);
138            }
139        }
140
141        let frame = creator.create_frame(desc)?;
142        let mut shared_frame = new_shared_frame(frame);
143        shared_frame.pool = Some(Arc::downgrade(self));
144
145        Ok(shared_frame)
146    }
147
148    fn set_frame_descriptor(&self, desc: F::Descriptor) {
149        let need_update = { self.config.read().unwrap().desc.as_ref() != Some(&desc) };
150
151        if need_update {
152            self.config.write().unwrap().desc = Some(desc);
153            self.clear();
154        }
155    }
156}
157
158impl<D: FrameDescriptorSpec> FramePool<RwLock<Frame<'static, D>>> {
159    pub fn get_frame(self: &Arc<Self>) -> Result<SharedFrame<RwLock<Frame<'static, D>>>> {
160        self.get_frame_internal(
161            |shared_frame| shared_frame.read().unwrap().desc.clone(),
162            |frame| SharedFrame::<RwLock<Frame<'static, D>>>::new(frame),
163        )
164    }
165
166    pub fn get_frame_with_descriptor(self: &Arc<Self>, desc: D) -> Result<SharedFrame<RwLock<Frame<'static, D>>>> {
167        self.set_frame_descriptor(desc);
168        self.get_frame()
169    }
170}
171
172impl<D: FrameDescriptorSpec> FramePool<Frame<'static, D>> {
173    pub fn get_frame(self: &Arc<Self>) -> Result<SharedFrame<Frame<'static, D>>> {
174        self.get_frame_internal(|shared_frame| shared_frame.read().desc.clone(), |frame| SharedFrame::<Frame<'static, D>>::new(frame))
175    }
176
177    pub fn get_frame_with_descriptor(self: &Arc<Self>, desc: D) -> Result<SharedFrame<Frame<'static, D>>> {
178        self.set_frame_descriptor(desc);
179        self.get_frame()
180    }
181}