| //! This example program demonstrates how to use the API using the `vicodec` |
| //! virtual codec driver. |
| //! |
| //! There are two variants doing the same thing: one using the higher-level |
| //! `device` abstraction (used by default), the other using the low-level |
| //! `ioctl` abstraction (used if `--use_ioctl` is specified). |
| mod device_api; |
| mod ioctl_api; |
| |
| use std::path::Path; |
| use std::sync::atomic::{AtomicBool, Ordering}; |
| use std::{fs::File, io::Write, sync::Arc}; |
| |
| use clap::{App, Arg}; |
| use v4l2r::memory::MemoryType; |
| |
| fn main() { |
| env_logger::init(); |
| |
| let matches = App::new("vicodec example") |
| .arg( |
| Arg::with_name("use_ioctl") |
| .long("use_ioctl") |
| .help("Use the lower-level ioctl interface"), |
| ) |
| .arg( |
| Arg::with_name("num_frames") |
| .long("stop_after") |
| .takes_value(true) |
| .help("Stop after encoding this number of buffers"), |
| ) |
| .arg( |
| Arg::with_name("device") |
| .required(true) |
| .help("Path to the vicodec device file"), |
| ) |
| .arg( |
| Arg::with_name("output_file") |
| .long("save") |
| .required(false) |
| .takes_value(true) |
| .help("Save the encoded stream to a file"), |
| ) |
| .arg( |
| Arg::with_name("output_mem") |
| .long("output_mem") |
| .required(false) |
| .takes_value(true) |
| .default_value("user") |
| .help("Type of memory to use for the OUTPUT queue (mmap or user)"), |
| ) |
| .arg( |
| Arg::with_name("capture_mem") |
| .long("capture_mem") |
| .required(false) |
| .takes_value(true) |
| .default_value("mmap") |
| .help("Type of memory to use for the CAPTURE queue (mmap)"), |
| ) |
| .get_matches(); |
| |
| let device_path = matches.value_of("device").unwrap_or("/dev/video0"); |
| let use_ioctl = matches.is_present("use_ioctl"); |
| let stop_after = match clap::value_t!(matches.value_of("num_frames"), usize) { |
| Ok(v) => Some(v), |
| Err(e) if e.kind == clap::ErrorKind::ArgumentNotFound => None, |
| Err(e) => panic!("Invalid value for stop_after: {}", e), |
| }; |
| |
| let mut output_file = matches |
| .value_of("output_file") |
| .map(|s| File::create(s).expect("Invalid output file specified.")); |
| |
| let output_mem = match matches.value_of("output_mem") { |
| Some("mmap") => MemoryType::Mmap, |
| Some("user") => MemoryType::UserPtr, |
| _ => panic!("Invalid value for output_mem"), |
| }; |
| let capture_mem = match matches.value_of("capture_mem") { |
| Some("mmap") => MemoryType::Mmap, |
| _ => panic!("Invalid value for capture_mem"), |
| }; |
| |
| let save_closure = |b: &[u8]| { |
| if let Some(ref mut output) = output_file { |
| output |
| .write_all(b) |
| .expect("Error while writing output data"); |
| } |
| }; |
| |
| let lets_quit = Arc::new(AtomicBool::new(false)); |
| // Setup the Ctrl+c handler. |
| { |
| let lets_quit_handler = lets_quit.clone(); |
| ctrlc::set_handler(move || { |
| lets_quit_handler.store(true, Ordering::SeqCst); |
| }) |
| .expect("Failed to set Ctrl-C handler."); |
| } |
| |
| if use_ioctl { |
| println!("Using ioctl interface"); |
| ioctl_api::run( |
| Path::new(&device_path), |
| output_mem, |
| capture_mem, |
| lets_quit, |
| stop_after, |
| save_closure, |
| ); |
| } else { |
| println!("Using device interface"); |
| device_api::run( |
| Path::new(&device_path), |
| output_mem, |
| capture_mem, |
| lets_quit, |
| stop_after, |
| save_closure, |
| ) |
| } |
| } |