|
1 | | -use ccap::{Provider, Result}; |
2 | | -use std::sync::{Arc, Mutex, mpsc}; |
| 1 | +use ccap::{Provider, Result, Utils, PropertyName, PixelFormat, LogLevel}; |
| 2 | +use std::sync::{Arc, Mutex}; |
3 | 3 | use std::thread; |
4 | | -use std::time::{Duration, Instant}; |
| 4 | +use std::time::Duration; |
5 | 5 |
|
6 | 6 | fn main() -> Result<()> { |
7 | | - // Create a camera provider |
8 | | - let mut provider = Provider::new()?; |
| 7 | + // Enable verbose log to see debug information |
| 8 | + Utils::set_log_level(LogLevel::Verbose); |
| 9 | + |
| 10 | + // Set error callback to receive error notifications |
| 11 | + Provider::set_error_callback(|error_code, description| { |
| 12 | + eprintln!("Camera Error - Code: {}, Description: {}", error_code, description); |
| 13 | + }); |
| 14 | + |
| 15 | + let temp_provider = Provider::new()?; |
| 16 | + let devices = temp_provider.list_devices()?; |
| 17 | + if devices.is_empty() { |
| 18 | + eprintln!("No camera devices found!"); |
| 19 | + return Ok(()); |
| 20 | + } |
| 21 | + |
| 22 | + for (i, device) in devices.iter().enumerate() { |
| 23 | + println!("## Found video capture device: {}: {}", i, device); |
| 24 | + } |
| 25 | + |
| 26 | + // Select camera device (automatically use first device for testing) |
| 27 | + let device_index = if devices.len() == 1 { |
| 28 | + 0 |
| 29 | + } else { |
| 30 | + 0 // Just use first device for now |
| 31 | + }; |
9 | 32 |
|
10 | | - // Open the first available device |
| 33 | + // Create provider with selected device |
| 34 | + let mut provider = Provider::with_device(device_index as i32)?; |
| 35 | + |
| 36 | + // Set camera properties |
| 37 | + let requested_width = 1920; |
| 38 | + let requested_height = 1080; |
| 39 | + let requested_fps = 60.0; |
| 40 | + |
| 41 | + provider.set_property(PropertyName::Width, requested_width as f64)?; |
| 42 | + provider.set_property(PropertyName::Height, requested_height as f64)?; |
| 43 | + provider.set_property(PropertyName::PixelFormatOutput, PixelFormat::Bgra32 as u32 as f64)?; |
| 44 | + provider.set_property(PropertyName::FrameRate, requested_fps)?; |
| 45 | + |
| 46 | + // Open and start camera |
11 | 47 | provider.open()?; |
12 | | - println!("Camera opened successfully."); |
13 | | - |
14 | | - // Start capture |
15 | 48 | provider.start()?; |
16 | | - println!("Camera capture started."); |
17 | | - |
| 49 | + |
| 50 | + if !provider.is_started() { |
| 51 | + eprintln!("Failed to start camera!"); |
| 52 | + return Ok(()); |
| 53 | + } |
| 54 | + |
| 55 | + // Get real camera properties |
| 56 | + let real_width = provider.get_property(PropertyName::Width)? as i32; |
| 57 | + let real_height = provider.get_property(PropertyName::Height)? as i32; |
| 58 | + let real_fps = provider.get_property(PropertyName::FrameRate)?; |
| 59 | + |
| 60 | + println!("Camera started successfully, requested resolution: {}x{}, real resolution: {}x{}, requested fps {}, real fps: {}", |
| 61 | + requested_width, requested_height, real_width, real_height, requested_fps, real_fps); |
| 62 | + |
| 63 | + // Create directory for captures (using std::fs) |
| 64 | + std::fs::create_dir_all("./image_capture").map_err(|e| ccap::CcapError::FileOperationFailed(e.to_string()))?; |
| 65 | + |
18 | 66 | // Statistics tracking |
19 | 67 | let frame_count = Arc::new(Mutex::new(0u32)); |
20 | | - let start_time = Arc::new(Mutex::new(Instant::now())); |
21 | | - |
22 | | - // Create a channel for communication |
23 | | - let (tx, rx) = mpsc::channel(); |
24 | | - |
25 | | - // Spawn a thread to continuously grab frames |
26 | 68 | let frame_count_clone = frame_count.clone(); |
27 | | - let start_time_clone = start_time.clone(); |
28 | | - |
29 | | - thread::spawn(move || { |
30 | | - loop { |
31 | | - // Check for stop signal |
32 | | - match rx.try_recv() { |
33 | | - Ok(_) => break, |
34 | | - Err(mpsc::TryRecvError::Disconnected) => break, |
35 | | - Err(mpsc::TryRecvError::Empty) => {} |
36 | | - } |
37 | | - |
38 | | - // Grab frame with timeout |
39 | | - match provider.grab_frame(100) { |
40 | | - Ok(Some(frame)) => { |
41 | | - let mut count = frame_count_clone.lock().unwrap(); |
42 | | - *count += 1; |
43 | | - |
44 | | - // Print stats every 30 frames |
45 | | - if *count % 30 == 0 { |
46 | | - let elapsed = start_time_clone.lock().unwrap().elapsed(); |
47 | | - let fps = *count as f64 / elapsed.as_secs_f64(); |
48 | | - |
49 | | - println!("Frame {}: {}x{}, format: {:?}, FPS: {:.1}", |
50 | | - *count, |
51 | | - frame.width(), |
52 | | - frame.height(), |
53 | | - frame.pixel_format(), |
54 | | - fps |
55 | | - ); |
56 | | - |
57 | | - // TODO: Save every 30th frame (saving not yet implemented) |
58 | | - println!("Frame {} captured: {}x{}, format: {:?} (saving not implemented)", |
59 | | - *count, frame.width(), frame.height(), frame.pixel_format()); |
60 | | - } |
61 | | - } |
62 | | - Ok(None) => { |
63 | | - // No frame available, continue |
64 | | - } |
65 | | - Err(e) => { |
66 | | - eprintln!("Error grabbing frame: {}", e); |
67 | | - thread::sleep(Duration::from_millis(10)); |
68 | | - } |
69 | | - } |
| 69 | + |
| 70 | + // Set frame callback |
| 71 | + provider.set_new_frame_callback(move |frame| { |
| 72 | + let mut count = frame_count_clone.lock().unwrap(); |
| 73 | + *count += 1; |
| 74 | + |
| 75 | + println!("VideoFrame {} grabbed: width = {}, height = {}, bytes: {}", |
| 76 | + frame.index(), frame.width(), frame.height(), frame.data_size()); |
| 77 | + |
| 78 | + // Try to save frame to directory |
| 79 | + if let Ok(filename) = Utils::dump_frame_to_directory(frame, "./image_capture") { |
| 80 | + println!("VideoFrame saved to: {}", filename); |
| 81 | + } else { |
| 82 | + eprintln!("Failed to save frame!"); |
70 | 83 | } |
71 | | - |
72 | | - println!("Frame grabbing thread stopped."); |
73 | | - }); |
74 | | - |
75 | | - // Run for 10 seconds |
76 | | - println!("Capturing frames for 10 seconds..."); |
77 | | - thread::sleep(Duration::from_secs(10)); |
78 | | - |
79 | | - // Signal stop |
80 | | - let _ = tx.send(()); |
81 | | - |
82 | | - // Wait a bit for thread to finish |
83 | | - thread::sleep(Duration::from_millis(100)); |
84 | | - |
85 | | - // Print final statistics |
| 84 | + |
| 85 | + true // no need to retain the frame |
| 86 | + })?; |
| 87 | + |
| 88 | + // Wait for 5 seconds to capture frames |
| 89 | + println!("Capturing frames for 5 seconds..."); |
| 90 | + thread::sleep(Duration::from_secs(5)); |
| 91 | + |
| 92 | + // Get final count |
86 | 93 | let final_count = *frame_count.lock().unwrap(); |
87 | | - let total_time = start_time.lock().unwrap().elapsed(); |
88 | | - let avg_fps = final_count as f64 / total_time.as_secs_f64(); |
89 | | - |
90 | | - println!("Capture completed:"); |
91 | | - println!(" Total frames: {}", final_count); |
92 | | - println!(" Total time: {:.2}s", total_time.as_secs_f64()); |
93 | | - println!(" Average FPS: {:.1}", avg_fps); |
| 94 | + println!("Captured {} frames, stopping...", final_count); |
94 | 95 |
|
| 96 | + // Remove callback before dropping |
| 97 | + let _ = provider.remove_new_frame_callback(); |
| 98 | + |
95 | 99 | Ok(()) |
96 | 100 | } |
0 commit comments