• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::collections::HashMap;
7 use std::os::fd::{AsRawFd, RawFd};
8 use std::rc::{Rc, Weak};
9 use std::sync::Arc;
10 use std::thread::sleep;
11 use std::time::Duration;
12 
13 use v4l2r::device::Device as VideoDevice;
14 use v4l2r::device::DeviceConfig;
15 use v4l2r::ioctl;
16 use v4l2r::nix::fcntl::open;
17 use v4l2r::nix::fcntl::OFlag;
18 use v4l2r::nix::sys::stat::Mode;
19 
20 use crate::decoder::stateless::DecodeError;
21 use crate::decoder::stateless::NewStatelessDecoderError;
22 use crate::device::v4l2::stateless::queue::QueueError;
23 use crate::device::v4l2::stateless::queue::V4l2CaptureBuffer;
24 use crate::device::v4l2::stateless::queue::V4l2CaptureQueue;
25 use crate::device::v4l2::stateless::queue::V4l2OutputQueue;
26 use crate::device::v4l2::stateless::request::V4l2Request;
27 use crate::device::v4l2::utils::enumerate_devices;
28 use crate::video_frame::VideoFrame;
29 use crate::Fourcc;
30 use crate::Resolution;
31 
32 //TODO: handle other memory backends for OUTPUT queue
33 //TODO: handle video formats other than h264
34 //TODO: handle queue start/stop at runtime
35 //TODO: handle DRC at runtime
36 struct DeviceHandle<V: VideoFrame> {
37     video_device: Arc<VideoDevice>,
38     media_device: RawFd,
39     output_queue: V4l2OutputQueue,
40     capture_queue: V4l2CaptureQueue<V>,
41     requests: HashMap<u64, Weak<RefCell<V4l2Request<V>>>>,
42 }
43 
44 impl<V: VideoFrame> DeviceHandle<V> {
new() -> Result<Self, NewStatelessDecoderError>45     fn new() -> Result<Self, NewStatelessDecoderError> {
46         let devices = enumerate_devices();
47         let (video_device_path, media_device_path) = match devices {
48             Some(paths) => paths,
49             None => return Err(NewStatelessDecoderError::DriverInitialization),
50         };
51 
52         let video_device_config = DeviceConfig::new().non_blocking_dqbuf();
53         let video_device = Arc::new(
54             VideoDevice::open(&video_device_path, video_device_config)
55                 .map_err(|_| NewStatelessDecoderError::DriverInitialization)?,
56         );
57 
58         let media_device =
59             open(&media_device_path, OFlag::O_RDWR | OFlag::O_CLOEXEC, Mode::empty())
60                 .map_err(|_| NewStatelessDecoderError::DriverInitialization)?;
61         let output_queue = V4l2OutputQueue::new(video_device.clone())?;
62         let capture_queue = V4l2CaptureQueue::new(video_device.clone())?;
63         Ok(Self {
64             video_device,
65             media_device,
66             output_queue,
67             capture_queue,
68             requests: HashMap::<u64, Weak<RefCell<V4l2Request<V>>>>::new(),
69         })
70     }
71 
reset_queues(&mut self) -> Result<(), QueueError>72     pub fn reset_queues(&mut self) -> Result<(), QueueError> {
73         self.output_queue
74             .reset(self.video_device.clone())
75             .map_err(|_| QueueError::ResetOutputQueue)?;
76         self.capture_queue
77             .reset(self.video_device.clone())
78             .map_err(|_| QueueError::ResetCaptureQueue)
79     }
80 
alloc_request(&self) -> ioctl::Request81     fn alloc_request(&self) -> ioctl::Request {
82         ioctl::Request::alloc(&self.media_device).expect("Failed to alloc request handle")
83     }
dequeue_output_buffer(&self)84     fn dequeue_output_buffer(&self) {
85         let mut back_off_duration = Duration::from_millis(1);
86         loop {
87             match self.output_queue.dequeue_buffer() {
88                 Ok(_) => {
89                     break;
90                 }
91                 Err(QueueError::BufferDequeue) => {
92                     sleep(back_off_duration);
93                     back_off_duration = back_off_duration + back_off_duration;
94                     continue;
95                 }
96                 Err(_) => panic!("handle this better"),
97             }
98         }
99     }
insert_request_into_hash(&mut self, request: Weak<RefCell<V4l2Request<V>>>)100     fn insert_request_into_hash(&mut self, request: Weak<RefCell<V4l2Request<V>>>) {
101         let timestamp = request.upgrade().unwrap().as_ref().borrow().timestamp();
102         self.requests.insert(timestamp, request);
103     }
try_dequeue_capture_buffers(&mut self)104     fn try_dequeue_capture_buffers(&mut self) {
105         loop {
106             match self.capture_queue.dequeue_buffer() {
107                 Ok(Some(buffer)) => {
108                     let timestamp = buffer.timestamp();
109                     let request = self.requests.remove(&timestamp).unwrap();
110                     match request.upgrade().unwrap().as_ref().try_borrow_mut() {
111                         Ok(mut request) => {
112                             request.associate_dequeued_buffer(buffer);
113                         }
114                         _ => (),
115                     }
116                     continue;
117                 }
118                 _ => break,
119             }
120         }
121     }
sync(&mut self, timestamp: u64) -> V4l2CaptureBuffer<V>122     fn sync(&mut self, timestamp: u64) -> V4l2CaptureBuffer<V> {
123         let mut back_off_duration = Duration::from_millis(1);
124         let time_out = Duration::from_millis(120);
125         loop {
126             match self.capture_queue.dequeue_buffer() {
127                 Ok(Some(buffer)) => {
128                     let dequeued_timestamp = buffer.timestamp();
129                     let request = self.requests.remove(&dequeued_timestamp).unwrap();
130                     if dequeued_timestamp == timestamp {
131                         return buffer;
132                     } else {
133                         match request.upgrade().unwrap().as_ref().try_borrow_mut() {
134                             Ok(mut request) => {
135                                 request.associate_dequeued_buffer(buffer);
136                             }
137                             _ => (),
138                         }
139                     }
140                 }
141                 _ => (),
142             }
143             back_off_duration = back_off_duration + back_off_duration;
144             if back_off_duration > time_out {
145                 panic!("there should not be a scenario where a queued frame is not returned.");
146             }
147             sleep(back_off_duration);
148         }
149     }
150 }
151 
152 pub struct V4l2Device<V: VideoFrame> {
153     handle: Rc<RefCell<DeviceHandle<V>>>,
154 }
155 
156 impl<V: VideoFrame> V4l2Device<V> {
new() -> Result<Self, NewStatelessDecoderError>157     pub fn new() -> Result<Self, NewStatelessDecoderError> {
158         Ok(Self { handle: Rc::new(RefCell::new(DeviceHandle::new()?)) })
159     }
160 
reset_queues(&mut self) -> Result<(), QueueError>161     pub fn reset_queues(&mut self) -> Result<(), QueueError> {
162         self.handle.borrow_mut().reset_queues()
163     }
164 
initialize_queues( &mut self, format: Fourcc, coded_size: Resolution, num_buffers: u32, ) -> Result<(), anyhow::Error>165     pub fn initialize_queues(
166         &mut self,
167         format: Fourcc,
168         coded_size: Resolution,
169         num_buffers: u32,
170     ) -> Result<(), anyhow::Error> {
171         self.handle.borrow_mut().output_queue.initialize(format, coded_size)?;
172         self.handle.borrow_mut().capture_queue.initialize(num_buffers)?;
173         Ok(())
174     }
alloc_request( &self, timestamp: u64, frame: V, ) -> Result<Rc<RefCell<V4l2Request<V>>>, DecodeError>175     pub fn alloc_request(
176         &self,
177         timestamp: u64,
178         frame: V,
179     ) -> Result<Rc<RefCell<V4l2Request<V>>>, DecodeError> {
180         if self.handle.borrow().capture_queue.num_free_buffers() == 0 {
181             return Err(DecodeError::NotEnoughOutputBuffers(0));
182         }
183 
184         let output_buffer = self.handle.borrow().output_queue.alloc_buffer();
185 
186         let output_buffer = match output_buffer {
187             Ok(buffer) => buffer,
188             Err(DecodeError::NotEnoughOutputBuffers(_)) => {
189                 self.handle.borrow_mut().dequeue_output_buffer();
190                 match self.handle.borrow().output_queue.alloc_buffer() {
191                     Ok(buffer) => buffer,
192                     Err(e) => return Err(e),
193                 }
194             }
195             Err(error) => return Err(error),
196         };
197         self.handle.borrow_mut().try_dequeue_capture_buffers();
198 
199         let request = Rc::new(RefCell::new(V4l2Request::new(
200             self.clone(),
201             timestamp,
202             self.handle.borrow().alloc_request(),
203             output_buffer,
204             frame,
205         )));
206         self.handle.borrow_mut().insert_request_into_hash(Rc::downgrade(&request.clone()));
207         Ok(request)
208     }
sync(&self, timestamp: u64) -> V4l2CaptureBuffer<V>209     pub fn sync(&self, timestamp: u64) -> V4l2CaptureBuffer<V> {
210         self.handle.borrow_mut().sync(timestamp)
211     }
queue_capture_buffer(&self, frame: V) -> Result<(), QueueError>212     pub fn queue_capture_buffer(&self, frame: V) -> Result<(), QueueError> {
213         self.handle.borrow().capture_queue.queue_buffer(frame)
214     }
215 }
216 
217 impl<V: VideoFrame> Clone for V4l2Device<V> {
clone(&self) -> Self218     fn clone(&self) -> Self {
219         Self { handle: self.handle.clone() }
220     }
221 }
222 
223 impl<V: VideoFrame> AsRawFd for V4l2Device<V> {
as_raw_fd(&self) -> i32224     fn as_raw_fd(&self) -> i32 {
225         self.handle.borrow().video_device.as_raw_fd()
226     }
227 }
228