much more efficient and cleaned up WebcamWriter

This commit is contained in:
Brandon Thomas committed 2020-04-30 21:40:10 -04:00
1 parent e29d003973
commit e2671e4380
2 files changed
+90 -200

No files matched your search

+5 -33
View File
@@ -26,41 +26,13 @@ use std::os::unix::io::AsRawFd;
use std::path::Path;
use std::sync::Arc;
use std::time::{Instant, Duration};
use webcam::write_frame_to_webcam;
use webcam::{WebcamWriter};
use std::error::Error;
pub fn run(capture_provider: Arc<CaptureProvider>, calibration_data: k4a_sys::k4a_calibration_t) {
//let mut file = File::create("/dev/video7").expect("write");
let path = Path::new("/dev/video0");
let mut file = OpenOptions::new()
//.append(true)
//.create(true)
.read(true)
.truncate(true)
.write(true)
.open(path)
.expect("file open");
//let mut contents = Vec::new();
//file.read_to_end(&mut contents).expect("read");
//file.set_len(0 as u64).expect("set length");
//file.set_len(100).expect("set length");
//let mut mmap_read = unsafe { Mmap::map(&file).expect("mmmap") };
//let mut mmap = unsafe { mmap_read.make_mut().expect("making mut") };
//let mut mmap = unsafe { MmapMut::map_mut(&file).expect("mmmap") };
/*let size = 1280*720*3 * 10;
let size = 640*480*3;
let file_descriptor = file.as_raw_fd();
println!("File descriptor: {}", file_descriptor);
let options = [
MapReadable,
MapWritable,
MapFd(file_descriptor)
];
let mut mmap = MemoryMap::new(size as usize, &options).expect("mmap");*/
let mut webcam_writer = WebcamWriter::open_file("/dev/video0", 1280, 720, 3)
.expect("should be able to create webcamwriter");
let sdl_context = sdl2::init().unwrap();
let video = sdl_context.video().unwrap();
@@ -244,12 +216,12 @@ pub fn run(capture_provider: Arc<CaptureProvider>, calibration_data: k4a_sys::k4
});
}
webcam_writer.write_current_frame_to_file(texture.texture_id())
.expect("should write");
//let change_delta = last_frame - last_change;
//if change_delta > Duration::from_millis(5_000) {
//}
//write_frame_to_webcam(&mut file, texture.texture_id());
write_frame_to_webcam(&mut file, texture.texture_id());
/*if change_delta > Duration::from_millis(5000) {
colorization_strategy = match colorization_strategy {
+85 -167
View File
@@ -1,189 +1,107 @@
use gl::types::*;
use gl;
use std::ffi::c_void;
use std::fs::File;
use std::fs::{File, OpenOptions};
use std::io::Write;
use opengl_wrapper::gl_get_error;
use opengl_wrapper::{gl_get_error, OpenGlError};
use image::imageops::FilterType;
use memmap2::MmapMut;
use mmap::MemoryMap;
use std::path::Path;
use std::{io, fmt};
use std::fmt::Formatter;
pub fn write_frame_to_webcam(file: &mut File, texture_id: GLuint) {
/// WebcamWriter uses Webcamoid's akvcam kernel driver to stream output to a /dev/video*
/// file. Their wiki contains all of the setup instructions, and I'm checked in some example
/// configs into this repo.
///
/// https://github.com/webcamoid/akvcam
pub struct WebcamWriter {
/// Internal byte buffer to pull from OpenGL texture and flush to file.
buffer: Vec<u8>,
buffer_size: usize,
/// File to flush raw RGB24 bytes to.
file: File,
}
//let mut buffer: [u8; 15_360_000] = [0; 15_360_000];
/*let mut buffer = Vec::with_capacity(15_360_000);
for _ in 0..15_360_000 {
buffer.push(0);
}*/
//let size = 800 * 800 * 4;
impl WebcamWriter {
let width = 1280;
let height = 720;
let depth = 3;
/// Create a WebcamWriter that outputs to the supplied file.
/// The file handle is created and owned by WebcamWriter.
pub fn open_file(filename: &str, width: usize, height: usize, bit_depth: usize)
-> Result<Self, io::Error>
{
let path = Path::new(filename);
let file = OpenOptions::new()
.read(true)
.truncate(true)
.write(true)
.open(path)?;
let size = width * height * depth;
let buffer_size = width * height * bit_depth;
//let size = 15_360_000;
let mut buffer = Vec::with_capacity(size);
buffer.resize(size, 0);
/*for _ in 0 .. size {
buffer.push(0);
}*/
let mut typed_buffer = buffer.as_mut_ptr() as *mut c_void;
let mut buffer = Vec::with_capacity(buffer_size);
buffer.resize(buffer_size, 0);
unsafe {
// > 600 * 800
// 480000
// > 600 * 800 * 4
// 1920000
/*
const width : usize = 640;
const height : usize = 480;
const bytes_per_pixel : usize = 4;
const size : usize = width * height * bytes_per_pixel;
let mut buffer: [u8; bytes_per_pixel] = [0; bytes_per_pixel];
let mut typed_buffer = buffer.as_mut_ptr() as *mut c_void;
gl::ReadnPixels(0, 0, width as i32, height as i32, gl::RGB, gl::BYTE, size as i32, typed_buffer);
println!("Write buffer to camera");
file.write(&buffer).expect("work");
*/
// width = 800
// height = 800
// rgb8 = 24
// size = 15_360_000
println!("Declare memory size");
Ok(Self {
buffer,
buffer_size,
file,
})
}
println!("Read frame into buffer");
//gl::Viewport(0, 0, 640, 480);
//gl::ReadPixels(0, 0, 640, 480, gl::RGB, gl::UNSIGNED_BYTE, typed_buffer);
println!("Getting texture: {}", texture_id);
// InvalidEnum
//gl::BindTexture(gl::TEXTURE_2D, texture_id);
//gl::GetnTexImage(gl::TEXTURE_2D, 0, gl::RGB8, gl::UNSIGNED_BYTE, 1_228_800, typed_buffer);
println!("Bind");
gl::BindTexture(gl::TEXTURE_2D, texture_id);
println!("getn");
//gl::GetnTexImage(gl::TEXTURE_2D, 0, gl::RGB, gl::UNSIGNED_BYTE, 15_360_000, typed_buffer);
//gl::GetnTexImage(gl::TEXTURE_2D, 0, gl::RGB, gl::UNSIGNED_BYTE, 15_360_000, typed_buffer); // WORKS
gl::GetnTexImage(gl::TEXTURE_2D, 0, gl::RGB, gl::UNSIGNED_BYTE, size as i32, typed_buffer);
println!("load from memory");
gl_get_error().unwrap();
println!("Write buffer to camera");
gl::BindTexture(gl::TEXTURE_2D, 0);
//let img = image::load_from_memory(&buffer).unwrap();
//let resized = img.resize(640, 480, FilterType::Nearest);
//let bytes = resized.to_bytes();
println!("Buffer width before: {}", buffer.len());
/*let mut resizer = resize::new(
800,
800,
640,
480,
resize::Pixel::RGB24,
resize::Type::Lanczos3);
let capacity = 640 * 480 * 3;
let mut dst_buffer = Vec::with_capacity(capacity);
dst_buffer.resize(capacity, 0);*/
/*for _ in 0 .. capacity {
dst_buffer.push(0);
}*/
//resizer.resize(&buffer, &mut dst_buffer);
/*println!("Buffer width after: {}", dst_buffer.len());
println!("Values: {}, {}, {}, {}, {}",
dst_buffer.get(0).unwrap(),
dst_buffer.get(10).unwrap(),
dst_buffer.get(100).unwrap(),
dst_buffer.get(5000).unwrap(),
dst_buffer.get(10000).unwrap());*/
//let width = 640 * 480 * 3;
//buffer.truncate(width);
//println!("Buffer width after: {}", buffer.len());
//gl::GetTextureImage(texture_id, 0, gl::RGB, gl::UNSIGNED_BYTE, 1_228_800, typed_buffer);
/*let image_size = 640 * 480 * 3;
println!("Writing mmap of size {}", file.len());
println!("Writing bytes: {}", image_size);
let mut image_buf = Vec::with_capacity(image_size);
image_buf.resize(image_size, 255);
let typed_buffer = image_buf.as_mut_ptr();
/// Grab the current texture held by `texture_id` and immediately write it to file.
pub fn write_current_frame_to_file(&mut self, texture_id: GLuint) -> Result<(), WebcamError> {
let mut typed_buffer = self.buffer.as_mut_ptr() as *mut c_void;
unsafe {
std::ptr::copy_nonoverlapping::<u8>(typed_buffer,
file.data(),
image_size as usize);
}*/
gl::BindTexture(gl::TEXTURE_2D, texture_id);
gl::GetnTexImage(gl::TEXTURE_2D, 0, gl::RGB, gl::UNSIGNED_BYTE, self.buffer_size as i32, typed_buffer);
/*let width = 1280;
let height = 720;
let depth = 3;
let size = width * height * depth;
let mut buffer= Vec::with_capacity(width * height);
buffer.resize(size, 255);
gl_get_error()?;
let use_width = true;
let mut i = 0;
for y in 0 .. height {
for x in 0 .. width {
/*
> approx_bytes = 2763000 - 1843500
919500
> approx_bytes/3
306500
> approx_bytes/3/720
425.69444444444446
*/
// y < 720 is the height of the screen. Duh.
/*buffer[i + 0] = 0;
buffer[i + 1] = 0;
buffer[i + 2] = 0;
// byte # 1_843_500 is super close to the start.
if i < 1_843_500 {
buffer[i + 0] = 255;
}
// byte # 2_763_000 is super close to the end.
if i < 2_763_000 {
buffer[i + 1] = 255;
}
if i < 3_000_000 {
buffer[i + 2] = 255;
}*/
if use_width {
// Width
buffer[i] = (x as f32 / width as f32 * 255.0) as u8;
buffer[i + 1] = (x as f32 / width as f32 * 255.0) as u8;
buffer[i + 2] = (x as f32 / width as f32 * 255.0) as u8;
} else {
// Height
buffer[i] = (y as f32 / height as f32 * 255.0) as u8;
buffer[i + 1] = (y as f32 / height as f32 * 255.0) as u8;
buffer[i + 2] = (y as f32 / height as f32 * 255.0) as u8;
}
i += depth;
}
}*/
gl::BindTexture(gl::TEXTURE_2D, 0);
}
//(&mut file[..]).write_all(&buffer[0..1280*720*3]).expect("work");
//(&mut file[..]).write_all(&buffer[0..1280*720*3]).expect("work");
file.write_all(&buffer).expect("should write");
file.flush().expect("flush");
self.file.write_all(&self.buffer)?;
self.file.flush()?;
Ok(())
}
}
/// Errors from this module.
#[derive(Debug)]
pub enum WebcamError {
IoError(io::Error),
OpenGlError(OpenGlError),
}
impl fmt::Display for WebcamError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let explain = match self {
WebcamError::IoError(e) => format!("IoError: {:?}", e),
WebcamError::OpenGlError(e) => format!("OpenGL error: {:?}", e),
};
write!(f, "{}", explain)
}
}
impl std::error::Error for WebcamError {
fn source(&self) -> Option<&(dyn std::error::Error +'static)> {
None // Generic error, no backtrace.
}
}
impl From<io::Error> for WebcamError {
fn from(error: io::Error) -> Self {
WebcamError::IoError(error)
}
}
impl From<OpenGlError> for WebcamError {
fn from(error: OpenGlError) -> Self {
WebcamError::OpenGlError(error)
}
}