forked from pedrosland/rascam
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ca33426
commit abb3c31
Showing
11 changed files
with
351 additions
and
273 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2017 Peter Sutherland | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,127 +1,41 @@ | ||
http://www.jvcref.com/files/PI/documentation/html/index.html | ||
http://vojtech.kral.hk/en/rust-ffi-wrapping-c-api-in-rust-struct/ | ||
http://siciarz.net/ffi-rust-writing-bindings-libcpuid/ | ||
# Rascam | ||
|
||
TODO: | ||
* decide on API | ||
* see what we can do about using Rust's memory allocator instead of `vcos`? malloc | ||
* match up capture method and complete status from callback function. this is currently very unsafe! | ||
* try to reduce unsafe rust to minimum | ||
* anything else unsafe? | ||
Rust library for interacting with the Raspberry Pi Camera. | ||
|
||
# API ideas | ||
This provides a friendly, high level API over the [mmal-sys](https://crates.io/crates/mmal-sys) library. | ||
|
||
## New SimpleCamera | ||
There are three main components in this library: | ||
|
||
Do we want to force users to use futures? Should we provide a callback-style API? Should `capture_still()` just block? | ||
* Info - Describe the attached camera. | ||
* SimpleCamera - Aims to provide a simple, easy to use API. | ||
* SeriousCamera - This API is very unstable and will likely change! Aims to expose the power of the `mmal-sys`'s camera while providing a safe Rust API. | ||
|
||
Note that these C types should actually be wrappers, not raw types or they are likely to cause memory management fun. | ||
## Documentation and examples | ||
|
||
There should be settings for brightness, exposure, burst mode, image format etc etc. | ||
Please see the [documentation](https://docs.rs/crate/mmal/0.0.0) and [examples](https://github.com/pedrosland/mmal/tree/master/examples) | ||
|
||
Should we provide a preview API? | ||
## Usage | ||
|
||
What API should be used for getting camera info? Note that this lists both cameras and "flashes". | ||
Add the following to your Cargo.toml, changing `0.0.1` for the latest release: | ||
|
||
### `SimpleCamera::new() -> SimpleCamera` | ||
|
||
### `set_camera_num(u8) -> Result<MMAL_PARAMETER_CAMERA_INFO_CAMERA_T, MMAL_STATUS_T>` | ||
|
||
### `set_camera_info(MMAL_PARAMETER_CAMERA_INFO_CAMERA_T) -> Result<(), MMAL_STATUS_T>` | ||
|
||
This is a companion for the above. Useful if the user already has a `MMAL_PARAMETER_CAMERA_INFO_CAMERA_T`. Does it provide enough value? | ||
|
||
### `activate() -> Result<(), MMAL_STATUS_T>` | ||
|
||
Start the camera. Useful for metering etc. | ||
|
||
### `capture_still() -> Future<[u8], MMAL_STATUS_T>` | ||
|
||
Take a still picture. | ||
|
||
What about burst mode? `capture_burst() -> Stream<[u8], MMAL_STATUS_T>`? | ||
|
||
### `record_video() -> Stream<[u8], MMAL_STATUS_T>` | ||
|
||
Record a video and return a stream of frames. | ||
|
||
### `stop_video()` | ||
|
||
Should this return a `Result<(), ?>` so that we can error if not already recording a video? | ||
|
||
## Old SimpleCamera | ||
|
||
Is there much need for `Result` when we have `MMAL_SUCCESS`? Not really but `Result` is Rust-like and `MMAL_SUCCESS` is C-like. | ||
|
||
How should we represent errors? Is just `MMAL_STATUS_T` ok? | ||
Is this informative? Should we have a `CameraError` type with a code property? Is this better? Is it enough? | ||
|
||
What happens when there are multiple libmmal calls inside a method? Is it clear which the error comes from or what it means? | ||
|
||
### `SimpleCamera::new() -> Result<SimpleCamera, MMAL_STATUS_T>` | ||
|
||
Should this actually create camera objects? (it does now) | ||
Should this take the camera number? | ||
Should this take a `MMAL_PARAMETER_CAMERA_INFO_CAMERA_T`? | ||
|
||
### `set_camera_num(u8) -> Result<(), MMAL_STATUS_T>` | ||
|
||
If constructor doesn't take a camera number or camera info, we | ||
should get one here. | ||
|
||
Users or SimpleCamera shouldn't care about any of the following APIs except `take()`. | ||
|
||
### `create_encoder() -> Result<(), MMAL_STATUS_T>` | ||
|
||
### `enable_control_port() -> Result<(), MMAL_STATUS_T>` | ||
|
||
### `set_camera_params(MMAL_PARAMETER_CAMERA_INFO_CAMERA_T) -> Result<(), MMAL_STATUS_T>` | ||
|
||
Users shouldn't have to pass this in. | ||
|
||
### `set_camera_format(MMAL_PARAMETER_CAMERA_INFO_CAMERA_T) -> Result<(), MMAL_STATUS_T>` | ||
|
||
Users shouldn't have to pass this in and certainly not twice. | ||
|
||
### `enable() -> Result<(), MMAL_STATUS_T>` | ||
|
||
### `create_pool() -> Result<(), MMAL_STATUS_T>` | ||
|
||
### `create_preview() -> Result<(), MMAL_STATUS_T>` | ||
|
||
### `enable_preview() -> Result<(), MMAL_STATUS_T>` | ||
|
||
### `connect_ports() -> Result<(), MMAL_STATUS_T>` | ||
|
||
### `enable_still_port() -> Result<(), MMAL_STATUS_T>` | ||
|
||
### `take() -> Result<(), MMAL_STATUS_T>` | ||
|
||
Rename to capture? | ||
|
||
## SeriousCamera (or just Camera?) | ||
|
||
## CameraInfo | ||
|
||
`CameraInfo::info() -> Result<CameraInfo, MMAL_STATUS_T>` | ||
```toml | ||
[dependencies] | ||
rascam = "0.0.1" | ||
``` | ||
|
||
# Debugging | ||
Import this crate into your lib.rs or main.rs file: | ||
|
||
``` | ||
$ convert --version | ||
Version: ImageMagick 6.9.9-27 Q16 x86_64 2017-12-23 http://www.imagemagick.org | ||
Copyright: © 1999-2018 ImageMagick Studio LLC | ||
License: http://www.imagemagick.org/script/license.php | ||
Features: Cipher DPC Modules OpenMP | ||
Delegates (built-in): bzlib cairo djvu fftw fontconfig freetype gslib jbig jng jp2 jpeg lcms ltdl lzma openexr pangocairo png ps rsvg tiff webp wmf x xml zlib | ||
```rust | ||
extern crate rascam; | ||
``` | ||
|
||
To test rgb output: | ||
``` | ||
convert -size 96x96 -depth 8 -colorspace RGB rgb:test.rgb out.png | ||
If things are crashing or producing unexpected results there is a feature flag which enables some print statements which may help to debug an issue: | ||
|
||
```toml | ||
[dependencies] | ||
libc = { version = "0.0.1", features = ["debug"] } | ||
``` | ||
|
||
Note that `mmal_port_parameter_get` and `mmal_port_parameter_set` use memcpy into our struct so `params` should be owned by rust. | ||
https://github.com/raspberrypi/userland/blob/a1b89e91f393c7134b4cdc36431f863bb3333163/interface/mmal/vc/mmal_vc_api.c#L1222 | ||
## License | ||
|
||
TODO: why does `cargo test` require a `build.rs` in the top level package when `cargo build` does not? | ||
Released under the MIT license. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
TODO: | ||
* see what we can do about using Rust's memory allocator instead of `vcos`? malloc | ||
* try to reduce unsafe rust to minimum | ||
* anything else unsafe? | ||
|
||
# API ideas | ||
|
||
## New SimpleCamera | ||
|
||
Note that these C types should actually be wrappers, not raw types or they are likely to cause memory management fun. | ||
|
||
There should be settings for brightness, exposure, burst mode, image format etc etc. | ||
|
||
Should we provide a preview API? | ||
|
||
What API should be used for getting camera info? Note that this lists both cameras and "flashes". | ||
|
||
### `SimpleCamera::new() -> SimpleCamera` | ||
|
||
### `set_camera_num(u8) -> Result<MMAL_PARAMETER_CAMERA_INFO_CAMERA_T, MMAL_STATUS_T>` | ||
|
||
### `set_camera_info(MMAL_PARAMETER_CAMERA_INFO_CAMERA_T) -> Result<(), MMAL_STATUS_T>` | ||
|
||
This is a companion for the above. Useful if the user already has a `MMAL_PARAMETER_CAMERA_INFO_CAMERA_T`. Does it provide enough value? | ||
|
||
### `activate() -> Result<(), MMAL_STATUS_T>` | ||
|
||
Start the camera. Useful for metering etc. | ||
|
||
### `capture_still() -> Future<[u8], MMAL_STATUS_T>` | ||
|
||
Take a still picture. | ||
|
||
What about burst mode? `capture_burst() -> Stream<[u8], MMAL_STATUS_T>`? | ||
|
||
### `record_video() -> Stream<[u8], MMAL_STATUS_T>` | ||
|
||
Record a video and return a stream of frames. | ||
|
||
### `stop_video()` | ||
|
||
Should this return a `Result<(), ?>` so that we can error if not already recording a video? | ||
|
||
## Old SimpleCamera | ||
|
||
Is there much need for `Result` when we have `MMAL_SUCCESS`? Not really but `Result` is Rust-like and `MMAL_SUCCESS` is C-like. | ||
|
||
How should we represent errors? Is just `MMAL_STATUS_T` ok? | ||
Is this informative? Should we have a `CameraError` type with a code property? Is this better? Is it enough? | ||
|
||
What happens when there are multiple libmmal calls inside a method? Is it clear which the error comes from or what it means? | ||
|
||
### `SimpleCamera::new() -> Result<SimpleCamera, MMAL_STATUS_T>` | ||
|
||
Should this actually create camera objects? (it does now) | ||
Should this take the camera number? | ||
Should this take a `MMAL_PARAMETER_CAMERA_INFO_CAMERA_T`? | ||
|
||
### `set_camera_num(u8) -> Result<(), MMAL_STATUS_T>` | ||
|
||
If constructor doesn't take a camera number or camera info, we | ||
should get one here. | ||
|
||
Users or SimpleCamera shouldn't care about any of the following APIs except `take()`. | ||
|
||
### `create_encoder() -> Result<(), MMAL_STATUS_T>` | ||
|
||
### `enable_control_port() -> Result<(), MMAL_STATUS_T>` | ||
|
||
### `set_camera_params(MMAL_PARAMETER_CAMERA_INFO_CAMERA_T) -> Result<(), MMAL_STATUS_T>` | ||
|
||
Users shouldn't have to pass this in. | ||
|
||
### `set_camera_format(MMAL_PARAMETER_CAMERA_INFO_CAMERA_T) -> Result<(), MMAL_STATUS_T>` | ||
|
||
Users shouldn't have to pass this in and certainly not twice. | ||
|
||
### `enable() -> Result<(), MMAL_STATUS_T>` | ||
|
||
### `create_pool() -> Result<(), MMAL_STATUS_T>` | ||
|
||
### `create_preview() -> Result<(), MMAL_STATUS_T>` | ||
|
||
### `enable_preview() -> Result<(), MMAL_STATUS_T>` | ||
|
||
### `connect_ports() -> Result<(), MMAL_STATUS_T>` | ||
|
||
### `enable_still_port() -> Result<(), MMAL_STATUS_T>` | ||
|
||
### `take() -> Result<(), MMAL_STATUS_T>` | ||
|
||
Rename to capture? | ||
|
||
## SeriousCamera (or just Camera?) | ||
|
||
## CameraInfo | ||
|
||
`CameraInfo::info() -> Result<CameraInfo, MMAL_STATUS_T>` | ||
|
||
# Debugging | ||
|
||
``` | ||
convert --version | ||
Version: ImageMagick 6.9.7-4 Q16 arm 20170114 http://www.imagemagick.org | ||
Copyright: © 1999-2017 ImageMagick Studio LLC | ||
License: http://www.imagemagick.org/script/license.php | ||
Features: Cipher DPC Modules OpenMP | ||
Delegates (built-in): bzlib djvu fftw fontconfig freetype jbig jng jp2 jpeg lcms lqr ltdl lzma openexr pangocairo png tiff wmf x xml zlib | ||
``` | ||
|
||
To test rgb output: | ||
``` | ||
convert -size 96x96 -depth 8 -colorspace RGB rgb:test.rgb out.png | ||
``` | ||
|
||
Note that `mmal_port_parameter_get` and `mmal_port_parameter_set` use memcpy into our struct so `params` should be owned by rust. | ||
https://github.com/raspberrypi/userland/blob/a1b89e91f393c7134b4cdc36431f863bb3333163/interface/mmal/vc/mmal_vc_api.c#L1222 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
extern crate rascam; | ||
|
||
use std::fs::File; | ||
use std::io::Write; | ||
use std::{thread, time}; | ||
use rascam::*; | ||
|
||
fn main() { | ||
let info = info().unwrap(); | ||
if info.cameras.len() < 1 { | ||
println!("Found 0 cameras. Exiting"); | ||
// note that this doesn't run destructors | ||
::std::process::exit(1); | ||
} | ||
println!("{}", info); | ||
|
||
serious(&info.cameras[0]); | ||
} | ||
|
||
fn serious(info: &CameraInfo) { | ||
let mut camera = SeriousCamera::new().unwrap(); | ||
println!("camera created"); | ||
camera.set_camera_num(0).unwrap(); | ||
println!("camera number set"); | ||
camera.create_encoder().unwrap(); | ||
println!("encoder created"); | ||
camera.enable_control_port(true).unwrap(); | ||
println!("camera control port enabled"); | ||
camera.set_camera_params(info).unwrap(); | ||
println!("camera params set"); | ||
|
||
let settings = CameraSettings { | ||
encoding: MMAL_ENCODING_RGB24, | ||
width: 96, // 96px will not require padding | ||
height: 96, | ||
zero_copy: true, | ||
use_encoder: false, | ||
}; | ||
|
||
camera.set_camera_format(&settings).unwrap(); | ||
println!("set camera format"); | ||
camera.enable().unwrap(); | ||
println!("camera enabled"); | ||
camera.create_pool().unwrap(); | ||
println!("pool created"); | ||
|
||
camera.create_preview().unwrap(); | ||
println!("preview created"); | ||
camera.connect_preview().unwrap(); | ||
println!("preview connected"); | ||
camera.enable_preview().unwrap(); | ||
println!("preview enabled"); | ||
|
||
println!("taking photo"); | ||
|
||
let sleep_duration = time::Duration::from_millis(2000); | ||
thread::sleep(sleep_duration); | ||
|
||
let receiver = camera.take().unwrap(); | ||
|
||
let buffer = receiver.recv().unwrap().unwrap(); | ||
|
||
File::create("image.rgb") | ||
.unwrap() | ||
.write_all(&buffer.get_bytes()) | ||
.unwrap(); | ||
|
||
println!("Raw rgb bytes written to image.rgb"); | ||
println!("Try: convert -size 96x96 -depth 8 -colorspace RGB rgb:image.rgb image.png"); | ||
// If imagemagick gives something like: | ||
// convert-im6.q16: unexpected end-of-file `image.rgb': No such file or directory @ error/rgb.c/ReadRGBImage/239. | ||
// There is probably padding in the image. Check the width. | ||
} |
Oops, something went wrong.