1 // Copyright 2024 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::cell::RefCell; 6 use std::os::fd::AsRawFd; 7 use std::rc::{Rc, Weak}; 8 9 use v4l2r::controls::ExtControlTrait; 10 use v4l2r::controls::SafeExtControl; 11 use v4l2r::ioctl; 12 13 use crate::backend::v4l2::decoder::stateless::V4l2Picture; 14 use crate::decoder::stateless::StatelessBackendError; 15 use crate::decoder::stateless::StatelessBackendResult; 16 use crate::device::v4l2::stateless::device::V4l2Device; 17 use crate::device::v4l2::stateless::queue::V4l2CaptureBuffer; 18 use crate::device::v4l2::stateless::queue::V4l2OutputBuffer; 19 use crate::video_frame::VideoFrame; 20 21 struct InitRequestHandle<V: VideoFrame> { 22 device: V4l2Device<V>, 23 timestamp: u64, 24 handle: ioctl::Request, 25 output_buffer: V4l2OutputBuffer, 26 picture: Weak<RefCell<V4l2Picture<V>>>, 27 frame: V, 28 } 29 30 impl<V: VideoFrame> InitRequestHandle<V> { new( device: V4l2Device<V>, timestamp: u64, handle: ioctl::Request, output_buffer: V4l2OutputBuffer, frame: V, ) -> Self31 fn new( 32 device: V4l2Device<V>, 33 timestamp: u64, 34 handle: ioctl::Request, 35 output_buffer: V4l2OutputBuffer, 36 frame: V, 37 ) -> Self { 38 Self { device, timestamp, handle, output_buffer, picture: Weak::new(), frame } 39 } which(&self) -> ioctl::CtrlWhich40 fn which(&self) -> ioctl::CtrlWhich { 41 ioctl::CtrlWhich::Request(self.handle.as_raw_fd()) 42 } ioctl<C, T>(&mut self, ctrl: C) -> StatelessBackendResult<&mut Self> where C: Into<SafeExtControl<T>>, T: ExtControlTrait,43 fn ioctl<C, T>(&mut self, ctrl: C) -> StatelessBackendResult<&mut Self> 44 where 45 C: Into<SafeExtControl<T>>, 46 T: ExtControlTrait, 47 { 48 let mut ctrl: SafeExtControl<T> = ctrl.into(); 49 ioctl::s_ext_ctrls(&self.device, self.which(), &mut ctrl) 50 .map_err(|e| StatelessBackendError::Other(anyhow::anyhow!(e)))?; 51 Ok(self) 52 } write(&mut self, data: &[u8]) -> &mut Self53 fn write(&mut self, data: &[u8]) -> &mut Self { 54 self.output_buffer.write(data); 55 self 56 } submit(self) -> StatelessBackendResult<PendingRequestHandle<V>>57 fn submit(self) -> StatelessBackendResult<PendingRequestHandle<V>> { 58 self.device 59 .queue_capture_buffer(self.frame) 60 .map_err(|e| StatelessBackendError::Other(anyhow::anyhow!(e)))?; 61 self.output_buffer 62 .submit(self.timestamp, self.handle.as_raw_fd()) 63 .map_err(|e| StatelessBackendError::Other(anyhow::anyhow!(e)))?; 64 self.handle.queue().map_err(|e| StatelessBackendError::Other(anyhow::anyhow!(e)))?; 65 Ok(PendingRequestHandle { 66 device: self.device.clone(), 67 timestamp: self.timestamp, 68 picture: self.picture, 69 }) 70 } set_picture_ref(&mut self, picture: Weak<RefCell<V4l2Picture<V>>>)71 fn set_picture_ref(&mut self, picture: Weak<RefCell<V4l2Picture<V>>>) { 72 self.picture = picture; 73 } 74 } 75 76 struct PendingRequestHandle<V: VideoFrame> { 77 device: V4l2Device<V>, 78 timestamp: u64, 79 picture: Weak<RefCell<V4l2Picture<V>>>, 80 } 81 82 impl<V: VideoFrame> PendingRequestHandle<V> { sync(self) -> DoneRequestHandle<V>83 fn sync(self) -> DoneRequestHandle<V> { 84 DoneRequestHandle { 85 capture_buffer: Rc::new(RefCell::new(self.device.sync(self.timestamp))), 86 } 87 } associate_dequeued_buffer( &mut self, capture_buffer: V4l2CaptureBuffer<V>, ) -> DoneRequestHandle<V>88 fn associate_dequeued_buffer( 89 &mut self, 90 capture_buffer: V4l2CaptureBuffer<V>, 91 ) -> DoneRequestHandle<V> { 92 self.picture.upgrade().unwrap().as_ref().try_borrow_mut().unwrap().drop_references(); 93 DoneRequestHandle { capture_buffer: Rc::new(RefCell::new(capture_buffer)) } 94 } 95 } 96 97 struct DoneRequestHandle<V: VideoFrame> { 98 capture_buffer: Rc<RefCell<V4l2CaptureBuffer<V>>>, 99 } 100 101 impl<V: VideoFrame> DoneRequestHandle<V> { result(&self) -> V4l2Result<V>102 fn result(&self) -> V4l2Result<V> { 103 V4l2Result { capture_buffer: self.capture_buffer.clone() } 104 } 105 } 106 107 #[derive(Default)] 108 enum RequestHandle<V: VideoFrame> { 109 Init(InitRequestHandle<V>), 110 Pending(PendingRequestHandle<V>), 111 Done(DoneRequestHandle<V>), 112 #[default] 113 Unknown, 114 } 115 116 impl<V: VideoFrame> RequestHandle<V> { new( device: V4l2Device<V>, timestamp: u64, handle: ioctl::Request, output_buffer: V4l2OutputBuffer, frame: V, ) -> Self117 fn new( 118 device: V4l2Device<V>, 119 timestamp: u64, 120 handle: ioctl::Request, 121 output_buffer: V4l2OutputBuffer, 122 frame: V, 123 ) -> Self { 124 Self::Init(InitRequestHandle::new(device, timestamp, handle, output_buffer, frame)) 125 } timestamp(&self) -> u64126 fn timestamp(&self) -> u64 { 127 match self { 128 Self::Init(handle) => handle.timestamp, 129 Self::Pending(handle) => handle.timestamp, 130 Self::Done(handle) => handle.capture_buffer.borrow().timestamp(), 131 _ => panic!("ERROR"), 132 } 133 } which(&self) -> ioctl::CtrlWhich134 fn which(&self) -> ioctl::CtrlWhich { 135 match self { 136 Self::Init(handle) => handle.which(), 137 _ => panic!("ERROR"), 138 } 139 } ioctl<C, T>(&mut self, ctrl: C) -> StatelessBackendResult<&mut Self> where C: Into<SafeExtControl<T>>, T: ExtControlTrait,140 fn ioctl<C, T>(&mut self, ctrl: C) -> StatelessBackendResult<&mut Self> 141 where 142 C: Into<SafeExtControl<T>>, 143 T: ExtControlTrait, 144 { 145 match self { 146 Self::Init(handle) => handle.ioctl(ctrl)?, 147 _ => { 148 return Err(StatelessBackendError::Other(anyhow::anyhow!( 149 "incorrect request state" 150 ))) 151 } 152 }; 153 Ok(self) 154 } write(&mut self, data: &[u8]) -> &mut Self155 fn write(&mut self, data: &[u8]) -> &mut Self { 156 match self { 157 Self::Init(handle) => handle.write(data), 158 _ => panic!("ERROR"), 159 }; 160 self 161 } 162 163 // This method can modify in-place instead of returning a new value. This removes the need for 164 // a RefCell in V4l2Request. submit(&mut self) -> StatelessBackendResult<()>165 fn submit(&mut self) -> StatelessBackendResult<()> { 166 match std::mem::take(self) { 167 Self::Init(handle) => Ok(*self = Self::Pending(handle.submit()?)), 168 _ => Err(StatelessBackendError::Other(anyhow::anyhow!("incorrect request state"))), 169 } 170 } sync(&mut self)171 fn sync(&mut self) { 172 match std::mem::take(self) { 173 Self::Pending(handle) => *self = Self::Done(handle.sync()), 174 s @ Self::Done(_) => *self = s, 175 _ => panic!("ERROR"), 176 } 177 } result(&self) -> V4l2Result<V>178 fn result(&self) -> V4l2Result<V> { 179 match self { 180 Self::Done(handle) => handle.result(), 181 _ => panic!("ERROR"), 182 } 183 } set_picture_ref(&mut self, picture: Weak<RefCell<V4l2Picture<V>>>)184 fn set_picture_ref(&mut self, picture: Weak<RefCell<V4l2Picture<V>>>) { 185 match self { 186 Self::Init(handle) => handle.set_picture_ref(picture), 187 _ => panic!("ERROR"), 188 } 189 } associate_dequeued_buffer(&mut self, capture_buffer: V4l2CaptureBuffer<V>)190 fn associate_dequeued_buffer(&mut self, capture_buffer: V4l2CaptureBuffer<V>) { 191 match self { 192 Self::Pending(handle) => { 193 *self = Self::Done(handle.associate_dequeued_buffer(capture_buffer)) 194 } 195 _ => panic!("ERROR"), 196 } 197 } 198 } 199 200 pub struct V4l2Request<V: VideoFrame>(RequestHandle<V>); 201 202 impl<V: VideoFrame> V4l2Request<V> { new( device: V4l2Device<V>, timestamp: u64, handle: ioctl::Request, output_buffer: V4l2OutputBuffer, frame: V, ) -> Self203 pub fn new( 204 device: V4l2Device<V>, 205 timestamp: u64, 206 handle: ioctl::Request, 207 output_buffer: V4l2OutputBuffer, 208 frame: V, 209 ) -> Self { 210 Self(RequestHandle::new(device, timestamp, handle, output_buffer, frame)) 211 } timestamp(&self) -> u64212 pub fn timestamp(&self) -> u64 { 213 self.0.timestamp() 214 } which(&self) -> ioctl::CtrlWhich215 pub fn which(&self) -> ioctl::CtrlWhich { 216 self.0.which() 217 } ioctl<C, T>(&mut self, ctrl: C) -> StatelessBackendResult<&mut Self> where C: Into<SafeExtControl<T>>, T: ExtControlTrait,218 pub fn ioctl<C, T>(&mut self, ctrl: C) -> StatelessBackendResult<&mut Self> 219 where 220 C: Into<SafeExtControl<T>>, 221 T: ExtControlTrait, 222 { 223 self.0.ioctl(ctrl)?; 224 Ok(self) 225 } write(&mut self, data: &[u8]) -> &mut Self226 pub fn write(&mut self, data: &[u8]) -> &mut Self { 227 self.0.write(data); 228 self 229 } submit(&mut self) -> StatelessBackendResult<()>230 pub fn submit(&mut self) -> StatelessBackendResult<()> { 231 self.0.submit() 232 } sync(&mut self)233 pub fn sync(&mut self) { 234 self.0.sync(); 235 } result(&self) -> V4l2Result<V>236 pub fn result(&self) -> V4l2Result<V> { 237 self.0.result() 238 } set_picture_ref(&mut self, picture: Weak<RefCell<V4l2Picture<V>>>)239 pub fn set_picture_ref(&mut self, picture: Weak<RefCell<V4l2Picture<V>>>) { 240 self.0.set_picture_ref(picture); 241 } associate_dequeued_buffer(&mut self, capture_buffer: V4l2CaptureBuffer<V>)242 pub fn associate_dequeued_buffer(&mut self, capture_buffer: V4l2CaptureBuffer<V>) { 243 self.0.associate_dequeued_buffer(capture_buffer) 244 } 245 } 246 247 pub struct V4l2Result<V: VideoFrame> { 248 pub capture_buffer: Rc<RefCell<V4l2CaptureBuffer<V>>>, 249 } 250