1 //! This example program demonstrates how to use the API using the `vicodec`
2 //! virtual codec driver.
3 //!
4 //! There are two variants doing the same thing: one using the higher-level
5 //! `device` abstraction (used by default), the other using the low-level
6 //! `ioctl` abstraction (used if `--use_ioctl` is specified).
7 mod device_api;
8 mod ioctl_api;
9
10 use std::path::Path;
11 use std::sync::atomic::{AtomicBool, Ordering};
12 use std::{fs::File, io::Write, sync::Arc};
13
14 use clap::{App, Arg};
15 use v4l2r::memory::MemoryType;
16
main()17 fn main() {
18 env_logger::init();
19
20 let matches = App::new("vicodec example")
21 .arg(
22 Arg::with_name("use_ioctl")
23 .long("use_ioctl")
24 .help("Use the lower-level ioctl interface"),
25 )
26 .arg(
27 Arg::with_name("num_frames")
28 .long("stop_after")
29 .takes_value(true)
30 .help("Stop after encoding this number of buffers"),
31 )
32 .arg(
33 Arg::with_name("device")
34 .required(true)
35 .help("Path to the vicodec device file"),
36 )
37 .arg(
38 Arg::with_name("output_file")
39 .long("save")
40 .required(false)
41 .takes_value(true)
42 .help("Save the encoded stream to a file"),
43 )
44 .arg(
45 Arg::with_name("output_mem")
46 .long("output_mem")
47 .required(false)
48 .takes_value(true)
49 .default_value("user")
50 .help("Type of memory to use for the OUTPUT queue (mmap or user)"),
51 )
52 .arg(
53 Arg::with_name("capture_mem")
54 .long("capture_mem")
55 .required(false)
56 .takes_value(true)
57 .default_value("mmap")
58 .help("Type of memory to use for the CAPTURE queue (mmap)"),
59 )
60 .get_matches();
61
62 let device_path = matches.value_of("device").unwrap_or("/dev/video0");
63 let use_ioctl = matches.is_present("use_ioctl");
64 let stop_after = match clap::value_t!(matches.value_of("num_frames"), usize) {
65 Ok(v) => Some(v),
66 Err(e) if e.kind == clap::ErrorKind::ArgumentNotFound => None,
67 Err(e) => panic!("Invalid value for stop_after: {}", e),
68 };
69
70 let mut output_file = matches
71 .value_of("output_file")
72 .map(|s| File::create(s).expect("Invalid output file specified."));
73
74 let output_mem = match matches.value_of("output_mem") {
75 Some("mmap") => MemoryType::Mmap,
76 Some("user") => MemoryType::UserPtr,
77 _ => panic!("Invalid value for output_mem"),
78 };
79 let capture_mem = match matches.value_of("capture_mem") {
80 Some("mmap") => MemoryType::Mmap,
81 _ => panic!("Invalid value for capture_mem"),
82 };
83
84 let save_closure = |b: &[u8]| {
85 if let Some(ref mut output) = output_file {
86 output
87 .write_all(b)
88 .expect("Error while writing output data");
89 }
90 };
91
92 let lets_quit = Arc::new(AtomicBool::new(false));
93 // Setup the Ctrl+c handler.
94 {
95 let lets_quit_handler = lets_quit.clone();
96 ctrlc::set_handler(move || {
97 lets_quit_handler.store(true, Ordering::SeqCst);
98 })
99 .expect("Failed to set Ctrl-C handler.");
100 }
101
102 if use_ioctl {
103 println!("Using ioctl interface");
104 ioctl_api::run(
105 Path::new(&device_path),
106 output_mem,
107 capture_mem,
108 lets_quit,
109 stop_after,
110 save_closure,
111 );
112 } else {
113 println!("Using device interface");
114 device_api::run(
115 Path::new(&device_path),
116 output_mem,
117 capture_mem,
118 lets_quit,
119 stop_after,
120 save_closure,
121 )
122 }
123 }
124