1 use std::{
2     fs::File,
3     io,
4     io::BufReader,
5     io::Write,
6     path::Path,
7     sync::atomic::AtomicBool,
8     sync::atomic::{AtomicUsize, Ordering},
9     sync::Arc,
10 };
11 
12 use anyhow::ensure;
13 use nix::sys::time::{TimeVal, TimeValLike};
14 use v4l2r::{
15     decoder::{format::fwht::FwhtFrameParser, FormatChangedReply},
16     device::queue::{handles_provider::MmapProvider, FormatBuilder},
17     memory::{MemoryType, MmapHandle},
18     PlaneLayout,
19 };
20 use v4l2r::{
21     decoder::{
22         format::{h264::H264FrameSplitter, StreamSplitter},
23         stateful::GetBufferError,
24     },
25     PixelFormat,
26 };
27 use v4l2r::{
28     decoder::{stateful::Decoder, DecoderEvent},
29     device::{
30         poller::PollError,
31         queue::{direction::Capture, dqbuf::DqBuffer},
32     },
33     Format, Rect,
34 };
35 
36 use clap::{App, Arg};
37 
38 enum Codec {
39     Fwht,
40     H264,
41 }
42 
main()43 fn main() {
44     env_logger::init();
45 
46     let matches = App::new("V4L2 stateful decoder")
47         .arg(
48             Arg::with_name("stream")
49                 .required(true)
50                 .help("Path to the encoded stream to decode"),
51         )
52         .arg(
53             Arg::with_name("device")
54                 .required(true)
55                 .help("Path to the vicodec device file"),
56         )
57         .arg(
58             Arg::with_name("input_format")
59                 .long("input_format")
60                 .required(false)
61                 .takes_value(true)
62                 .default_value("fwht")
63                 .help("Format of the encoded stream (fwht or h264)"),
64         )
65         .arg(
66             Arg::with_name("output_file")
67                 .long("save")
68                 .required(false)
69                 .takes_value(true)
70                 .help("Save the decoded RGB frames to a file"),
71         )
72         .get_matches();
73 
74     let stream_path = matches
75         .value_of("stream")
76         .expect("Stream argument not specified");
77     let device_path = matches
78         .value_of("device")
79         .expect("Device argument not specified");
80     let codec = match matches
81         .value_of("input_format")
82         .expect("Input format not specified")
83     {
84         "fwht" => Codec::Fwht,
85         "h264" => Codec::H264,
86         _ => panic!("Invalid input format specified"),
87     };
88 
89     let stream = BufReader::new(File::open(stream_path).expect("Compressed stream not found"));
90 
91     let mut output_file: Option<File> = matches
92         .value_of("output_file")
93         .map(|path| File::create(path).expect("Invalid output file specified."));
94 
95     let lets_quit = Arc::new(AtomicBool::new(false));
96     // Setup the Ctrl+c handler.
97     {
98         let lets_quit_handler = lets_quit.clone();
99         ctrlc::set_handler(move || {
100             lets_quit_handler.store(true, Ordering::SeqCst);
101         })
102         .expect("Failed to set Ctrl-C handler.");
103     }
104 
105     const NUM_OUTPUT_BUFFERS: usize = 4;
106 
107     let poll_count_reader = Arc::new(AtomicUsize::new(0));
108     let poll_count_writer = Arc::clone(&poll_count_reader);
109     let start_time = std::time::Instant::now();
110     let mut frame_counter = 0usize;
111     let mut output_ready_cb = move |cap_dqbuf: DqBuffer<Capture, Vec<MmapHandle>>| {
112         let bytes_used = *cap_dqbuf.data.get_first_plane().bytesused as usize;
113         // Ignore zero-sized buffers.
114         if bytes_used == 0 {
115             return;
116         }
117 
118         let elapsed = start_time.elapsed();
119         frame_counter += 1;
120         let fps = frame_counter as f32 / elapsed.as_millis() as f32 * 1000.0;
121         let ppf = poll_count_reader.load(Ordering::SeqCst) as f32 / frame_counter as f32;
122         print!(
123             "\rDecoded buffer {:#5}, index: {:#2}), bytes used:{:#6} fps: {:#5.2} ppf: {:#4.2}",
124             cap_dqbuf.data.sequence(),
125             cap_dqbuf.data.index(),
126             bytes_used,
127             fps,
128             ppf,
129         );
130         io::stdout().flush().unwrap();
131 
132         if let Some(ref mut output) = output_file {
133             for i in 0..cap_dqbuf.data.num_planes() {
134                 let mapping = cap_dqbuf
135                     .get_plane_mapping(i)
136                     .expect("Failed to map capture buffer plane");
137                 output
138                     .write_all(&mapping)
139                     .expect("Error while writing output data");
140             }
141         }
142     };
143     let decoder_event_cb = move |event: DecoderEvent<MmapProvider>| match event {
144         DecoderEvent::FrameDecoded(dqbuf) => output_ready_cb(dqbuf),
145         DecoderEvent::EndOfStream => (),
146     };
147     let set_capture_format_cb = move |f: FormatBuilder,
148                                       visible_rect: Rect,
149                                       min_num_buffers: usize|
150           -> anyhow::Result<FormatChangedReply<MmapProvider>> {
151         // Let's keep the pixel format that the decoder found convenient.
152         let format = f.format();
153 
154         println!(
155             "New CAPTURE format: {:?} (visible rect: {})",
156             format, visible_rect
157         );
158 
159         Ok(FormatChangedReply {
160             provider: MmapProvider::new(format),
161             // TODO: can't the provider report the memory type that it is
162             // actually serving itself?
163             mem_type: MemoryType::Mmap,
164             num_buffers: min_num_buffers,
165         })
166     };
167 
168     let mut decoder = Decoder::open(Path::new(device_path))
169         .expect("Failed to open device")
170         .set_output_format(|f| {
171             let pixel_format: PixelFormat = match codec {
172                 Codec::Fwht => b"FWHT".into(),
173                 Codec::H264 => b"H264".into(),
174             };
175             let format: Format = f
176                 .set_pixelformat(pixel_format)
177                 // 1 MB per decoding unit should be enough for most streams.
178                 .set_planes_layout(vec![PlaneLayout {
179                     sizeimage: 1024 * 1024,
180                     ..Default::default()
181                 }])
182                 .apply()?;
183 
184             ensure!(
185                 format.pixelformat == pixel_format,
186                 format!("{} format not supported by device", pixel_format)
187             );
188 
189             println!("Tentative OUTPUT format: {:?}", format);
190 
191             Ok(())
192         })
193         .expect("Failed to set output format")
194         .allocate_output_buffers::<Vec<MmapHandle>>(NUM_OUTPUT_BUFFERS)
195         .expect("Failed to allocate output buffers")
196         .set_poll_counter(poll_count_writer)
197         .start(|_| (), decoder_event_cb, set_capture_format_cb)
198         .expect("Failed to start decoder");
199 
200     println!("Allocated {} buffers", decoder.num_output_buffers());
201 
202     let parser = match codec {
203         Codec::Fwht => Box::new(
204             FwhtFrameParser::new(stream)
205                 .unwrap_or_else(|| panic!("No FWHT stream detected in {}", stream_path)),
206         ) as Box<dyn StreamSplitter>,
207         Codec::H264 => Box::new(
208             H264FrameSplitter::new(stream)
209                 .unwrap_or_else(|| panic!("No H.264 stream detected in {}", stream_path)),
210         ) as Box<dyn StreamSplitter>,
211     };
212 
213     'mainloop: for (bitstream_id, frame) in parser.enumerate() {
214         // Ctrl-c ?
215         if lets_quit.load(Ordering::SeqCst) {
216             break;
217         }
218 
219         let v4l2_buffer = match decoder.get_buffer() {
220             Ok(buffer) => buffer,
221             // If we got interrupted while waiting for a buffer, just exit normally.
222             Err(GetBufferError::PollError(PollError::EPollWait(nix::errno::Errno::EINTR))) => {
223                 break 'mainloop
224             }
225             Err(e) => panic!("{}", e),
226         };
227 
228         let mut mapping = v4l2_buffer
229             .get_plane_mapping(0)
230             .expect("Failed to get OUTPUT buffer mapping");
231         mapping.as_mut()[0..frame.len()].copy_from_slice(&frame);
232         drop(mapping);
233 
234         // TODO setting the timestamp should not be necessary. This is a requirement of the crosvm
235         // video device.
236         v4l2_buffer
237             .set_timestamp(TimeVal::seconds(bitstream_id as i64))
238             .queue(&[frame.len()])
239             .expect("Failed to queue input frame");
240     }
241 
242     decoder.drain(true).unwrap();
243     decoder.stop().unwrap();
244     println!();
245 }
246