├── CHANGES ├── LICENSE ├── Makefile-shared ├── README.md ├── benchmark ├── Makefile ├── bench.c ├── bench.h ├── h264.c ├── jpeg.c ├── rgb.c └── yuv.c ├── clean-all.sh ├── examples ├── Makefile-common ├── Makefile-shared-common ├── still │ ├── jpeg │ │ ├── Makefile │ │ ├── Makefile-shared │ │ ├── OpenCVexample.c │ │ └── jpeg.c │ ├── rgb │ │ ├── Makefile │ │ ├── Makefile-shared │ │ └── rgb.c │ └── yuv │ │ ├── Makefile │ │ ├── Makefile-shared │ │ └── yuv.c └── video │ ├── h264-motion-nopthread │ ├── Makefile │ ├── Makefile-shared │ └── h264-motion-nopthread.c │ ├── h264-motion │ ├── Makefile │ ├── Makefile-shared │ └── h264-motion.c │ ├── h264-nopthread │ ├── Makefile │ ├── Makefile-shared │ └── h264-nopthread.c │ ├── h264-stdout │ ├── Makefile │ ├── Makefile-shared │ └── h264-stdout.c │ ├── h264-update-timer │ ├── Makefile │ ├── Makefile-shared │ └── h264-update-timer.c │ ├── h264-update │ ├── Makefile │ ├── Makefile-shared │ └── h264-update.c │ ├── h264 │ ├── Makefile │ ├── Makefile-shared │ └── h264.c │ ├── rgb │ ├── Makefile │ ├── Makefile-shared │ └── rgb.c │ └── yuv │ ├── Makefile │ ├── Makefile-shared │ └── yuv.c ├── include ├── omxcam.h └── omxcam_version.h └── src ├── camera.c ├── core.c ├── debug.c ├── dump_omx.c ├── error.c ├── event.c ├── h264.c ├── internal.h ├── jpeg.c ├── still.c ├── utils.c ├── version.c └── video.c /CHANGES: -------------------------------------------------------------------------------- 1 | v0.0.1 (xx xx 2014) 2 | First release. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Gabriel Llamas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile-shared: -------------------------------------------------------------------------------- 1 | # Path to the target shared library 2 | TARGET_LIB = lib/libomxcam.so 3 | 4 | CC = gcc 5 | # Add -DOMXCAM_DEBUG for debugging purposes 6 | CFLAGS = -DSTANDALONE -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS \ 7 | -DTARGET_POSIX -D_LINUX -DPIC -D_REENTRANT -D_LARGEFILE64_SOURCE \ 8 | -D_FILE_OFFSET_BITS=64 -U_FORTIFY_SOURCE -DHAVE_LIBOPENMAX=2 -DOMX \ 9 | -DOMX_SKIP64BIT -DUSE_EXTERNAL_OMX -DHAVE_LIBBCM_HOST \ 10 | -DUSE_EXTERNAL_LIBBCM_HOST -DUSE_VCHIQ_ARM -fPIC -ftree-vectorize -pipe \ 11 | -Werror -g -Wall -O2 -fvisibility=hidden -DOMXCAM_DEBUG 12 | LDFLAGS = -shared 13 | INCLUDES = -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads \ 14 | -I/opt/vc/include/interface/vmcs_host/linux -I./src -I./include 15 | 16 | SRC = $(wildcard src/*.c) 17 | OBJS = $(patsubst src/%.c,src/%.o,$(SRC)) 18 | 19 | all: $(TARGET_LIB) 20 | 21 | %.o: %.c 22 | $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ -Wno-deprecated-declarations 23 | 24 | $(TARGET_LIB): $(OBJS) 25 | @mkdir -p $(@D) 26 | $(CC) -o $@ -Wl,--whole-archive $(OBJS) $(LDFLAGS) -Wl,--no-whole-archive -rdynamic 27 | 28 | .PHONY: clean rebuild 29 | 30 | clean: 31 | rm -f $(TARGET_LIB) src/*.o 32 | 33 | rebuild: 34 | make -f Makefile-shared clean && make -f Makefile-shared -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | omxcam 2 | ====== 3 | 4 | #### OpenMAX camera abstraction layer for the Raspberry Pi #### 5 | 6 | [Forum thread](http://www.raspberrypi.org/forums/viewtopic.php?f=43&t=72523) 7 | 8 | The Raspberry Pi uses the Bellagio's implementation of the OpenMAX IL specification in order to expose the media codecs (audio/image/video) available for the board. Broadcom, the manufacturer of the SoC, extends it by adding some propietary communication between the components. OpenMAX it's by nature open source. The problem here is the Broadcom's specific implementation which is closed source, so despite being the Raspberry Pi a platform built on top of an open source specification, there are some hidden parts in the interface that you must discover as an IL client by trial and error and with the little help that some of the Broadcom employees can provide. 9 | 10 | Furthermore, there is an extra layer called MMAL (Multi-Media Abstraction Layer) that sits on top of OpenMAX IL but it's also closed source and written by Broadcom. This API it's supposed to be used by the developers to communicate with the media components, including the camera module. But there's a problem with it, it lacks of documentation. It's a hard job to get used to it by simply looking at the raspistill/raspivid examples. MMAL it's not a camera library, so you still need to write how the components interact with each other. 11 | 12 | This library talks directly with OpenMAX IL and it's just an abstraction layer to ease the camera usage. It's not bloated with a lot of functionalities, it just provides the minimum functions to start and stop the streaming of the media content (image/video). You receive the content directly from the OpenMAX IL layer and you decide how to process the data. 13 | 14 | You will notice that the only available encoding algorithms are JPEG and H264. That's for a good reason; they are the only encoders that are hardware-accelerated. Encoding the images/videos with another encoder would take too long. 15 | 16 | #### Some references #### 17 | 18 | If you want to see [SSCCE](http://www.sscce.org/) examples, check these two projects: [jpeg](https://github.com/gagle/raspberrypi-openmax-jpeg) and [h264](https://github.com/gagle/raspberrypi-openmax-h264). 19 | 20 | For a global understanding of the camera module check the documentation of the [picamera](http://picamera.readthedocs.org) project. 21 | 22 | ### API ### 23 | 24 | When you start the streaming, a new thread is spawned and it's the responsible of emitting the data. You define a buffer callback and you receive the data when it's ready to be consumed, that's all. You don't even need to `malloc()` and `free()` the buffers, just use them. If you need some kind of inter-thread communication, I recommend a lock-free queue. Look at the [concurrency kit](http://concurrencykit.org/) project for more details, especially the `ck_ring_*()` functions. 25 | 26 | - [Build](#build) 27 | - [Error handling](#error_handling) 28 | - [Camera modes](#camera_modes) 29 | - [Camera settings](#camera_settings) 30 | - [Image streaming](#image_streaming) 31 | - [Video streaming](#video_streaming) 32 | - [OpenGL](#opengl) 33 | - [Utilities](#utilities) 34 | 35 | The [omxcam.h](https://github.com/gagle/raspberrypi-omxcam/blob/master/include/omxcam.h) header file is what you need to include in your projects. All the enumerations, type definitions and prototypes are located here. This README file introduces the library and explains just a few things. For a full reference, please take a look at the header `omxcam.h`. 36 | 37 | 38 | #### Build #### 39 | 40 | Two makefiles are provided with each example: `Makefile` and `Makefile-shared`. If you compile an example with the latter makefile you will also need to execute the makefile [./Makefile-shared](https://github.com/gagle/raspberrypi-omxcam/blob/master/Makefile-shared) in order to compile the library as a shared library. This will generate the file `./lib/libomxcam.so`. 41 | 42 | For example, to compile the example [./examples/still/jpeg](https://github.com/gagle/raspberrypi-omxcam/tree/master/examples/still/jpeg) with the whole code embedded in the binary file: 43 | 44 | ``` 45 | $ cd ./examples/still/jpeg 46 | $ make 47 | ``` 48 | To compile the library as a shared library and link it to the binary file: 49 | 50 | ``` 51 | $ make -f Makefile-shared 52 | $ cd ./examples/still/jpeg 53 | $ make -f Makefile-shared 54 | ``` 55 | 56 | Please take into account that the shared library needs to be located in the `./lib` directory due to this LDFLAG that you can find in [./examples/Makefile-shared-common](https://github.com/gagle/raspberrypi-omxcam/blob/master/examples/Makefile-shared-common): 57 | 58 | ``` 59 | -Wl,-rpath=$(OMXCAM_HOME)/lib 60 | ``` 61 | 62 | If you need to store the library in another place, change the path, use the environment variable `LD_LIBRARY_PATH` or put the library in a common place, e.g. `/usr/lib`. 63 | 64 | 65 | #### Error handling #### 66 | 67 | All the functions that have a non-void return, return an `int` type: `0` if the function succeeds, `-1` otherwise. If something fails, you can call to `omxcam_last_error()` to get the last error number. You have additional functions such as `omxcam_error_name(omxcam_errno)` which returns the error name, `omxcam_strerror(omxcam_errno)` which returns the string message describing the error and `omxcam_perror()` which formats and prints the last error to the stderr, something similar to this: 68 | 69 | ``` 70 | omxcam: OMXCAM_ERROR_INIT_CAMERA: cannot initialize the 'camera' component 71 | ``` 72 | 73 | You should not get any error. If you receive an error and you are sure that it's not due to bad parameters, you can enable the debugging flag `-DOMXCAM_DEBUG` and recompile the library. An even more specific error message should be printed to the stdout, for example: 74 | 75 | ``` 76 | omxcam: error: OMX_EventError: OMX_ErrorInsufficientResources (function: 'event_handler', file: '../../../src/core.c', line: 41) 77 | ``` 78 | 79 | Copy all the debug messages and open an issue. 80 | 81 | All the error codes and their descriptive messages are: 82 | 83 | ``` 84 | X (0, ERROR_NONE, "success") \ 85 | X (1, ERROR_CAMERA_MODULE, "camera module is not ready to be used") \ 86 | X (2, ERROR_DRIVERS, "cannot load the camera drivers") \ 87 | X (3, ERROR_INIT, "initialization error") \ 88 | X (4, ERROR_INIT_CAMERA, "cannot initialize the 'camera' component") \ 89 | X (5, ERROR_INIT_IMAGE_ENCODER, "cannot initialize the 'image_encode' " \ 90 | "component") \ 91 | X (6, ERROR_INIT_VIDEO_ENCODER, "cannot initialize the 'video_encode' " \ 92 | "component") \ 93 | X (7, ERROR_INIT_NULL_SINK, "cannot initialize the 'null_sink' component") \ 94 | X (8, ERROR_DEINIT, "deinitialization error") \ 95 | X (9, ERROR_DEINIT_CAMERA, "cannot deinitialize the 'camera' component") \ 96 | X (10, ERROR_DEINIT_IMAGE_ENCODER, "cannot deinitialize the 'image_encode' " \ 97 | "component") \ 98 | X (11, ERROR_DEINIT_VIDEO_ENCODER, "cannot deinitialize the 'video_encode' " \ 99 | "component") \ 100 | X (12, ERROR_DEINIT_NULL_SINK, "cannot deinitialize the 'null_sink' " \ 101 | "component") \ 102 | X (13, ERROR_CAPTURE, "error while capturing") \ 103 | X (14, ERROR_CAMERA_RUNNING, "camera is already running") \ 104 | X (15, ERROR_CAMERA_NOT_RUNNING, "camera is not running") \ 105 | X (16, ERROR_CAMERA_STOPPING, "camera is already being stopped") \ 106 | X (17, ERROR_CAMERA_UPDATE, "camera is not ready to be updated") \ 107 | X (18, ERROR_BAD_PARAMETER, "incorrect parameter value") \ 108 | X (19, ERROR_VIDEO_ONLY, "action can be executed only in video mode") \ 109 | X (20, ERROR_STILL, "still error") \ 110 | X (21, ERROR_VIDEO, "video error") \ 111 | X (22, ERROR_JPEG, "error configuring jpeg encoder") \ 112 | X (23, ERROR_H264, "error configuring h264 encoder") \ 113 | X (24, ERROR_LOADED, "cannot transition to the Loaded state") \ 114 | X (25, ERROR_IDLE, "cannot transition to the Idle state") \ 115 | X (26, ERROR_EXECUTING, "cannot transition to the Executing state") \ 116 | X (27, ERROR_FORMAT, "invalid encoding format") \ 117 | X (28, ERROR_SLEEP, "cannot sleep the thread") \ 118 | X (29, ERROR_WAKE, "cannot wake the thread") \ 119 | X (30, ERROR_LOCK, "cannot lock the thread") \ 120 | X (31, ERROR_UNLOCK, "cannot unlock the thread") 121 | ``` 122 | 123 | Note: If you receive a `ERROR_CAMERA_MODULE` error, make sure that the property `gpu_mem_512` or `gpu_mem_256` (depending on the model of the Raspberry Pi) has `128` or more MB in the file `/boot/config.txt`. Uncomment if necessary. For example, if you have a Raspberry Pi model B, Arch Linux ARM (build from june 2014) defaults to: 124 | 125 | ``` 126 | #gpu_mem_512=64 127 | ``` 128 | 129 | After: 130 | 131 | ``` 132 | gpu_mem_512=128 133 | ``` 134 | 135 | 136 | #### Camera modes #### 137 | 138 | 139 | 140 | 141 | #### Camera settings #### 142 | 143 | The `omxcam_still_settings_t` and `omxcam_video_settings_t` structs have a `camera` field that is used to configure the camera settings. Its type definition is `omxcam_camera_settings_t` and has the following fields: 144 | 145 | ``` 146 | type name default range 147 | ---- ---- ------- ----- 148 | uint32_t width image 2592, video 1920 16 .. 2592 | 1920 149 | uint32_t height image 1944, video 1080 16 .. 1944 | 1080 150 | int32_t sharpness 0 -100 .. 100 151 | int32_t contrast 0 -100 .. 100 152 | uint32_t brightness 50 0 .. 100 153 | int32_t saturation 0 -100 .. 100 154 | uint32_t shutter_speed 0 (auto) 0 .. 155 | omxcam_iso iso OMXCAM_ISO_AUTO 156 | omxcam_exposure exposure OMXCAM_EXPOSURE_AUTO 157 | int32_t exposure_compensation 0 -24 .. 24 158 | omxcam_mirror mirror OMXCAM_MIRROR_NONE 159 | omxcam_rotation rotation OMXCAM_ROTATION_NONE 160 | omxcam_color_effects_t color_effects 161 | omxcam_bool enabled OMXCAM_FALSE 162 | uint32_t u 128 0 .. 255 163 | uint32_t v 128 0 .. 255 164 | omxcam_bool color_denoise OMXCAM_TRUE 165 | omxcam_metering metering OMXCAM_METERING_AVERAGE 166 | omxcam_white_balance_t white_balance 167 | omxcam_white_balance mode OMXCAM_WHITE_BALANCE_AUTO 168 | uint32_t red_gain 100 0 .. 169 | uint32_t blue_gain 100 0 .. 170 | omxcam_image_filter image_filter OMXCAM_IMAGE_FILTER_NONE 171 | omxcam_drc drc OMXCAM_DRC_OFF 172 | omxcam_roi_t roi 173 | uint32_t top 0 0 .. 100 174 | uint32_t left 0 0 .. 100 175 | uint32_t width 0 0 .. 100 176 | uint32_t height 0 0 .. 100 177 | uint32_t framerate 30 2 .. 178 | omxcam_bool frame_stabilisation OMXCAM_FALSE 179 | ``` 180 | 181 | All the previous settings can be used in video and still mode, except: 182 | 183 | - Still only: `color_denoise`. 184 | - Video only: `framerate`, `frame_stabilisation`. 185 | 186 | For example, if you want to take a grayscale jpeg image with vga resolution (640x480), vertically mirrored and with a fixed shutter speed of 1/2 second: 187 | 188 | ```c 189 | omxcam_still_settings_t settings; 190 | 191 | omxcam_still_init (&settings); 192 | 193 | settings.camera.mirror = OMXCAM_MIRROR_VERTICAL; 194 | 195 | //Shutter speed in milliseconds 196 | settings.camera.shutter_speed = 500; 197 | 198 | //When 'camera.color_effects' is enabled, 'camera.color_effects.u' and 199 | //'camera.color_effects.v' are used. They default to 128, the values for a 200 | //grayscale image 201 | settings.camera.color_effects = OMXCAM_TRUE; 202 | ``` 203 | 204 | The `omxcam_h264_settings_t` struct has the following fields: 205 | 206 | ``` 207 | type name default range 208 | ---- ---- ------- ----- 209 | uint32_t bitrate 17000000 1 .. 25000000 210 | uint32_t idr_period OMXCAM_H264_IDR_PERIOD_OFF 0 .. 211 | omxcam_bool sei OMXCAM_FALSE 212 | omxcam_eede_t eede 213 | omxcam_bool enabled OMXCAM_FALSE 214 | uint32_t loss_rate 0 0 .. 100 215 | omxcam_quantization_t qp 216 | omxcam_bool enabled OMXCAM_FALSE 217 | uint32_t i OMXCAM_H264_QP_OFF 1 .. 51 218 | uint32_t p OMXCAM_H264_QP_OFF 1 .. 51 219 | ``` 220 | 221 | 222 | #### Image streaming #### 223 | 224 | ```c 225 | #include "omxcam.h" 226 | 227 | void on_data (uint8_t* buffer, uint32_t length){ 228 | //buffer: the data 229 | //length: the length of the buffer 230 | } 231 | 232 | int main (){ 233 | //The settings of the image capture 234 | omxcam_still_settings_t settings; 235 | 236 | //Initialize the settings with default values (jpeg, 2592x1944) 237 | omxcam_still_init (&settings); 238 | 239 | //Set the buffer callback, this is mandatory 240 | settings.on_data = on_data; 241 | 242 | //Start the image streaming 243 | omxcam_still_start (&settings); 244 | 245 | //Then, from anywhere in your code you can stop the image capture 246 | //omxcam_stop_still (); 247 | } 248 | ``` 249 | 250 | 251 | #### Video streaming #### 252 | 253 | ```c 254 | #include "omxcam.h" 255 | 256 | void on_data (uint8_t* buffer, uint32_t length){ 257 | //buffer: the data 258 | //length: the length of the buffer 259 | } 260 | 261 | int main (){ 262 | //The settings of the video capture 263 | omxcam_video_settings_t settings; 264 | 265 | //Initialize the settings with default values (h264, 1920x1080, 30fps) 266 | omxcam_video_init (&settings); 267 | 268 | //Set the buffer callback, this is mandatory 269 | settings.on_data = on_data; 270 | 271 | //Two capture modes: with or without a timer 272 | //Capture 3000ms 273 | omxcam_video_start (&settings, 3000); 274 | 275 | //Capture indefinitely 276 | omxcam_video_start (&settings, OMXCAM_CAPTURE_FOREVER); 277 | 278 | //Then, from anywhere in your code you can stop the video capture 279 | //omxcam_stop_video (); 280 | } 281 | ``` 282 | 283 | 284 | #### OpenGL #### 285 | 286 | 287 | 288 | 289 | #### Utilities #### 290 | 291 | __Version__ 292 | 293 | Two functions are available: 294 | 295 | - ___uint32_t omxcam_version()___ 296 | Returns the library version packed into a single integer. 8 bits are used for each component, with the patch number stored in the 8 least significant bits, e.g. version 1.2.3 returns `0x010203`. 297 | 298 | - ___const char* omxcam_version()___ 299 | Returns the library version number as a string, e.g. `1.2.3`. 300 | 301 | __YUV planes__ 302 | 303 | When capturing YUV images/video, you need to calculate the offset and length of each plane if you want to manipulate them somehow. There are a couple of functions that you can use for that purpose: 304 | 305 | - __void omxcam_yuv_planes (uint32_t width, uint32_t height, omxcam_yuv_planes_t* planes)__ 306 | Given the width and height of a frame, returns an `omxcam_yuv_planes_t` struct with the offset and length of each plane. The struct definition contains the following fields: 307 | 308 | ```c 309 | uint32_t offset_y; 310 | uint32_t length_y; 311 | uint32_t offset_u; 312 | uint32_t length_u; 313 | uint32_t offset_v; 314 | uint32_t length_v; 315 | ``` 316 | 317 | Tip: you can calculate the size of a yuv frame this way: `offset_v + length_v`. 318 | 319 | - ___void omxcam_yuv_planes_slice (uint32_t width, omxcam_yuv_planes_t* planes)___ 320 | Same as `omxcam_yuv_planes()` but used to calculate the offset and length of the planes of a payload buffer. 321 | 322 | Look at the [still/yuv](https://github.com/gagle/raspberrypi-omxcam/blob/master/examples/still/yuv/yuv.c) and [video/yuv](https://github.com/gagle/raspberrypi-omxcam/blob/master/examples/video/yuv/yuv.c) examples for further details. -------------------------------------------------------------------------------- /benchmark/Makefile: -------------------------------------------------------------------------------- 1 | APP = bench 2 | OMXCAM_HOME = .. 3 | SRC = rgb.c yuv.c h264.c jpeg.c 4 | OBJS = rgb.o yuv.o h264.o jpeg.o 5 | CLEAN = rgb.o yuv.o h264.o jpeg.o 6 | 7 | include ../examples/Makefile-common -------------------------------------------------------------------------------- /benchmark/bench.c: -------------------------------------------------------------------------------- 1 | #include "bench.h" 2 | 3 | /* 4 | Default settings are used. This is not a "real" benchmark since the capture time 5 | depends on various settings like the shutter speed and scene illuminance. This 6 | is just a little benchmark to confirm that the library is working as expected. 7 | 8 | Note: Remove the flag -DOMXCAM_DEBUG from the makefile. 9 | 10 | Results: 11 | 12 | In video mode, the closer to 30fps and 1000ms, the better. 13 | In still mode, the faster, the better, being 1fps the minimum desirable. 14 | 15 | set up h264: 323 ms 16 | tear down h264: 58 ms 17 | set up h264 (npt): 319 ms 18 | tear down h264 (npt): 39 ms 19 | video rgb: 28.17 fps (1065 ms) 20 | video yuv: 28.17 fps (1065 ms) 21 | video yuv (npt): 27.86 fps (1077 ms) 22 | */ 23 | 24 | uint32_t start; 25 | uint32_t end; 26 | uint32_t diff1; 27 | uint32_t diff2; 28 | 29 | static uint32_t now (){ 30 | struct timespec t; 31 | clock_gettime (CLOCK_MONOTONIC, &t); 32 | return t.tv_sec*1000 + t.tv_nsec/1.0e6; 33 | } 34 | 35 | static void print_time_video (char* label, uint32_t frames){ 36 | printf ("%s: %.2f fps (%d ms)\n", label, frames/(diff1/1000.0), diff1); 37 | } 38 | 39 | /*static void print_time_still (char* label){ 40 | printf ("%s: %.2f fps (%d ms)\n", label, 1000.0/diff1, diff1); 41 | }*/ 42 | 43 | static int log_error (){ 44 | omxcam_perror (); 45 | return 1; 46 | } 47 | 48 | static void on_ready (){ 49 | start = now (); 50 | } 51 | 52 | static void on_stop (){ 53 | diff1 = now () - start; 54 | } 55 | 56 | static void on_ready_set_up (){ 57 | diff1 = now () - start; 58 | } 59 | 60 | static void on_stop_tear_down (){ 61 | start = now (); 62 | } 63 | 64 | int main (){ 65 | bench_t req; 66 | req.width = 640; 67 | req.height = 480; 68 | req.frames = 30; 69 | req.ms = 1000; 70 | 71 | req.on_ready = on_ready_set_up; 72 | req.on_stop = on_stop_tear_down; 73 | 74 | start = now (); 75 | if (h264 (&req)) return log_error (); 76 | diff2 = now () - start; 77 | printf ("set up h264: %d ms\n", diff1); 78 | printf ("tear down h264: %d ms\n", diff2); 79 | 80 | start = now (); 81 | if (h264_npt (&req)) return log_error (); 82 | diff2 = now () - start; 83 | printf ("set up h264 (npt): %d ms\n", diff1); 84 | printf ("tear down h264 (npt): %d ms\n", diff2); 85 | 86 | /*start = now (); 87 | if (jpeg (&req)) return log_error (); 88 | diff2 = now () - start; 89 | printf ("set up jpeg: %d ms\n", diff1); 90 | printf ("tear down jpeg: %d ms\n", diff2);*/ 91 | 92 | req.on_ready = on_ready; 93 | req.on_stop = on_stop; 94 | 95 | if (rgb_video (&req)) return log_error (); 96 | print_time_video ("video rgb", req.frames); 97 | 98 | if (yuv_video (&req)) return log_error (); 99 | print_time_video ("video yuv", req.frames); 100 | 101 | if (yuv_video_npt (&req)) return log_error (); 102 | print_time_video ("video yuv (npt)", req.frames); 103 | 104 | /*if (rgb_still (&req)) return log_error (); 105 | print_time_still ("still rgb"); 106 | 107 | if (yuv_still (&req)) return log_error (); 108 | print_time_still ("still yuv");*/ 109 | 110 | return 0; 111 | } -------------------------------------------------------------------------------- /benchmark/bench.h: -------------------------------------------------------------------------------- 1 | #ifndef BENCH_H 2 | #define BENCH_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "omxcam.h" 9 | 10 | typedef struct { 11 | uint32_t width; 12 | uint32_t height; 13 | uint32_t frames; 14 | uint32_t ms; 15 | void (*on_ready)(); 16 | void (*on_stop)(); 17 | } bench_t; 18 | 19 | int h264 (bench_t* req); 20 | int h264_npt (bench_t* req); 21 | int jpeg (bench_t* req); 22 | 23 | int rgb_video (bench_t* req); 24 | int rgb_still (bench_t* req); 25 | 26 | int yuv_video (bench_t* req); 27 | int yuv_video_npt (bench_t* req); 28 | int yuv_still (bench_t* req); 29 | 30 | #endif -------------------------------------------------------------------------------- /benchmark/h264.c: -------------------------------------------------------------------------------- 1 | #include "bench.h" 2 | 3 | int h264 (bench_t* req){ 4 | omxcam_video_settings_t settings; 5 | 6 | omxcam_video_init (&settings); 7 | settings.on_ready = req->on_ready; 8 | settings.on_stop = req->on_stop; 9 | settings.camera.width = req->width; 10 | settings.camera.height = req->height; 11 | 12 | return omxcam_video_start (&settings, req->ms); 13 | } 14 | 15 | int h264_npt (bench_t* req){ 16 | omxcam_video_settings_t settings; 17 | 18 | omxcam_video_init (&settings); 19 | settings.camera.width = req->width; 20 | settings.camera.height = req->height; 21 | 22 | if (omxcam_video_start_npt (&settings)) return -1; 23 | 24 | req->on_ready (); 25 | req->on_stop (); 26 | 27 | return omxcam_video_stop_npt (); 28 | } -------------------------------------------------------------------------------- /benchmark/jpeg.c: -------------------------------------------------------------------------------- 1 | #include "bench.h" 2 | 3 | int jpeg (bench_t* req){ 4 | omxcam_still_settings_t settings; 5 | 6 | omxcam_still_init (&settings); 7 | settings.on_ready = req->on_ready; 8 | settings.on_stop = req->on_stop; 9 | settings.camera.width = req->width; 10 | settings.camera.height = req->height; 11 | 12 | return omxcam_still_start (&settings); 13 | } -------------------------------------------------------------------------------- /benchmark/rgb.c: -------------------------------------------------------------------------------- 1 | #include "bench.h" 2 | 3 | static uint32_t current = 0; 4 | static uint32_t total; 5 | static int bg_error = 0; 6 | 7 | static void on_data_video (uint8_t* buffer, uint32_t length){ 8 | current += length; 9 | 10 | if (current >= total){ 11 | bg_error = omxcam_video_stop (); 12 | } 13 | } 14 | 15 | static void on_data_still (uint8_t* buffer, uint32_t length){ 16 | //No-op 17 | } 18 | 19 | int rgb_video (bench_t* req){ 20 | omxcam_video_settings_t settings; 21 | 22 | omxcam_video_init (&settings); 23 | settings.on_ready = req->on_ready; 24 | settings.on_data = on_data_video; 25 | settings.on_stop = req->on_stop; 26 | settings.format = OMXCAM_FORMAT_RGB888; 27 | settings.camera.width = req->width; 28 | settings.camera.height = req->height; 29 | 30 | total = req->width*req->height*3*req->frames; 31 | 32 | int error = omxcam_video_start (&settings, OMXCAM_CAPTURE_FOREVER); 33 | 34 | return error ? error : bg_error; 35 | } 36 | 37 | int rgb_still (bench_t* req){ 38 | omxcam_still_settings_t settings; 39 | 40 | omxcam_still_init (&settings); 41 | settings.on_ready = req->on_ready; 42 | settings.on_data = on_data_still; 43 | settings.on_stop = req->on_stop; 44 | settings.format = OMXCAM_FORMAT_RGB888; 45 | settings.camera.width = req->width; 46 | settings.camera.height = req->height; 47 | 48 | return omxcam_still_start (&settings); 49 | } -------------------------------------------------------------------------------- /benchmark/yuv.c: -------------------------------------------------------------------------------- 1 | #include "bench.h" 2 | 3 | static omxcam_yuv_planes_t planes; 4 | static uint32_t current; 5 | static uint32_t current_frames; 6 | static uint32_t frame_size; 7 | static int total_frames; 8 | static int bg_error = 0; 9 | static int quit = 0; 10 | 11 | static void on_data_video (uint8_t* buffer, uint32_t length){ 12 | current += length; 13 | 14 | if (current == frame_size){ 15 | current = 0; 16 | 17 | if (++current_frames == total_frames){ 18 | bg_error = omxcam_video_stop (); 19 | } 20 | } 21 | } 22 | 23 | static void on_data_video_npt (uint8_t* buffer, uint32_t length){ 24 | current += length; 25 | 26 | if (current == frame_size){ 27 | current = 0; 28 | 29 | if (++current_frames == total_frames){ 30 | quit = 1; 31 | bg_error = omxcam_video_stop_npt (); 32 | } 33 | } 34 | } 35 | 36 | static void on_data_still (uint8_t* buffer, uint32_t length){ 37 | //No-op 38 | } 39 | 40 | int yuv_video (bench_t* req){ 41 | current = 0; 42 | current_frames = 0; 43 | 44 | omxcam_video_settings_t settings; 45 | 46 | omxcam_video_init (&settings); 47 | settings.on_ready = req->on_ready; 48 | settings.on_data = on_data_video; 49 | settings.on_stop = req->on_stop; 50 | settings.format = OMXCAM_FORMAT_YUV420; 51 | settings.camera.width = req->width; 52 | settings.camera.height = req->height; 53 | 54 | omxcam_yuv_planes (req->width, req->height, &planes); 55 | 56 | frame_size = planes.offset_v + planes.length_v; 57 | total_frames = req->frames; 58 | 59 | int error = omxcam_video_start (&settings, OMXCAM_CAPTURE_FOREVER); 60 | 61 | return error ? error : bg_error; 62 | } 63 | 64 | int yuv_video_npt (bench_t* req){ 65 | current = 0; 66 | current_frames = 0; 67 | 68 | omxcam_video_settings_t settings; 69 | 70 | omxcam_video_init (&settings); 71 | settings.format = OMXCAM_FORMAT_YUV420; 72 | settings.camera.width = req->width; 73 | settings.camera.height = req->height; 74 | 75 | omxcam_yuv_planes (req->width, req->height, &planes); 76 | 77 | frame_size = planes.offset_v + planes.length_v; 78 | total_frames = req->frames; 79 | 80 | if (omxcam_video_start_npt (&settings)) return -1; 81 | omxcam_buffer_t buffer; 82 | 83 | req->on_ready (); 84 | 85 | while (!quit){ 86 | if (omxcam_video_read_npt (&buffer)) return -1; 87 | on_data_video_npt (buffer.data, buffer.length); 88 | } 89 | 90 | req->on_stop (); 91 | 92 | return bg_error; 93 | } 94 | 95 | int yuv_still (bench_t* req){ 96 | omxcam_still_settings_t settings; 97 | 98 | omxcam_still_init (&settings); 99 | settings.on_ready = req->on_ready; 100 | settings.on_data = on_data_still; 101 | settings.on_stop = req->on_stop; 102 | settings.format = OMXCAM_FORMAT_YUV420; 103 | settings.camera.width = req->width; 104 | settings.camera.height = req->height; 105 | 106 | return omxcam_still_start (&settings); 107 | } -------------------------------------------------------------------------------- /clean-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd $(dirname $0) 4 | dir=$(pwd -P) 5 | 6 | make -f Makefile-shared clean 7 | 8 | for file in $(find $dir -name Makefile); do 9 | cd $(dirname $file) 10 | make clean 11 | done -------------------------------------------------------------------------------- /examples/Makefile-common: -------------------------------------------------------------------------------- 1 | OMXCAM_HEADER_DIR = $(OMXCAM_HOME)/include 2 | OMXCAM_SRC_DIR = $(OMXCAM_HOME)/src 3 | OMXCAM_SRC_FILES = $(wildcard $(OMXCAM_SRC_DIR)/*.c) 4 | 5 | CC = gcc 6 | # Add -DOMXCAM_DEBUG for debugging purposes 7 | CFLAGS = -DSTANDALONE -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS \ 8 | -DTARGET_POSIX -D_LINUX -DPIC -D_REENTRANT -D_LARGEFILE64_SOURCE \ 9 | -D_FILE_OFFSET_BITS=64 -U_FORTIFY_SOURCE -DHAVE_LIBOPENMAX=2 -DOMX \ 10 | -DOMX_SKIP64BIT -DUSE_EXTERNAL_OMX -DHAVE_LIBBCM_HOST \ 11 | -DUSE_EXTERNAL_LIBBCM_HOST -DUSE_VCHIQ_ARM -fPIC -ftree-vectorize -pipe \ 12 | -Werror -g -Wall -O2 -fvisibility=hidden -DOMXCAM_DEBUG 13 | LDFLAGS = -L/opt/vc/lib -lopenmaxil -lbcm_host -lvchiq_arm -lpthread 14 | INCLUDES = -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads \ 15 | -I/opt/vc/include/interface/vmcs_host/linux -I./$(OMXCAM_SRC_DIR) \ 16 | -I./$(OMXCAM_HEADER_DIR) 17 | 18 | SRC := $(SRC) $(APP).c $(OMXCAM_SRC_FILES) 19 | OBJS := $(OBJS) $(APP).o $(patsubst $(OMXCAM_SRC_DIR)/%.c,$(OMXCAM_SRC_DIR)/%.o,$(OMXCAM_SRC_FILES)) 20 | 21 | all: $(APP) $(SRC) 22 | 23 | %.o: %.c 24 | $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ -Wno-deprecated-declarations 25 | 26 | $(APP): $(OBJS) 27 | $(CC) -o $@ -Wl,--whole-archive $(OBJS) $(LDFLAGS) -Wl,--no-whole-archive -rdynamic 28 | 29 | .PHONY: clean rebuild 30 | 31 | clean: 32 | rm -f $(APP) $(APP).o $(OMXCAM_SRC_DIR)/*.o $(CLEAN) 33 | 34 | rebuild: 35 | make clean && make 36 | -------------------------------------------------------------------------------- /examples/Makefile-shared-common: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -Werror -g -Wall -O2 3 | LDFLAGS = -L/opt/vc/lib -lopenmaxil -lbcm_host -lvchiq_arm -lpthread \ 4 | -L./$(OMXCAM_HOME)/lib -lomxcam -Wl,-rpath=$(OMXCAM_HOME)/lib 5 | INCLUDES = -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads \ 6 | -I/opt/vc/include/interface/vmcs_host/linux -I./$(OMXCAM_HOME)/include 7 | 8 | SRC := $(SRC) $(APP).c 9 | OBJS := $(OBJS) $(APP).o 10 | 11 | all: $(APP) $(SRC) 12 | 13 | %.o: %.c 14 | $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ -Wno-deprecated-declarations 15 | 16 | $(APP): $(OBJS) 17 | $(CC) -o $@ -Wl,--whole-archive $(OBJS) $(LDFLAGS) -Wl,--no-whole-archive -rdynamic 18 | 19 | .PHONY: clean rebuild 20 | 21 | clean: 22 | rm -f $(APP) $(APP).o $(CLEAN) 23 | 24 | rebuild: 25 | make -f Makefile-shared clean && make -f Makefile-shared -------------------------------------------------------------------------------- /examples/still/jpeg/Makefile: -------------------------------------------------------------------------------- 1 | APP = jpeg 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = still-default-2592x1944.jpg still-2592x1944.jpg 4 | 5 | include ../../Makefile-common -------------------------------------------------------------------------------- /examples/still/jpeg/Makefile-shared: -------------------------------------------------------------------------------- 1 | APP = jpeg 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = still-default-2592x1944.jpg still-2592x1944.jpg 4 | 5 | include ../../Makefile-shared-common -------------------------------------------------------------------------------- /examples/still/jpeg/OpenCVexample.c: -------------------------------------------------------------------------------- 1 | /* 2 | Make sure you have installed and linked the OpenCV and OMXCam libraries. 3 | */ 4 | 5 | #include "omxcam.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | using namespace cv; 14 | 15 | int log_error() { 16 | omxcam_perror(); 17 | return 1; 18 | } 19 | 20 | 21 | vector buffer; 22 | 23 | 24 | void on_data(omxcam_buffer_t omx_buffer) { 25 | for (uint ptr = 0; ptr < omx_buffer.length; ptr++) { 26 | buffer.push_back(omx_buffer.data[ptr]); 27 | } 28 | } 29 | 30 | 31 | int main() { 32 | 33 | //2592x1944 by default 34 | omxcam_still_settings_t settings; 35 | Mat builded_img; 36 | 37 | //Capture an image with default settings 38 | omxcam_still_init(&settings); 39 | 40 | settings.on_data = on_data; 41 | 42 | settings.camera.shutter_speed = 50000; 43 | settings.camera.iso = (omxcam_iso) 200; 44 | settings.jpeg.thumbnail.width = 0; 45 | settings.jpeg.thumbnail.height = 0; 46 | 47 | omxcam_still_start(&settings); 48 | builded_img = imdecode(buffer, CV_LOAD_IMAGE_COLOR); //needed for imwrite to work properly. 49 | printf(“Image captured\n”); 50 | imwrite("Default_test.jpg",builded_img); 51 | buffer.clear(); 52 | omxcam_still_stop(); 53 | 54 | printf("ok\n"); 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /examples/still/jpeg/jpeg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "omxcam.h" 6 | 7 | int log_error (){ 8 | omxcam_perror (); 9 | return 1; 10 | } 11 | 12 | int fd; 13 | 14 | void on_data (omxcam_buffer_t buffer){ 15 | //Append the buffer to the file 16 | //Note: Writing the data directly to disk will slow down the capture speed 17 | //due to the I/O access. A posible workaround is to save the buffers into 18 | //memory, similar to the still/raw.c (YUV) example, and then write the 19 | //whole image to disk 20 | if (pwrite (fd, buffer.data, buffer.length, 0) == -1){ 21 | fprintf (stderr, "error: pwrite\n"); 22 | if (omxcam_still_stop ()) log_error (); 23 | } 24 | } 25 | 26 | int save (char* filename, omxcam_still_settings_t* settings){ 27 | printf ("capturing %s\n", filename); 28 | 29 | fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666); 30 | if (fd == -1){ 31 | fprintf (stderr, "error: open\n"); 32 | return -1; 33 | } 34 | 35 | if (omxcam_still_start (settings)) return log_error (); 36 | 37 | //Close the file 38 | if (close (fd)){ 39 | fprintf (stderr, "error: close\n"); 40 | return -1; 41 | } 42 | 43 | return 0; 44 | } 45 | 46 | int main (){ 47 | //2592x1944 by default 48 | omxcam_still_settings_t settings; 49 | 50 | //Capture an image with default settings 51 | omxcam_still_init (&settings); 52 | settings.on_data = on_data; 53 | //settings.camera.shutter_speed = 1000*1000; 54 | //settings.camera.exposure = OMXCAM_EXPOSURE_NIGHT; 55 | settings.camera.shutter_speed = 50000; 56 | settings.camera.iso = 200; 57 | settings.jpeg.thumbnail.width = 0; 58 | settings.jpeg.thumbnail.height = 0; 59 | settings.camera.image_filter = OMXCAM_IMAGE_FILTER_SHARPEN; 60 | 61 | if (save ("still-default-2592x1944.jpg", &settings)) return 1; 62 | 63 | //Capture gray image with shutter speed 1/4, EV -10 and some EXIF tags 64 | settings.camera.exposure_compensation = -10; 65 | //Shutter speed in microseconds, (1/4)*1e6 66 | settings.camera.shutter_speed = 250000; 67 | //Values of color_effects.u and color_effects.v are 128 by default, 68 | //a gray image 69 | settings.camera.color_effects.enabled = OMXCAM_TRUE; 70 | 71 | //See firmware/documentation/ilcomponents/image_decode.html for valid keys 72 | //See http://www.media.mit.edu/pia/Research/deepview/exif.html#IFD0Tags 73 | //for valid keys and their descriptions 74 | omxcam_exif_tag_t exif_tags[] = { 75 | //Manufacturer 76 | { "IFD0.Make", "omxcam" } 77 | }; 78 | settings.jpeg.exif.tags = exif_tags; 79 | settings.jpeg.exif.valid_tags = 1; 80 | 81 | //if (save ("still-2592x1944.jpg", &settings)) return 1; 82 | 83 | printf ("ok\n"); 84 | 85 | return 0; 86 | } -------------------------------------------------------------------------------- /examples/still/rgb/Makefile: -------------------------------------------------------------------------------- 1 | APP = rgb 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = still-640x480.rgb still-640x480.rgba 4 | 5 | include ../../Makefile-common -------------------------------------------------------------------------------- /examples/still/rgb/Makefile-shared: -------------------------------------------------------------------------------- 1 | APP = rgb 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = still.rgb still.rgba 4 | 5 | include ../../Makefile-shared-common -------------------------------------------------------------------------------- /examples/still/rgb/rgb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "omxcam.h" 8 | 9 | int log_error (){ 10 | omxcam_perror (); 11 | return 1; 12 | } 13 | 14 | int fd; 15 | 16 | void on_data (omxcam_buffer_t buffer){ 17 | //Append the buffer to the file 18 | //Note: Writing the data directly to disk will slow down the capture speed 19 | //due to the I/O access. A posible workaround is to save the buffers into 20 | //memory, similar to the YUV example, and then write the whole image to disk 21 | if (pwrite (fd, buffer.data, buffer.length, 0) == -1){ 22 | fprintf (stderr, "error: pwrite\n"); 23 | if (omxcam_still_stop ()) log_error (); 24 | } 25 | } 26 | 27 | int save (char* filename, omxcam_still_settings_t* settings){ 28 | printf ("capturing %s\n", filename); 29 | 30 | fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666); 31 | if (fd == -1){ 32 | fprintf (stderr, "error: open\n"); 33 | return 1; 34 | } 35 | 36 | if (omxcam_still_start (settings)) log_error (); 37 | 38 | //Close the file 39 | if (close (fd)){ 40 | fprintf (stderr, "error: close\n"); 41 | return 1; 42 | } 43 | 44 | return 0; 45 | } 46 | 47 | int main (){ 48 | omxcam_still_settings_t settings; 49 | omxcam_still_init (&settings); 50 | 51 | //2592x1944 by default 52 | 53 | settings.on_data = on_data; 54 | //Shutter speed in microseconds, (1/8)*1e6 55 | settings.camera.shutter_speed = 125000; 56 | settings.camera.width = 640; 57 | settings.camera.height = 480; 58 | 59 | //RGB, 640x480 60 | settings.format = OMXCAM_FORMAT_RGB888; 61 | 62 | if (save ("still-640x480.rgb", &settings)) return 1; 63 | 64 | //RGBA (alpha channel is unused, value 255), 640x480 65 | settings.format = OMXCAM_FORMAT_RGBA8888; 66 | 67 | if (save ("still-640x480.rgba", &settings)) return 1; 68 | 69 | printf ("ok\n"); 70 | 71 | return 0; 72 | } -------------------------------------------------------------------------------- /examples/still/yuv/Makefile: -------------------------------------------------------------------------------- 1 | APP = yuv 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = still-1312x736.yuv still-1312x976.yuv 4 | 5 | include ../../Makefile-common -------------------------------------------------------------------------------- /examples/still/yuv/Makefile-shared: -------------------------------------------------------------------------------- 1 | APP = yuv 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = still-1312x736.yuv still-1312x976.yuv 4 | 5 | include ../../Makefile-shared-common -------------------------------------------------------------------------------- /examples/still/yuv/yuv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "omxcam.h" 8 | 9 | int log_error (){ 10 | omxcam_perror (); 11 | return 1; 12 | } 13 | 14 | int fd; 15 | 16 | omxcam_yuv_planes_t yuv_planes; 17 | omxcam_yuv_planes_t yuv_planes_slice; 18 | uint32_t offset_y; 19 | uint32_t offset_u; 20 | uint32_t offset_v; 21 | uint8_t* file_buffer; 22 | 23 | void on_data (omxcam_buffer_t buffer){ 24 | //Append the data to the buffers 25 | memcpy (file_buffer + offset_y, buffer.data + yuv_planes_slice.offset_y, 26 | yuv_planes_slice.length_y); 27 | offset_y += yuv_planes_slice.length_y; 28 | 29 | memcpy (file_buffer + offset_u, buffer.data + yuv_planes_slice.offset_u, 30 | yuv_planes_slice.length_u); 31 | offset_u += yuv_planes_slice.length_u; 32 | 33 | memcpy (file_buffer + offset_v, buffer.data + yuv_planes_slice.offset_v, 34 | yuv_planes_slice.length_v); 35 | offset_v += yuv_planes_slice.length_v; 36 | } 37 | 38 | int save (char* filename, omxcam_still_settings_t* settings){ 39 | /* 40 | The camera returns YUV420PackedPlanar buffers/slices. 41 | Packed means that each slice has a little portion of y + u + v planes. 42 | Planar means that each YUV component is located in a different plane/array, 43 | that is, it's not interleaved. 44 | PackedPlannar allows you to process each plane at the same time, that is, 45 | you don't need to wait to receive the entire Y plane to begin processing 46 | the U plane. This is good if you want to stream and manipulate the buffers, 47 | but when you need to store the data into a file, you need to store the entire 48 | planes one after the other, that is: 49 | 50 | WRONG: store the buffers as they come 51 | (y+u+v) + (y+u+v) + (y+u+v) + (y+u+v) + ... 52 | 53 | RIGHT: save the slices in different buffers and then store the entire planes 54 | (y+y+y+y+...) + (u+u+u+u+...) + (v+v+v+v+...) 55 | 56 | For this purpose you have the following functions: 57 | 58 | omxcam_yuv_planes(): Given the width and height of a frame, returns the offset 59 | and length of each of the yuv planes. 60 | omxcam_yuv_planes_slice(): Same as 'omxcam_yuv_planes()' but used with the 61 | payload buffers. 62 | */ 63 | 64 | printf ("capturing %s\n", filename); 65 | 66 | fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); 67 | if (fd == -1){ 68 | fprintf (stderr, "error: open\n"); 69 | return 1; 70 | } 71 | 72 | omxcam_yuv_planes (settings->camera.width, settings->camera.height, 73 | &yuv_planes); 74 | omxcam_yuv_planes_slice (settings->camera.width, &yuv_planes_slice); 75 | 76 | int yuv_frame_size = yuv_planes.offset_v + yuv_planes.length_v; 77 | offset_y = yuv_planes.offset_y; 78 | offset_u = yuv_planes.offset_u; 79 | offset_v = yuv_planes.offset_v; 80 | 81 | //Allocate the buffer 82 | file_buffer = (uint8_t*)malloc (sizeof (uint8_t)*yuv_frame_size); 83 | 84 | if (omxcam_still_start (settings)) log_error (); 85 | 86 | if (pwrite (fd, file_buffer, yuv_frame_size, 0) == -1){ 87 | fprintf (stderr, "error: pwrite\n"); 88 | return 1; 89 | } 90 | 91 | free (file_buffer); 92 | 93 | //Close the file 94 | if (close (fd)){ 95 | fprintf (stderr, "error: close\n"); 96 | return 1; 97 | } 98 | 99 | return 0; 100 | } 101 | 102 | int main (){ 103 | omxcam_still_settings_t settings; 104 | omxcam_still_init (&settings); 105 | 106 | //2592x1944 by default 107 | 108 | settings.on_data = on_data; 109 | settings.format = OMXCAM_FORMAT_YUV420; 110 | //Shutter speed in milliseconds, (1/8)*1e6 111 | settings.camera.shutter_speed = 125000; 112 | settings.camera.width = 1296; 113 | 114 | /* 115 | Please note that the original aspect ratio of an image is 4:3. If you set 116 | dimensions with different ratios, the final image will still have the same 117 | aspect ratio (4:3) but you will notice that it will be cropped to the given 118 | dimensions. 119 | 120 | For example: 121 | - You want to take an image: 1296x730, 16:9. 122 | - The camera captures at 2592x1944, 4:3. 123 | - If you're capturing a raw image (no encoder), the width and the height need 124 | to be multiple of 32 and 16, respectively. You don't need to ensure that the 125 | dimensions are correct when capturing an image, this is done automatically, 126 | but you need to know them in order to open the file with the correct 127 | dimensions. 128 | - To go from 2592x1944 to 1296x730 the image needs to be resized to the 129 | "nearest" dimensions of the destination image but maintaining the 4:3 aspect 130 | ratio, that is, it is resized to 1296x972 (1296/(4/3) = 972). 131 | - The resized image it's cropped to 1312x736 in a centered way as depicted in 132 | the following diagram: 133 | 134 | -- ++++++++++++++++++++ -- 135 | 120 | + + | 136 | +- +------------------+ | 137 | | + + | 138 | 736 | + + | 976 (972 rounded up) 139 | | + + | 140 | +- +------------------+ | 141 | 120 | + + | 142 | -- ++++++++++++++++++++ -- 143 | 1312 144 | 145 | The inner image is what you get and the outer image is what it's captured by 146 | the camera. 147 | */ 148 | 149 | //YUV420, 1296x730, 16:9 150 | settings.camera.height = 730; 151 | 152 | if (save ("still-1312x736.yuv", &settings)) return 1; 153 | 154 | //YUV420, 1296x972, 4:3 155 | 156 | settings.camera.height = 972; 157 | 158 | if (save ("still-1312x976.yuv", &settings)) return 1; 159 | 160 | printf ("ok\n"); 161 | 162 | return 0; 163 | } -------------------------------------------------------------------------------- /examples/video/h264-motion-nopthread/Makefile: -------------------------------------------------------------------------------- 1 | APP = h264-motion-nopthread 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = video.h264 motion 4 | 5 | include ../../Makefile-common -------------------------------------------------------------------------------- /examples/video/h264-motion-nopthread/Makefile-shared: -------------------------------------------------------------------------------- 1 | APP = h264-motion-nopthread 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = video.h264 motion 4 | 5 | include ../../Makefile-shared-common -------------------------------------------------------------------------------- /examples/video/h264-motion-nopthread/h264-motion-nopthread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "omxcam.h" 8 | 9 | int fd; 10 | int fd_motion; 11 | uint32_t current = 0; 12 | int timeout = 2000; 13 | int quit = 0; 14 | 15 | int log_error (){ 16 | omxcam_perror (); 17 | return 1; 18 | } 19 | 20 | void signal_handler (int signal){ 21 | quit = 1; 22 | } 23 | 24 | void start_timer (){ 25 | signal (SIGALRM, signal_handler); 26 | 27 | struct itimerval timer; 28 | 29 | timer.it_value.tv_sec = timeout/1000; 30 | timer.it_value.tv_usec = (timeout*1000)%1000000; 31 | timer.it_interval.tv_sec = timer.it_interval.tv_usec = 0; 32 | 33 | setitimer (ITIMER_REAL, &timer, 0); 34 | } 35 | 36 | int save (char* filename, char* motion, omxcam_video_settings_t* settings){ 37 | printf ("capturing %s\n", filename); 38 | printf ("capturing motion %s\n", motion); 39 | 40 | fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666); 41 | if (fd == -1){ 42 | fprintf (stderr, "error: open\n"); 43 | return 1; 44 | } 45 | 46 | fd_motion = open (motion, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666); 47 | if (fd_motion == -1){ 48 | fprintf (stderr, "error: open (motion)\n"); 49 | return 1; 50 | } 51 | 52 | if (omxcam_video_start_npt (settings)) return log_error (); 53 | omxcam_buffer_t buffer; 54 | omxcam_bool is_motion_vector; 55 | start_timer (); 56 | 57 | while (!quit){ 58 | //When read() is called, the current thread is locked until 'on_data' is 59 | //executed or an error occurs 60 | if (omxcam_video_read_npt (&buffer, &is_motion_vector)) return log_error (); 61 | 62 | if (is_motion_vector){ 63 | if (pwrite (fd_motion, buffer.data, buffer.length, 0) == -1){ 64 | fprintf (stderr, "error: pwrite (motion)\n"); 65 | if (omxcam_video_stop_npt ()) log_error (); 66 | } 67 | }else{ 68 | if (pwrite (fd, buffer.data, buffer.length, 0) == -1){ 69 | fprintf (stderr, "error: pwrite\n"); 70 | if (omxcam_video_stop_npt ()) log_error (); 71 | } 72 | } 73 | } 74 | 75 | if (omxcam_video_stop_npt ()) return log_error (); 76 | 77 | if (close (fd)){ 78 | fprintf (stderr, "error: close\n"); 79 | return 1; 80 | } 81 | 82 | if (close (fd_motion)){ 83 | fprintf (stderr, "error: close (motion)\n"); 84 | return 1; 85 | } 86 | 87 | return 0; 88 | } 89 | 90 | int main (){ 91 | omxcam_video_settings_t settings; 92 | 93 | omxcam_video_init (&settings); 94 | settings.camera.width = 640; 95 | settings.camera.height = 480; 96 | settings.h264.inline_motion_vectors = OMXCAM_TRUE; 97 | 98 | if (save ("video.h264", "motion", &settings)) return 1; 99 | 100 | printf ("ok\n"); 101 | 102 | return 0; 103 | } -------------------------------------------------------------------------------- /examples/video/h264-motion/Makefile: -------------------------------------------------------------------------------- 1 | APP = h264-motion 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = video.h264 motion 4 | 5 | include ../../Makefile-common -------------------------------------------------------------------------------- /examples/video/h264-motion/Makefile-shared: -------------------------------------------------------------------------------- 1 | APP = h264-motion 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = video.h264 motion 4 | 5 | include ../../Makefile-shared-common -------------------------------------------------------------------------------- /examples/video/h264-motion/h264-motion.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "omxcam.h" 6 | 7 | int fd; 8 | int fd_motion; 9 | 10 | int log_error (){ 11 | omxcam_perror (); 12 | return 1; 13 | } 14 | 15 | void on_data (omxcam_buffer_t buffer){ 16 | if (pwrite (fd, buffer.data, buffer.length, 0) == -1){ 17 | fprintf (stderr, "error: pwrite\n"); 18 | if (omxcam_video_stop ()) log_error (); 19 | } 20 | } 21 | 22 | void on_motion (omxcam_buffer_t buffer){ 23 | if (pwrite (fd_motion, buffer.data, buffer.length, 0) == -1){ 24 | fprintf (stderr, "error: pwrite (motion)\n"); 25 | if (omxcam_video_stop ()) log_error (); 26 | } 27 | } 28 | 29 | int save (char* filename, char* motion, omxcam_video_settings_t* settings){ 30 | printf ("capturing %s\n", filename); 31 | printf ("capturing motion %s\n", motion); 32 | 33 | fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666); 34 | if (fd == -1){ 35 | fprintf (stderr, "error: open\n"); 36 | return 1; 37 | } 38 | 39 | fd_motion = open (motion, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666); 40 | if (fd_motion == -1){ 41 | fprintf (stderr, "error: open (motion)\n"); 42 | return 1; 43 | } 44 | 45 | if (omxcam_video_start (settings, 2000)) return log_error (); 46 | 47 | if (close (fd)){ 48 | fprintf (stderr, "error: close\n"); 49 | return 1; 50 | } 51 | 52 | if (close (fd_motion)){ 53 | fprintf (stderr, "error: close (motion)\n"); 54 | return 1; 55 | } 56 | 57 | return 0; 58 | } 59 | 60 | int main (){ 61 | omxcam_video_settings_t settings; 62 | 63 | omxcam_video_init (&settings); 64 | settings.on_data = on_data; 65 | settings.on_motion = on_motion; 66 | settings.camera.width = 640; 67 | settings.camera.height = 480; 68 | settings.h264.inline_motion_vectors = OMXCAM_TRUE; 69 | 70 | if (save ("video.h264", "motion", &settings)) return 1; 71 | 72 | printf ("ok\n"); 73 | 74 | return 0; 75 | } -------------------------------------------------------------------------------- /examples/video/h264-nopthread/Makefile: -------------------------------------------------------------------------------- 1 | APP = h264-nopthread 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = video.h264 4 | 5 | include ../../Makefile-common -------------------------------------------------------------------------------- /examples/video/h264-nopthread/Makefile-shared: -------------------------------------------------------------------------------- 1 | APP = h264-nopthread 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = video.h264 4 | 5 | include ../../Makefile-shared-common -------------------------------------------------------------------------------- /examples/video/h264-nopthread/h264-nopthread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "omxcam.h" 8 | 9 | int fd; 10 | uint32_t current = 0; 11 | int timeout = 2000; 12 | int quit = 0; 13 | 14 | int log_error (){ 15 | omxcam_perror (); 16 | return 1; 17 | } 18 | 19 | void signal_handler (int signal){ 20 | quit = 1; 21 | } 22 | 23 | void start_timer (){ 24 | signal (SIGALRM, signal_handler); 25 | 26 | struct itimerval timer; 27 | 28 | timer.it_value.tv_sec = timeout/1000; 29 | timer.it_value.tv_usec = (timeout*1000)%1000000; 30 | timer.it_interval.tv_sec = timer.it_interval.tv_usec = 0; 31 | 32 | setitimer (ITIMER_REAL, &timer, 0); 33 | } 34 | 35 | int save (char* filename, omxcam_video_settings_t* settings){ 36 | printf ("capturing %s\n", filename); 37 | 38 | fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666); 39 | if (fd == -1){ 40 | fprintf (stderr, "error: open\n"); 41 | return 1; 42 | } 43 | 44 | if (omxcam_video_start_npt (settings)) return log_error (); 45 | omxcam_buffer_t buffer; 46 | 47 | start_timer (); 48 | 49 | while (!quit){ 50 | //When read() is called, the current thread is locked until 'on_data' is 51 | //executed or an error occurs 52 | if (omxcam_video_read_npt (&buffer, 0)) return log_error (); 53 | 54 | //Append the buffer to the file 55 | if (pwrite (fd, buffer.data, buffer.length, 0) == -1){ 56 | fprintf (stderr, "error: pwrite\n"); 57 | if (omxcam_video_stop_npt ()) log_error (); 58 | } 59 | } 60 | 61 | if (omxcam_video_stop_npt ()) return log_error (); 62 | 63 | //Close the file 64 | if (close (fd)){ 65 | fprintf (stderr, "error: close\n"); 66 | return 1; 67 | } 68 | 69 | return 0; 70 | } 71 | 72 | int main (){ 73 | omxcam_video_settings_t settings; 74 | 75 | //Capture a video of ~2000ms, 640x480 @30fps 76 | omxcam_video_init (&settings); 77 | settings.camera.width = 640; 78 | settings.camera.height = 480; 79 | 80 | if (save ("video.h264", &settings)) return 1; 81 | 82 | printf ("ok\n"); 83 | 84 | return 0; 85 | } -------------------------------------------------------------------------------- /examples/video/h264-stdout/Makefile: -------------------------------------------------------------------------------- 1 | APP = h264-stdout 2 | OMXCAM_HOME = ../../.. 3 | 4 | include ../../Makefile-common -------------------------------------------------------------------------------- /examples/video/h264-stdout/Makefile-shared: -------------------------------------------------------------------------------- 1 | APP = h264-stdout 2 | OMXCAM_HOME = ../../.. 3 | 4 | include ../../Makefile-shared-common -------------------------------------------------------------------------------- /examples/video/h264-stdout/h264-stdout.c: -------------------------------------------------------------------------------- 1 | #include "omxcam.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | /* 8 | Usage: 9 | 10 | $ ./h264-stdout > video.h264 11 | 12 | Note: Remove the flag -DOMXCAM_DEBUG from the makefile. 13 | */ 14 | 15 | int log_error (){ 16 | omxcam_perror (); 17 | return 1; 18 | } 19 | 20 | void on_data (omxcam_buffer_t buffer){ 21 | //Write the buffers to the stdout 22 | if (write (STDOUT_FILENO, buffer.data, buffer.length) == -1){ 23 | fprintf (stderr, "error: write\n"); 24 | if (omxcam_video_stop ()) log_error (); 25 | } 26 | } 27 | 28 | void signal_handler (int signal){ 29 | if (omxcam_video_stop ()) log_error (); 30 | } 31 | 32 | int main (){ 33 | omxcam_video_settings_t settings; 34 | omxcam_video_init (&settings); 35 | 36 | settings.on_data = on_data; 37 | settings.camera.width = 640; 38 | settings.camera.height = 480; 39 | 40 | signal (SIGINT, signal_handler); 41 | signal (SIGTERM, signal_handler); 42 | signal (SIGQUIT, signal_handler); 43 | signal (SIGHUP, signal_handler); 44 | 45 | if (omxcam_video_start (&settings, OMXCAM_CAPTURE_FOREVER)){ 46 | return log_error (); 47 | } 48 | 49 | return 0; 50 | } -------------------------------------------------------------------------------- /examples/video/h264-update-timer/Makefile: -------------------------------------------------------------------------------- 1 | APP = h264-update-timer 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = video.h264 4 | 5 | include ../../Makefile-common -------------------------------------------------------------------------------- /examples/video/h264-update-timer/Makefile-shared: -------------------------------------------------------------------------------- 1 | APP = h264-update-timer 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = video.h264 4 | 5 | include ../../Makefile-shared-common -------------------------------------------------------------------------------- /examples/video/h264-update-timer/h264-update-timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "omxcam.h" 8 | 9 | //If you need to iterate through all the values of a setting, you can use the 10 | //available mapping macros. 11 | 12 | //Edit the following macros to apply all the possible values of a setting. 13 | #define MAP OMXCAM_IMAGE_FILTER_MAP 14 | #define MAP_LENGTH OMXCAM_IMAGE_FILTER_MAP_LENGTH 15 | #define FN omxcam_video_update_image_filter 16 | 17 | #define VALUES(_, value) value, 18 | 19 | int values[] = { 20 | MAP (VALUES) 21 | }; 22 | 23 | int fd; 24 | int current; 25 | int interval = 1000; 26 | int stop = 0; 27 | 28 | int log_error (){ 29 | omxcam_perror (); 30 | return 1; 31 | } 32 | 33 | void signal_handler (int signal){ 34 | if (stop){ 35 | struct itimerval timer; 36 | timer.it_value.tv_sec = timer.it_value.tv_usec = 0; 37 | timer.it_interval = timer.it_value; 38 | setitimer (ITIMER_REAL, &timer, 0); 39 | 40 | if (omxcam_video_stop ()) log_error (); 41 | return; 42 | } 43 | if (omxcam_video_update_image_filter (values[current])) log_error (); 44 | if (++current == MAP_LENGTH) stop = 1; 45 | } 46 | 47 | void on_ready (){ 48 | signal (SIGALRM, signal_handler); 49 | 50 | struct itimerval timer; 51 | 52 | timer.it_value.tv_sec = interval/1000; 53 | timer.it_value.tv_usec = (interval*1000)%1000000; 54 | timer.it_interval = timer.it_value; 55 | 56 | setitimer (ITIMER_REAL, &timer, 0); 57 | } 58 | 59 | void on_data (omxcam_buffer_t buffer){ 60 | if (pwrite (fd, buffer.data, buffer.length, 0) == -1){ 61 | fprintf (stderr, "error: pwrite\n"); 62 | if (omxcam_video_stop ()) log_error (); 63 | } 64 | } 65 | 66 | int save (char* filename, omxcam_video_settings_t* settings){ 67 | fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666); 68 | if (fd == -1){ 69 | fprintf (stderr, "error: open\n"); 70 | return 1; 71 | } 72 | 73 | if (omxcam_video_start (settings, OMXCAM_CAPTURE_FOREVER)){ 74 | return log_error (); 75 | } 76 | 77 | //Close the file 78 | if (close (fd)){ 79 | fprintf (stderr, "error: close\n"); 80 | return 1; 81 | } 82 | 83 | return 0; 84 | } 85 | 86 | int main (){ 87 | omxcam_video_settings_t settings; 88 | omxcam_video_init (&settings); 89 | 90 | settings.on_ready = on_ready; 91 | settings.on_data = on_data; 92 | settings.camera.width = 640; 93 | settings.camera.height = 480; 94 | 95 | if (save ("video.h264", &settings)) return 1; 96 | 97 | printf ("ok\n"); 98 | 99 | return 0; 100 | } -------------------------------------------------------------------------------- /examples/video/h264-update/Makefile: -------------------------------------------------------------------------------- 1 | APP = h264-update 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = video.h264 4 | 5 | include ../../Makefile-common -------------------------------------------------------------------------------- /examples/video/h264-update/Makefile-shared: -------------------------------------------------------------------------------- 1 | APP = h264-update 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = video.h264 4 | 5 | include ../../Makefile-shared-common -------------------------------------------------------------------------------- /examples/video/h264-update/h264-update.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "omxcam.h" 7 | 8 | int fd; 9 | long start; 10 | long change; 11 | long stop; 12 | int changed; 13 | 14 | //Time spent writing to disk, this is basically to ensure a 2-second video 15 | int delay = 110; 16 | 17 | int log_error (){ 18 | omxcam_perror (); 19 | return 1; 20 | } 21 | 22 | long now (){ 23 | struct timespec spec; 24 | clock_gettime (CLOCK_MONOTONIC, &spec); 25 | return spec.tv_sec*1000 + spec.tv_nsec/1.0e6; 26 | } 27 | 28 | void on_ready (){ 29 | //Record 1s, change settings and record 1s 30 | change = now () + 1000 + delay; 31 | } 32 | 33 | void on_data (omxcam_buffer_t buffer){ 34 | int ms = now (); 35 | 36 | if (!changed){ 37 | if (ms >= change){ 38 | changed = 1; 39 | stop = ms + 1000 + delay; 40 | //If an error occurs, the camera is still running, so you need stop it 41 | //manually if you want to stop recording 42 | if (omxcam_video_update_saturation (100)) log_error (); 43 | if (omxcam_video_update_mirror (OMXCAM_MIRROR_HORIZONTAL)) log_error (); 44 | } 45 | }else{ 46 | if (ms >= stop){ 47 | if (omxcam_video_stop ()) log_error (); 48 | return; 49 | } 50 | } 51 | 52 | //Append the buffer to the file 53 | if (pwrite (fd, buffer.data, buffer.length, 0) == -1){ 54 | fprintf (stderr, "error: pwrite\n"); 55 | if (omxcam_video_stop ()) log_error (); 56 | } 57 | } 58 | 59 | int save (char* filename, omxcam_video_settings_t* settings){ 60 | printf ("capturing %s\n", filename); 61 | 62 | fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666); 63 | if (fd == -1){ 64 | fprintf (stderr, "error: open\n"); 65 | return 1; 66 | } 67 | 68 | //Capture indefinitely 69 | if (omxcam_video_start (settings, OMXCAM_CAPTURE_FOREVER)){ 70 | return log_error (); 71 | } 72 | 73 | //Close the file 74 | if (close (fd)){ 75 | fprintf (stderr, "error: close\n"); 76 | return 1; 77 | } 78 | 79 | return 0; 80 | } 81 | 82 | int main (){ 83 | omxcam_video_settings_t settings; 84 | omxcam_video_init (&settings); 85 | 86 | settings.on_ready = on_ready; 87 | settings.on_data = on_data; 88 | settings.camera.width = 640; 89 | settings.camera.height = 480; 90 | 91 | if (save ("video.h264", &settings)) return 1; 92 | 93 | printf ("ok\n"); 94 | 95 | return 0; 96 | } -------------------------------------------------------------------------------- /examples/video/h264/Makefile: -------------------------------------------------------------------------------- 1 | APP = h264 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = video-time-640x480.h264 video-length-1920x1080.h264 4 | 5 | include ../../Makefile-common -------------------------------------------------------------------------------- /examples/video/h264/Makefile-shared: -------------------------------------------------------------------------------- 1 | APP = h264 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = video-time-640x480.h264 video-length-1920x1080.h264 4 | 5 | include ../../Makefile-shared-common -------------------------------------------------------------------------------- /examples/video/h264/h264.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "omxcam.h" 6 | 7 | int fd; 8 | uint32_t current = 0; 9 | 10 | int log_error (){ 11 | omxcam_perror (); 12 | return 1; 13 | } 14 | 15 | void on_data_time (omxcam_buffer_t buffer){ 16 | //Append the buffer to the file 17 | if (pwrite (fd, buffer.data, buffer.length, 0) == -1){ 18 | fprintf (stderr, "error: pwrite\n"); 19 | if (omxcam_video_stop ()) log_error (); 20 | } 21 | } 22 | 23 | void on_data_length (omxcam_buffer_t buffer){ 24 | current += buffer.length; 25 | 26 | //Max file size 2MB 27 | if (current > 2097152){ 28 | if (omxcam_video_stop ()) log_error (); 29 | return; 30 | } 31 | 32 | //Append the buffer to the file 33 | if (pwrite (fd, buffer.data, buffer.length, 0) == -1){ 34 | fprintf (stderr, "error: pwrite\n"); 35 | if (omxcam_video_stop ()) log_error (); 36 | } 37 | } 38 | 39 | int save_time (char* filename, omxcam_video_settings_t* settings){ 40 | printf ("capturing %s\n", filename); 41 | 42 | fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666); 43 | if (fd == -1){ 44 | fprintf (stderr, "error: open\n"); 45 | return 1; 46 | } 47 | 48 | //Capture ~2000ms 49 | if (omxcam_video_start (settings, 2000)) return log_error (); 50 | 51 | //Close the file 52 | if (close (fd)){ 53 | fprintf (stderr, "error: close\n"); 54 | return 1; 55 | } 56 | 57 | return 0; 58 | } 59 | 60 | int save_length (char* filename, omxcam_video_settings_t* settings){ 61 | printf ("capturing %s\n", filename); 62 | 63 | fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666); 64 | if (fd == -1){ 65 | fprintf (stderr, "error: open\n"); 66 | return 1; 67 | } 68 | 69 | //Capture indefinitely 70 | if (omxcam_video_start (settings, OMXCAM_CAPTURE_FOREVER)){ 71 | return log_error (); 72 | } 73 | 74 | //Close the file 75 | if (close (fd)){ 76 | fprintf (stderr, "error: close\n"); 77 | return 1; 78 | } 79 | 80 | return 0; 81 | } 82 | 83 | int main (){ 84 | //1920x1080 @30fps by default 85 | omxcam_video_settings_t settings; 86 | 87 | //Capture a video of ~2000ms, 640x480 @90fps 88 | //Camera modes: http://www.raspberrypi.org/new-camera-mode-released 89 | //Note: Encode the file at 30fps 90 | omxcam_video_init (&settings); 91 | settings.on_data = on_data_time; 92 | settings.camera.width = 640; 93 | settings.camera.height = 480; 94 | settings.camera.framerate = 90; 95 | 96 | if (save_time ("video-time-640x480.h264", &settings)) return 1; 97 | 98 | //Capture a video of 2MB, 1920x1080 @30fps 99 | omxcam_video_init (&settings); 100 | settings.on_data = on_data_length; 101 | 102 | if (save_length ("video-length-1920x1080.h264", &settings)) return 1; 103 | 104 | printf ("ok\n"); 105 | 106 | return 0; 107 | } -------------------------------------------------------------------------------- /examples/video/rgb/Makefile: -------------------------------------------------------------------------------- 1 | APP = rgb 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = video-640x480.rgb video-672x480.rgba 4 | 5 | include ../../Makefile-common -------------------------------------------------------------------------------- /examples/video/rgb/Makefile-shared: -------------------------------------------------------------------------------- 1 | APP = rgb 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = video-640x480.rgb video-672x480.rgba 4 | 5 | include ../../Makefile-shared-common -------------------------------------------------------------------------------- /examples/video/rgb/rgb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "omxcam.h" 8 | 9 | int fd; 10 | 11 | uint32_t current; 12 | uint32_t total; 13 | 14 | int log_error (){ 15 | omxcam_perror (); 16 | return 1; 17 | } 18 | 19 | void on_data (omxcam_buffer_t buffer){ 20 | uint32_t length = buffer.length; 21 | int stop = 0; 22 | current += length; 23 | 24 | if (current >= total){ 25 | length -= current - total; 26 | stop = 1; 27 | } 28 | 29 | //Append the buffer to the file 30 | if (pwrite (fd, buffer.data, length, 0) == -1){ 31 | fprintf (stderr, "error: pwrite\n"); 32 | if (omxcam_video_stop ()) log_error (); 33 | return; 34 | } 35 | 36 | if (stop){ 37 | if (omxcam_video_stop ()) log_error (); 38 | } 39 | } 40 | 41 | int save (char* filename, omxcam_video_settings_t* settings){ 42 | /* 43 | The RGB video comes in slices, that is, each buffer is part of a frame: 44 | buffer != frame -> buffer < frame. Take into account that a buffer can contain 45 | data from two consecutive frames because the frames are just concatenated one 46 | after the other. Therefore, you MUST control the storage/transmission of the 47 | frames because the video capture can be stopped at anytime, so it's likely 48 | that the last frame won't be received entirely, so the current received bytes 49 | MUST be discarded. For example: 50 | 51 | Note: Rf1 means channel Red of a pixel in the frame 1. 52 | 53 | ... Rf1 Gf1 Bf1 Rf2 Gf2 Bf2 ... 54 | | |-----------|-----------| | 55 | | |last pixel |first pixel| | 56 | | |of frame 1 |of frame 2 | | 57 | |-------------------------------| 58 | | buffer | 59 | */ 60 | 61 | printf ("capturing %s\n", filename); 62 | 63 | fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666); 64 | if (fd == -1){ 65 | fprintf (stderr, "error: open\n"); 66 | return 1; 67 | } 68 | 69 | if (omxcam_video_start (settings, OMXCAM_CAPTURE_FOREVER)) log_error (); 70 | 71 | //Close the file 72 | if (close (fd)){ 73 | fprintf (stderr, "error: close\n"); 74 | return 1; 75 | } 76 | 77 | return 0; 78 | } 79 | 80 | int main (){ 81 | omxcam_video_settings_t settings; 82 | omxcam_video_init (&settings); 83 | 84 | //1920x1080 @30fps by default 85 | 86 | settings.on_data = on_data; 87 | 88 | //RGB, 640x480 @30fps (10 frames) 89 | settings.format = OMXCAM_FORMAT_RGB888; 90 | settings.camera.width = 640; 91 | settings.camera.height = 480; 92 | settings.h264.inline_motion_vectors = OMXCAM_TRUE; 93 | 94 | current = 0; 95 | total = 640*480*3*10; 96 | 97 | if (save ("video-640x480.rgb", &settings)) return 1; 98 | 99 | //RGBA (alpha channel is unused, value 255), 642x480 @30fps (10 frames) 100 | //When no encoder is used, the width and the height need to be multiple of 32 101 | //and 16, therefore, 642 rounded up to the nearest multiple of 32 is 672 102 | settings.format = OMXCAM_FORMAT_RGBA8888; 103 | settings.camera.width = 642; 104 | settings.camera.height = 480; 105 | 106 | current = 0; 107 | total = 672*480*4*10; 108 | 109 | if (save ("video-672x480.rgba", &settings)) return 1; 110 | 111 | printf ("ok\n"); 112 | 113 | return 0; 114 | } -------------------------------------------------------------------------------- /examples/video/yuv/Makefile: -------------------------------------------------------------------------------- 1 | APP = yuv 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = video-640x480.yuv 4 | 5 | include ../../Makefile-common -------------------------------------------------------------------------------- /examples/video/yuv/Makefile-shared: -------------------------------------------------------------------------------- 1 | APP = yuv 2 | OMXCAM_HOME = ../../.. 3 | CLEAN = video-640x480.yuv 4 | 5 | include ../../Makefile-shared-common -------------------------------------------------------------------------------- /examples/video/yuv/yuv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "omxcam.h" 8 | 9 | int fd; 10 | 11 | uint32_t current = 0; 12 | uint32_t frames = 0; 13 | uint32_t frame_size; 14 | omxcam_yuv_planes_t planes; 15 | omxcam_yuv_planes_t planes_slice; 16 | uint32_t offset_y; 17 | uint32_t offset_u; 18 | uint32_t offset_v; 19 | uint8_t* file_buffer; 20 | 21 | int log_error (){ 22 | omxcam_perror (); 23 | return 1; 24 | } 25 | 26 | void on_data (omxcam_buffer_t buffer){ 27 | current += buffer.length; 28 | 29 | //Append the data to the buffer 30 | memcpy (file_buffer + offset_y, buffer.data + planes_slice.offset_y, 31 | planes_slice.length_y); 32 | offset_y += planes_slice.length_y; 33 | 34 | memcpy (file_buffer + offset_u, buffer.data + planes_slice.offset_u, 35 | planes_slice.length_u); 36 | offset_u += planes_slice.length_u; 37 | 38 | memcpy (file_buffer + offset_v, buffer.data + planes_slice.offset_v, 39 | planes_slice.length_v); 40 | offset_v += planes_slice.length_v; 41 | 42 | if (current == frame_size){ 43 | //An entire YUV frame has been received 44 | current = 0; 45 | 46 | offset_y = planes.offset_y; 47 | offset_u = planes.offset_u; 48 | offset_v = planes.offset_v; 49 | 50 | if (pwrite (fd, file_buffer, frame_size, 0) == -1){ 51 | fprintf (stderr, "error: pwrite\n"); 52 | if (omxcam_video_stop ()) log_error (); 53 | return; 54 | } 55 | 56 | if (++frames == 10){ 57 | //All the frames have been received 58 | if (omxcam_video_stop ()) log_error (); 59 | } 60 | } 61 | } 62 | 63 | int save (char* filename, omxcam_video_settings_t* settings){ 64 | /* 65 | The camera returns YUV420PackedPlanar buffers/slices. 66 | Packed means that each slice has a little portion of y + u + v planes. 67 | Planar means that each YUV component is located in a different plane/array, 68 | that is, it's not interleaved. 69 | PackedPlannar allows you to process each plane at the same time, that is, 70 | you don't need to wait to receive the entire Y plane to begin processing 71 | the U plane. This is good if you want to stream and manipulate the buffers, 72 | but when you need to store the data into a file, you need to store the entire 73 | planes one after the other, that is: 74 | 75 | WRONG: store the buffers as they come 76 | (y+u+v) + (y+u+v) + (y+u+v) + (y+u+v) + ... 77 | 78 | RIGHT: save the slices in different buffers and then store the entire planes 79 | (y+y+y+y+...) + (u+u+u+u+...) + (v+v+v+v+...) 80 | 81 | For this purpose you have the following functions: 82 | 83 | omxcam_yuv_planes(): Given the width and height of a frame, returns the offset 84 | and length of each of the yuv planes. 85 | omxcam_yuv_planes_slice(): Same as 'omxcam_yuv_planes()' but used with the 86 | payload buffers. 87 | 88 | In contrast to the RGB video, a YUV buffer contains data that belongs only to 89 | one frame, but you still need to control de storage/transmission of the frames 90 | because the video can be stopped at any time, so you need to make sure that 91 | the last whole frame is stored correctly. 92 | */ 93 | 94 | printf ("capturing %s\n", filename); 95 | 96 | fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666); 97 | if (fd == -1){ 98 | fprintf (stderr, "error: open\n"); 99 | return 1; 100 | } 101 | 102 | omxcam_yuv_planes (settings->camera.width, settings->camera.height, 103 | &planes); 104 | omxcam_yuv_planes_slice (settings->camera.width, &planes_slice); 105 | 106 | //Frame size 107 | frame_size = planes.offset_v + planes.length_v; 108 | 109 | offset_y = planes.offset_y; 110 | offset_u = planes.offset_u; 111 | offset_v = planes.offset_v; 112 | 113 | //Allocate the buffer 114 | file_buffer = (uint8_t*)malloc (sizeof (uint8_t)*frame_size); 115 | 116 | if (omxcam_video_start (settings, OMXCAM_CAPTURE_FOREVER)) log_error (); 117 | 118 | free (file_buffer); 119 | 120 | //Close the file 121 | if (close (fd)){ 122 | fprintf (stderr, "error: close\n"); 123 | return 1; 124 | } 125 | 126 | return 0; 127 | } 128 | 129 | int main (){ 130 | omxcam_video_settings_t settings; 131 | omxcam_video_init (&settings); 132 | 133 | //1920x1080 @30fps by default 134 | 135 | //YUV420, 640x480 @30fps (10 frames) 136 | settings.on_data = on_data; 137 | settings.format = OMXCAM_FORMAT_YUV420; 138 | settings.camera.width = 640; 139 | settings.camera.height = 480; 140 | 141 | if (save ("video-640x480.yuv", &settings)) return 1; 142 | 143 | printf ("ok\n"); 144 | 145 | return 0; 146 | } -------------------------------------------------------------------------------- /include/omxcam.h: -------------------------------------------------------------------------------- 1 | #ifndef OMXCAM_H 2 | #define OMXCAM_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | #include "omxcam_version.h" 12 | 13 | #if __GNUC__ >= 4 14 | # define OMXCAM_EXTERN __attribute__ ((visibility ("default"))) 15 | #else 16 | # define OMXCAM_EXTERN //Empty 17 | #endif 18 | 19 | //Error definitions, expand if necessary 20 | #define OMXCAM_ERRNO_MAP(X) \ 21 | X (0, ERROR_NONE, "success") \ 22 | X (1, ERROR_CAMERA_MODULE, "camera module is not ready to be used") \ 23 | X (2, ERROR_DRIVERS, "cannot load the camera drivers") \ 24 | X (3, ERROR_INIT, "initialization error") \ 25 | X (4, ERROR_INIT_CAMERA, "cannot initialize the 'camera' component") \ 26 | X (5, ERROR_INIT_IMAGE_ENCODER, "cannot initialize the 'image_encode' " \ 27 | "component") \ 28 | X (6, ERROR_INIT_VIDEO_ENCODER, "cannot initialize the 'video_encode' " \ 29 | "component") \ 30 | X (7, ERROR_INIT_NULL_SINK, "cannot initialize the 'null_sink' component") \ 31 | X (8, ERROR_DEINIT, "deinitialization error") \ 32 | X (9, ERROR_DEINIT_CAMERA, "cannot deinitialize the 'camera' component") \ 33 | X (10, ERROR_DEINIT_IMAGE_ENCODER, "cannot deinitialize the 'image_encode' " \ 34 | "component") \ 35 | X (11, ERROR_DEINIT_VIDEO_ENCODER, "cannot deinitialize the 'video_encode' " \ 36 | "component") \ 37 | X (12, ERROR_DEINIT_NULL_SINK, "cannot deinitialize the 'null_sink' " \ 38 | "component") \ 39 | X (13, ERROR_CAPTURE, "error while capturing") \ 40 | X (14, ERROR_CAMERA_RUNNING, "camera is already running") \ 41 | X (15, ERROR_CAMERA_NOT_RUNNING, "camera is not running") \ 42 | X (16, ERROR_CAMERA_STOPPING, "camera is already being stopped") \ 43 | X (17, ERROR_CAMERA_UPDATE, "camera is not ready to be updated") \ 44 | X (18, ERROR_BAD_PARAMETER, "incorrect parameter value") \ 45 | X (19, ERROR_VIDEO_ONLY, "action can be executed only in video mode") \ 46 | X (20, ERROR_STILL, "still error") \ 47 | X (21, ERROR_VIDEO, "video error") \ 48 | X (22, ERROR_JPEG, "error configuring jpeg encoder") \ 49 | X (23, ERROR_H264, "error configuring h264 encoder") \ 50 | X (24, ERROR_LOADED, "cannot transition to the Loaded state") \ 51 | X (25, ERROR_IDLE, "cannot transition to the Idle state") \ 52 | X (26, ERROR_EXECUTING, "cannot transition to the Executing state") \ 53 | X (27, ERROR_FORMAT, "invalid encoding format") \ 54 | X (28, ERROR_SLEEP, "cannot sleep the thread") \ 55 | X (29, ERROR_WAKE, "cannot wake the thread") \ 56 | X (30, ERROR_LOCK, "cannot lock the thread") \ 57 | X (31, ERROR_UNLOCK, "cannot unlock the thread") \ 58 | X (32, ERROR_NO_PTHREAD, "capture started in 'no pthread' mode") \ 59 | X (33, ERROR_NOT_NO_PTHREAD, "capture started not in 'no pthread' mode") 60 | 61 | #define OMXCAM_ISO_MAP_LENGTH 10 62 | #define OMXCAM_ISO_MAP(X) \ 63 | X (ISO_AUTO, 0) \ 64 | X (ISO_100, 100) \ 65 | X (ISO_160, 160) \ 66 | X (ISO_200, 200) \ 67 | X (ISO_250, 250) \ 68 | X (ISO_320, 320) \ 69 | X (ISO_400, 400) \ 70 | X (ISO_500, 500) \ 71 | X (ISO_640, 640) \ 72 | X (ISO_800, 800) 73 | 74 | #define OMXCAM_EXPOSURE_MAP_LENGTH 15 75 | #define OMXCAM_EXPOSURE_MAP(X) \ 76 | X (EXPOSURE_OFF, OMX_ExposureControlOff) \ 77 | X (EXPOSURE_AUTO, OMX_ExposureControlAuto) \ 78 | X (EXPOSURE_NIGHT, OMX_ExposureControlNight) \ 79 | X (EXPOSURE_BLACK_LIGHT, OMX_ExposureControlBackLight) \ 80 | X (EXPOSURE_SPOTLIGHT, OMX_ExposureControlSpotLight) \ 81 | X (EXPOSURE_SPORTS, OMX_ExposureControlSports) \ 82 | X (EXPOSURE_SNOW, OMX_ExposureControlSnow) \ 83 | X (EXPOSURE_BEACH, OMX_ExposureControlBeach) \ 84 | X (EXPOSURE_LARGE_APERTURE, OMX_ExposureControlLargeAperture) \ 85 | X (EXPOSURE_SMALL_APERTURE, OMX_ExposureControlSmallAperture) \ 86 | X (EXPOSURE_VERY_LONG, OMX_ExposureControlVeryLong) \ 87 | X (EXPOSURE_FIXED_FPS, OMX_ExposureControlFixedFps) \ 88 | X (EXPOSURE_NIGHT_WITH_PREVIEW, OMX_ExposureControlNightWithPreview) \ 89 | X (EXPOSURE_ANTISHAKE, OMX_ExposureControlAntishake) \ 90 | X (EXPOSURE_FIREWORKS, OMX_ExposureControlFireworks) 91 | 92 | #define OMXCAM_MIRROR_MAP_LENGTH 4 93 | #define OMXCAM_MIRROR_MAP(X) \ 94 | X (MIRROR_NONE, OMX_MirrorNone) \ 95 | X (MIRROR_VERTICAL, OMX_MirrorVertical) \ 96 | X (MIRROR_HORIZONTAL, OMX_MirrorHorizontal) \ 97 | X (MIRROR_BOTH, OMX_MirrorBoth) 98 | 99 | #define OMXCAM_ROTATION_MAP_LENGTH 4 100 | #define OMXCAM_ROTATION_MAP(X) \ 101 | X (ROTATION_NONE, 0) \ 102 | X (ROTATION_90, 90) \ 103 | X (ROTATION_180, 180) \ 104 | X (ROTATION_270, 270) 105 | 106 | #define OMXCAM_METERING_MAP_LENGTH 4 107 | #define OMXCAM_METERING_MAP(X) \ 108 | X (METERING_AVERAGE, OMX_MeteringModeAverage) \ 109 | X (METERING_SPOT, OMX_MeteringModeSpot) \ 110 | X (METERING_MATRIX, OMX_MeteringModeMatrix) \ 111 | X (METERING_BACKLIT, OMX_MeteringModeBacklit) 112 | 113 | #define OMXCAM_WHITE_BALANCE_MAP_LENGTH 10 114 | #define OMXCAM_WHITE_BALANCE_MAP(X) \ 115 | X (WHITE_BALANCE_OFF, OMX_WhiteBalControlOff) \ 116 | X (WHITE_BALANCE_AUTO, OMX_WhiteBalControlAuto) \ 117 | X (WHITE_BALANCE_SUNLIGHT, OMX_WhiteBalControlSunLight) \ 118 | X (WHITE_BALANCE_CLOUDY, OMX_WhiteBalControlCloudy) \ 119 | X (WHITE_BALANCE_SHADE, OMX_WhiteBalControlShade) \ 120 | X (WHITE_BALANCE_TUNGSTEN, OMX_WhiteBalControlTungsten) \ 121 | X (WHITE_BALANCE_FLUORESCENT, OMX_WhiteBalControlFluorescent) \ 122 | X (WHITE_BALANCE_INCANDESCENT, OMX_WhiteBalControlIncandescent) \ 123 | X (WHITE_BALANCE_FLASH, OMX_WhiteBalControlFlash) \ 124 | X (WHITE_BALANCE_HORIZON, OMX_WhiteBalControlHorizon) 125 | 126 | #define OMXCAM_IMAGE_FILTER_MAP_LENGTH 18 127 | #define OMXCAM_IMAGE_FILTER_MAP(X) \ 128 | X (IMAGE_FILTER_NONE, OMX_ImageFilterNone) \ 129 | X (IMAGE_FILTER_EMBOSS, OMX_ImageFilterEmboss) \ 130 | X (IMAGE_FILTER_NEGATIVE, OMX_ImageFilterNegative) \ 131 | X (IMAGE_FILTER_SKETCH, OMX_ImageFilterSketch) \ 132 | X (IMAGE_FILTER_OILPAINT, OMX_ImageFilterOilPaint) \ 133 | X (IMAGE_FILTER_HATCH, OMX_ImageFilterHatch) \ 134 | X (IMAGE_FILTER_GPEN, OMX_ImageFilterGpen) \ 135 | X (IMAGE_FILTER_SOLARIZE, OMX_ImageFilterSolarize) \ 136 | X (IMAGE_FILTER_WATERCOLOR, OMX_ImageFilterWatercolor) \ 137 | X (IMAGE_FILTER_PASTEL, OMX_ImageFilterPastel) \ 138 | X (IMAGE_FILTER_FILM, OMX_ImageFilterFilm) \ 139 | X (IMAGE_FILTER_BLUR, OMX_ImageFilterBlur) \ 140 | X (IMAGE_FILTER_COLOUR_SWAP, OMX_ImageFilterColourSwap) \ 141 | X (IMAGE_FILTER_WASHED_OUT, OMX_ImageFilterWashedOut) \ 142 | X (IMAGE_FILTER_COLOUR_POINT, OMX_ImageFilterColourPoint) \ 143 | X (IMAGE_FILTER_POSTERISE, OMX_ImageFilterPosterise) \ 144 | X (IMAGE_FILTER_COLOUR_BALANCE, OMX_ImageFilterColourBalance) \ 145 | X (IMAGE_FILTER_CARTOON, OMX_ImageFilterCartoon) 146 | 147 | #define OMXCAM_DRC_MAP_LENGTH 4 148 | #define OMXCAM_DRC_MAP(X) \ 149 | X (DRC_OFF, OMX_DynRangeExpOff) \ 150 | X (DRC_LOW, OMX_DynRangeExpLow) \ 151 | X (DRC_MEDIUM, OMX_DynRangeExpMedium) \ 152 | X (DRC_HIGH, OMX_DynRangeExpHigh) 153 | 154 | #define OMXCAM_H264_AVC_PROFILE_MAP_LENGTH 3 155 | #define OMXCAM_H264_AVC_PROFILE_MAP(X) \ 156 | X (H264_AVC_PROFILE_BASELINE, OMX_VIDEO_AVCProfileBaseline) \ 157 | X (H264_AVC_PROFILE_MAIN, OMX_VIDEO_AVCProfileMain) \ 158 | X (H264_AVC_PROFILE_HIGH, OMX_VIDEO_AVCProfileHigh) 159 | 160 | #define OMXCAM_SHUTTER_SPEED_AUTO 0 161 | #define OMXCAM_JPEG_THUMBNAIL_WIDTH_AUTO 0 162 | #define OMXCAM_JPEG_THUMBNAIL_HEIGHT_AUTO 0 163 | #define OMXCAM_H264_IDR_PERIOD_OFF 0 164 | #define OMXCAM_H264_QP_OFF 0 165 | 166 | //Handy way to sleep forever while recording a video 167 | #define OMXCAM_CAPTURE_FOREVER 0 168 | 169 | typedef enum { 170 | OMXCAM_FALSE, 171 | OMXCAM_TRUE 172 | } omxcam_bool; 173 | 174 | typedef enum { 175 | OMXCAM_FORMAT_RGB888, 176 | OMXCAM_FORMAT_RGBA8888, 177 | OMXCAM_FORMAT_YUV420, 178 | OMXCAM_FORMAT_JPEG, 179 | OMXCAM_FORMAT_H264 180 | } omxcam_format; 181 | 182 | #define OMXCAM_ENUM_FN(name, value) \ 183 | OMXCAM_ ## name = value, 184 | 185 | typedef enum { 186 | OMXCAM_ISO_MAP (OMXCAM_ENUM_FN) 187 | } omxcam_iso; 188 | 189 | typedef enum { 190 | OMXCAM_EXPOSURE_MAP (OMXCAM_ENUM_FN) 191 | } omxcam_exposure; 192 | 193 | typedef enum { 194 | OMXCAM_MIRROR_MAP (OMXCAM_ENUM_FN) 195 | } omxcam_mirror; 196 | 197 | typedef enum { 198 | OMXCAM_ROTATION_MAP (OMXCAM_ENUM_FN) 199 | } omxcam_rotation; 200 | 201 | typedef enum { 202 | OMXCAM_METERING_MAP (OMXCAM_ENUM_FN) 203 | } omxcam_metering; 204 | 205 | typedef enum { 206 | OMXCAM_WHITE_BALANCE_MAP (OMXCAM_ENUM_FN) 207 | } omxcam_white_balance; 208 | 209 | typedef enum { 210 | OMXCAM_IMAGE_FILTER_MAP (OMXCAM_ENUM_FN) 211 | } omxcam_image_filter; 212 | 213 | typedef enum { 214 | OMXCAM_DRC_MAP (OMXCAM_ENUM_FN) 215 | } omxcam_drc; 216 | 217 | typedef enum { 218 | OMXCAM_H264_AVC_PROFILE_MAP (OMXCAM_ENUM_FN) 219 | } omxcam_avc_profile; 220 | 221 | #undef OMXCAM_ENUM_FN 222 | 223 | #define OMXCAM_ENUM_FN(errno, name, _) \ 224 | OMXCAM_ ## name = errno, 225 | 226 | typedef enum { 227 | OMXCAM_ERRNO_MAP (OMXCAM_ENUM_FN) 228 | } omxcam_errno; 229 | 230 | #undef OMXCAM_ENUM_FN 231 | 232 | typedef struct { 233 | uint8_t* data; 234 | uint32_t length; 235 | } omxcam_buffer_t; 236 | 237 | typedef struct { 238 | omxcam_bool enabled; 239 | uint32_t u; 240 | uint32_t v; 241 | } omxcam_color_effects_t; 242 | 243 | typedef struct { 244 | omxcam_white_balance mode; 245 | uint32_t red_gain; 246 | uint32_t blue_gain; 247 | } omxcam_white_balance_t; 248 | 249 | typedef struct { 250 | uint32_t top; 251 | uint32_t left; 252 | uint32_t width; 253 | uint32_t height; 254 | } omxcam_roi_t; 255 | 256 | typedef struct { 257 | uint32_t width; 258 | uint32_t height; 259 | int32_t sharpness; 260 | int32_t contrast; 261 | uint32_t brightness; 262 | int32_t saturation; 263 | uint32_t shutter_speed; 264 | omxcam_iso iso; 265 | omxcam_exposure exposure; 266 | int32_t exposure_compensation; 267 | omxcam_mirror mirror; 268 | omxcam_rotation rotation; 269 | omxcam_color_effects_t color_effects; 270 | omxcam_bool color_denoise; 271 | omxcam_metering metering; 272 | omxcam_white_balance_t white_balance; 273 | omxcam_image_filter image_filter; 274 | omxcam_roi_t roi; 275 | omxcam_drc drc; 276 | //Used only in video mode 277 | uint32_t framerate; 278 | //Used only in video mode 279 | omxcam_bool frame_stabilisation; 280 | } omxcam_camera_settings_t; 281 | 282 | typedef struct { 283 | uint32_t offset_y; 284 | uint32_t length_y; 285 | uint32_t offset_u; 286 | uint32_t length_u; 287 | uint32_t offset_v; 288 | uint32_t length_v; 289 | } omxcam_yuv_planes_t; 290 | 291 | typedef struct { 292 | char* key; 293 | char* value; 294 | } omxcam_exif_tag_t; 295 | 296 | typedef struct { 297 | omxcam_bool enabled; 298 | omxcam_exif_tag_t* tags; 299 | uint32_t valid_tags; 300 | } omxcam_exif_t; 301 | 302 | typedef struct { 303 | omxcam_bool enabled; 304 | uint32_t width; 305 | uint32_t height; 306 | omxcam_bool preview; 307 | } omxcam_thumbnail_t; 308 | 309 | typedef struct { 310 | uint32_t quality; 311 | omxcam_exif_t exif; 312 | omxcam_bool ijg; 313 | omxcam_thumbnail_t thumbnail; 314 | omxcam_bool raw_bayer; 315 | } omxcam_jpeg_settings_t; 316 | 317 | typedef struct { 318 | omxcam_bool enabled; 319 | uint32_t loss_rate; 320 | } omxcam_eede_t; 321 | 322 | typedef struct { 323 | omxcam_bool enabled; 324 | uint32_t i; 325 | uint32_t p; 326 | } omxcam_quantization_t; 327 | 328 | typedef struct { 329 | uint32_t bitrate; 330 | uint32_t idr_period; 331 | omxcam_bool sei; 332 | omxcam_eede_t eede; 333 | omxcam_quantization_t qp; 334 | omxcam_avc_profile profile; 335 | omxcam_bool inline_headers; 336 | omxcam_bool inline_motion_vectors; 337 | } omxcam_h264_settings_t; 338 | 339 | #define OMXCAM_COMMON_SETTINGS \ 340 | omxcam_camera_settings_t camera; \ 341 | omxcam_format format; \ 342 | uint32_t camera_id; \ 343 | void (*on_ready)(); \ 344 | void (*on_data)(omxcam_buffer_t buffer); \ 345 | void (*on_motion)(omxcam_buffer_t buffer); \ 346 | void (*on_stop)(); 347 | 348 | typedef struct { 349 | OMXCAM_COMMON_SETTINGS 350 | omxcam_jpeg_settings_t jpeg; 351 | } omxcam_still_settings_t; 352 | 353 | typedef struct { 354 | OMXCAM_COMMON_SETTINGS 355 | omxcam_h264_settings_t h264; 356 | } omxcam_video_settings_t; 357 | 358 | #undef OMXCAM_COMMON_SETTINGS 359 | 360 | /* 361 | * Returns the string name of the given error. Returns NULL if the error is not 362 | * valid. 363 | */ 364 | OMXCAM_EXTERN const char* omxcam_error_name (omxcam_errno error); 365 | 366 | /* 367 | * Returns the string message of the given error. 368 | */ 369 | OMXCAM_EXTERN const char* omxcam_strerror (omxcam_errno error); 370 | 371 | /* 372 | * Returns the last error, if any. 373 | */ 374 | OMXCAM_EXTERN omxcam_errno omxcam_last_error (); 375 | 376 | /* 377 | * Prints to stderr the last error in this way: 378 | * 379 | * omxcam: : \n 380 | */ 381 | OMXCAM_EXTERN void omxcam_perror (); 382 | 383 | /* 384 | * Returns the library version packed into a single integer. 8 bits are used for 385 | * each component, with the patch number stored in the 8 least significant 386 | * bits, e.g. version 1.2.3 returns 0x010203. 387 | */ 388 | OMXCAM_EXTERN uint32_t omxcam_version (); 389 | 390 | /* 391 | * Returns the library version number as a string, e.g. 1.2.3 392 | */ 393 | OMXCAM_EXTERN const char* omxcam_version_string (); 394 | 395 | /* 396 | * Rounds up a number given a divisor. For example, omxcam_round(1944, 16) 397 | * returns 1952. It is mainly used to align values according to the OpenMAX IL 398 | * and the Raspberry Pi camera board. 399 | */ 400 | OMXCAM_EXTERN uint32_t omxcam_round (uint32_t value, uint32_t divisor); 401 | 402 | /* 403 | * Given the width and height of a frame, returns the offset and length of each 404 | * of the yuv planes. 405 | * 406 | * For example, a 2592x1944 yuv frame is organized as follows: 407 | * 408 | * omxcam_yuv_planes_t yuv; 409 | * omxcam_yuv_planes (2592, 1944, &yuv); 410 | * printf ( 411 | * "y: %d %d\n" 412 | * "u: %d %d\n" 413 | * "v: %d %d\n", 414 | * yuv.offset_y, yuv.length_y, 415 | * yuv.offset_u, yuv.length_u, 416 | * yuv.offset_v, yuv.length_v 417 | * ); 418 | * 419 | * y: 0 5059584 420 | * u: 5059584 1264896 421 | * v: 6324480 1264896 422 | */ 423 | OMXCAM_EXTERN void omxcam_yuv_planes ( 424 | uint32_t width, 425 | uint32_t height, 426 | omxcam_yuv_planes_t* planes); 427 | 428 | /* 429 | * Same as 'omxcam_yuv_planes()' but used to calculate the offset and length of 430 | * the planes of a payload buffer. 431 | */ 432 | OMXCAM_EXTERN void omxcam_yuv_planes_slice ( 433 | uint32_t width, 434 | omxcam_yuv_planes_t* planes); 435 | 436 | /* 437 | * Sets the default settings for the image capture. 438 | */ 439 | OMXCAM_EXTERN void omxcam_still_init (omxcam_still_settings_t* settings); 440 | 441 | /* 442 | * Starts the image capture with the given settings. 443 | */ 444 | OMXCAM_EXTERN int omxcam_still_start (omxcam_still_settings_t* settings); 445 | 446 | /* 447 | * Stops the image capture and unblocks the current thread. It is safe to use 448 | * from anywhere in your code. You can call it from inside the 'on_data' 449 | * callback or from another thread. 450 | */ 451 | OMXCAM_EXTERN int omxcam_still_stop (); 452 | 453 | /* 454 | * Sets the default settings for the video capture. 455 | */ 456 | OMXCAM_EXTERN void omxcam_video_init (omxcam_video_settings_t* settings); 457 | 458 | /* 459 | * Starts the video capture with the given settings. While the video is being 460 | * streamed, the current thread is blocked. If you want to sleep the thread 461 | * forever, use the macro OMXCAM_CAPTURE_FOREVER: 462 | * 463 | * omxcam_video_start(settings, OMXCAM_CAPTURE_FOREVER); 464 | */ 465 | OMXCAM_EXTERN int omxcam_video_start ( 466 | omxcam_video_settings_t* settings, 467 | uint32_t ms); 468 | 469 | /* 470 | * Stops the video capture and unblocks the current thread. It is safe to use 471 | * from anywhere in your code. You can call it from inside the 'on_data' 472 | * callback or from another thread. 473 | */ 474 | OMXCAM_EXTERN int omxcam_video_stop (); 475 | 476 | /* 477 | * Replaces the video buffer callback. Can be only executed when the camera is 478 | * running. 479 | */ 480 | OMXCAM_EXTERN int omxcam_video_update_on_data ( 481 | void (*on_data)(omxcam_buffer_t buffer)); 482 | 483 | /* 484 | * Updates the camera settings. Can be only executed while the camera is running 485 | * and it's in video mode. 486 | */ 487 | OMXCAM_EXTERN int omxcam_video_update_sharpness (int32_t sharpness); 488 | OMXCAM_EXTERN int omxcam_video_update_contrast (int32_t contrast); 489 | OMXCAM_EXTERN int omxcam_video_update_brightness (uint32_t brightness); 490 | OMXCAM_EXTERN int omxcam_video_update_saturation (int32_t saturation); 491 | OMXCAM_EXTERN int omxcam_video_update_iso (omxcam_iso iso); 492 | OMXCAM_EXTERN int omxcam_video_update_exposure (omxcam_exposure exposure); 493 | OMXCAM_EXTERN int omxcam_video_update_exposure_compensation ( 494 | int32_t exposure_compensation); 495 | OMXCAM_EXTERN int omxcam_video_update_mirror (omxcam_mirror mirror); 496 | OMXCAM_EXTERN int omxcam_video_update_rotation (omxcam_rotation rotation); 497 | OMXCAM_EXTERN int omxcam_video_update_color_effects ( 498 | omxcam_color_effects_t* color_effects); 499 | OMXCAM_EXTERN int omxcam_video_update_metering (omxcam_metering metering); 500 | OMXCAM_EXTERN int omxcam_video_update_white_balance ( 501 | omxcam_white_balance_t* white_balance); 502 | OMXCAM_EXTERN int omxcam_video_update_image_filter ( 503 | omxcam_image_filter image_filter); 504 | OMXCAM_EXTERN int omxcam_video_update_roi (omxcam_roi_t* roi); 505 | OMXCAM_EXTERN int omxcam_video_update_frame_stabilisation ( 506 | omxcam_bool frame_stabilisation); 507 | 508 | /* 509 | * Starts the video capture in "no pthread" mode. After this call the video 510 | * data is ready to be read. 511 | */ 512 | OMXCAM_EXTERN int omxcam_video_start_npt (omxcam_video_settings_t* settings); 513 | 514 | /* 515 | * Stops the video capture in "no pthread" mode. 516 | */ 517 | OMXCAM_EXTERN int omxcam_video_stop_npt (); 518 | 519 | /* 520 | * Fills a buffer with video data. This is a blocking function, that is, the 521 | * current thread is blocked until the buffer is filled. If an error occurs, the 522 | * video is stopped automatically. 523 | * 524 | * The "no pthread" functions don't have any multithread synchronization 525 | * mechanism, just the minimum required synchronization for communicating with 526 | * OpenMAX IL. 527 | * 528 | * They are useful when the client needs to request the buffers instead of 529 | * providing a callback to the camera to be called in a future, "give me data 530 | * and I'll wait for it" instead of "I give you a callback and I'll be doing 531 | * other things". The "no pthread" functions are useful when some kind of 532 | * inter-thread communication is required, otherwise, with the second approach 533 | * some kind of lock-free or blocking queue would be required (consumer-producer 534 | * problem). If the camera needs to be controlled by an asynchronous framework, 535 | * e.g.: libuv, these functions are very useful. 536 | */ 537 | int omxcam_video_read_npt ( 538 | omxcam_buffer_t* buffer, 539 | omxcam_bool* is_motion_vector); 540 | 541 | #ifdef __cplusplus 542 | } 543 | #endif 544 | 545 | #endif -------------------------------------------------------------------------------- /include/omxcam_version.h: -------------------------------------------------------------------------------- 1 | #ifndef OMXCAM_VERSION_H 2 | #define OMXCAM_VERSION_H 3 | 4 | #define OMXCAM_VERSION_MAJOR 0 5 | #define OMXCAM_VERSION_MINOR 0 6 | #define OMXCAM_VERSION_PATCH 0 7 | 8 | #endif -------------------------------------------------------------------------------- /src/camera.c: -------------------------------------------------------------------------------- 1 | #include "omxcam.h" 2 | #include "internal.h" 3 | 4 | int omxcam__camera_load_drivers (uint32_t camera_id){ 5 | /* 6 | This is a specific behaviour of the Broadcom's Raspberry Pi OpenMAX IL 7 | implementation module because the OMX_SetConfig() and OMX_SetParameter() are 8 | blocking functions but the drivers are loaded asynchronously, that is, an 9 | event is fired to signal the completion. Basically, what you're saying is: 10 | 11 | "When the parameter with index OMX_IndexParamCameraDeviceNumber is set, load 12 | the camera drivers and emit an OMX_EventParamOrConfigChanged event" 13 | 14 | The red led of the camera will be turned on after this call. 15 | */ 16 | 17 | omxcam__trace ("loading '%s' drivers", omxcam__ctx.camera.name); 18 | 19 | OMX_ERRORTYPE error; 20 | 21 | OMX_CONFIG_REQUESTCALLBACKTYPE req_st; 22 | omxcam__omx_struct_init (req_st); 23 | req_st.nPortIndex = OMX_ALL; 24 | req_st.nIndex = OMX_IndexParamCameraDeviceNumber; 25 | req_st.bEnable = OMX_TRUE; 26 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 27 | OMX_IndexConfigRequestCallback, &req_st))){ 28 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigRequestCallback: %s", 29 | omxcam__dump_OMX_ERRORTYPE (error)); 30 | return -1; 31 | } 32 | 33 | OMX_PARAM_U32TYPE dev_st; 34 | omxcam__omx_struct_init (dev_st); 35 | dev_st.nPortIndex = OMX_ALL; 36 | dev_st.nU32 = camera_id; 37 | if ((error = OMX_SetParameter (omxcam__ctx.camera.handle, 38 | OMX_IndexParamCameraDeviceNumber, &dev_st))){ 39 | omxcam__error ("OMX_SetParameter - OMX_IndexParamCameraDeviceNumber: " 40 | "%s", omxcam__dump_OMX_ERRORTYPE (error)); 41 | return -1; 42 | } 43 | 44 | return omxcam__event_wait (&omxcam__ctx.camera, 45 | OMXCAM_EVENT_PARAM_OR_CONFIG_CHANGED, 0, 0); 46 | } 47 | 48 | int omxcam__camera_check (){ 49 | char buffer[32]; 50 | int mem_gpu = 0; 51 | int supported = 0; 52 | int detected = 0; 53 | 54 | if (!vc_gencmd (buffer, sizeof (buffer), "get_mem gpu")){ 55 | vc_gencmd_number_property (buffer, "gpu", &mem_gpu); 56 | } 57 | 58 | if (mem_gpu < OMXCAM_MIN_GPU_MEM){ 59 | omxcam__error ("memory configured for the gpu is smaller than the minimum " 60 | "required: current %d, minimum %d", mem_gpu, OMXCAM_MIN_GPU_MEM); 61 | return -1; 62 | } 63 | 64 | if (!vc_gencmd (buffer, sizeof (buffer), "get_camera")){ 65 | vc_gencmd_number_property (buffer, "supported", &supported); 66 | vc_gencmd_number_property (buffer, "detected", &detected); 67 | } 68 | 69 | if (!supported){ 70 | omxcam__error ("camera is not enabled in this build"); 71 | return -1; 72 | } 73 | 74 | if (!detected){ 75 | omxcam__error ("camera is not detected"); 76 | return -1; 77 | } 78 | 79 | return 0; 80 | } 81 | 82 | static int omxcam__config_capture_port (uint32_t port, OMX_BOOL set){ 83 | OMX_ERRORTYPE error; 84 | 85 | OMX_CONFIG_PORTBOOLEANTYPE port_st; 86 | omxcam__omx_struct_init (port_st); 87 | port_st.nPortIndex = port; 88 | port_st.bEnabled = set; 89 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 90 | OMX_IndexConfigPortCapturing, &port_st))){ 91 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigPortCapturing: %s", 92 | omxcam__dump_OMX_ERRORTYPE (error)); 93 | return -1; 94 | } 95 | 96 | return 0; 97 | } 98 | 99 | int omxcam__camera_capture_port_set (uint32_t port){ 100 | omxcam__trace ("setting '%s' capture port", omxcam__ctx.camera.name); 101 | return omxcam__config_capture_port (port, OMX_TRUE); 102 | } 103 | 104 | int omxcam__camera_capture_port_reset (uint32_t port){ 105 | omxcam__trace ("resetting '%s' capture port", omxcam__ctx.camera.name); 106 | return omxcam__config_capture_port (port, OMX_FALSE); 107 | } 108 | 109 | void omxcam__camera_init ( 110 | omxcam_camera_settings_t* settings, 111 | uint32_t width, 112 | uint32_t height){ 113 | settings->width = width; 114 | settings->height = height; 115 | settings->sharpness = 0; 116 | settings->contrast = 0; 117 | settings->brightness = 50; 118 | settings->saturation = 0; 119 | settings->shutter_speed = OMXCAM_SHUTTER_SPEED_AUTO; 120 | settings->iso = OMXCAM_ISO_AUTO; 121 | settings->exposure = OMXCAM_EXPOSURE_AUTO; 122 | settings->exposure_compensation = 0; 123 | settings->mirror = OMXCAM_MIRROR_NONE; 124 | settings->rotation = OMXCAM_ROTATION_NONE; 125 | settings->color_effects.enabled = OMXCAM_FALSE; 126 | settings->color_effects.u = 128; 127 | settings->color_effects.v = 128; 128 | settings->color_denoise = OMXCAM_TRUE; 129 | settings->metering = OMXCAM_METERING_AVERAGE; 130 | settings->white_balance.mode = OMXCAM_WHITE_BALANCE_AUTO; 131 | settings->white_balance.red_gain = 100; 132 | settings->white_balance.blue_gain = 100; 133 | settings->image_filter = OMXCAM_IMAGE_FILTER_NONE; 134 | settings->roi.top = 0; 135 | settings->roi.left = 0; 136 | settings->roi.width = 100; 137 | settings->roi.height = 100; 138 | settings->drc = OMXCAM_DRC_OFF; 139 | settings->framerate = 30; 140 | settings->frame_stabilisation = OMXCAM_FALSE; 141 | } 142 | 143 | int omxcam__camera_validate (omxcam_camera_settings_t* settings, int video){ 144 | if (!omxcam__camera_is_valid_width (settings->width, video)){ 145 | omxcam__error ("invalid 'camera.width' value"); 146 | return -1; 147 | } 148 | if (!omxcam__camera_is_valid_height (settings->height, video)){ 149 | omxcam__error ("invalid 'camera.height' value"); 150 | return -1; 151 | } 152 | if (settings->width < settings->height){ 153 | omxcam__error ("'camera.width' must be >= than 'camera.height'"); 154 | return -1; 155 | } 156 | if (!omxcam__camera_is_valid_sharpness (settings->sharpness)){ 157 | omxcam__error ("invalid 'camera.sharpness' value"); 158 | return -1; 159 | } 160 | if (!omxcam__camera_is_valid_contrast (settings->contrast)){ 161 | omxcam__error ("invalid 'camera.contrast' value"); 162 | return -1; 163 | } 164 | if (!omxcam__camera_is_valid_brightness (settings->brightness)){ 165 | omxcam__error ("invalid 'camera.brightness' value"); 166 | return -1; 167 | } 168 | if (!omxcam__camera_is_valid_saturation (settings->saturation)){ 169 | omxcam__error ("invalid 'camera.saturation' value"); 170 | return -1; 171 | } 172 | if (!omxcam__camera_is_valid_iso (settings->iso)){ 173 | omxcam__error ("invalid 'camera.iso' value"); 174 | return -1; 175 | } 176 | if (!omxcam__camera_is_valid_exposure (settings->exposure)){ 177 | omxcam__error ("invalid 'camera.exposure' value"); 178 | return -1; 179 | } 180 | if (!omxcam__camera_is_valid_exposure_compensation ( 181 | settings->exposure_compensation)){ 182 | omxcam__error ("invalid 'camera.exposure_compensation' value"); 183 | return -1; 184 | } 185 | if (!omxcam__camera_is_valid_mirror (settings->mirror)){ 186 | omxcam__error ("invalid 'camera.mirror' value"); 187 | return -1; 188 | } 189 | if (!omxcam__camera_is_valid_rotation (settings->rotation)){ 190 | omxcam__error ("invalid 'camera.rotation' value"); 191 | return -1; 192 | } 193 | if (settings->color_effects.enabled){ 194 | if (!omxcam__camera_is_valid_color_effects (settings->color_effects.u)){ 195 | omxcam__error ("invalid 'camera.color_effects.u' value"); 196 | return -1; 197 | } 198 | if (!omxcam__camera_is_valid_color_effects (settings->color_effects.v)){ 199 | omxcam__error ("invalid 'camera.color_effects.v' value"); 200 | return -1; 201 | } 202 | } 203 | if (!omxcam__camera_is_valid_metering (settings->metering)){ 204 | omxcam__error ("invalid 'camera.metering' value"); 205 | return -1; 206 | } 207 | if (!omxcam__camera_is_valid_white_balance (settings->white_balance.mode)){ 208 | omxcam__error ("invalid 'camera.white_balance.mode' value"); 209 | return -1; 210 | } 211 | if (!omxcam__camera_is_valid_image_filter (settings->image_filter)){ 212 | omxcam__error ("invalid 'camera.image_filter' value"); 213 | return -1; 214 | } 215 | if (!omxcam__camera_is_valid_drc (settings->drc)){ 216 | omxcam__error ("invalid 'camera.drc' value"); 217 | return -1; 218 | } 219 | if (!omxcam__camera_is_valid_roi (settings->roi.top)){ 220 | omxcam__error ("invalid 'camera.roi.top' value"); 221 | return -1; 222 | } 223 | if (!omxcam__camera_is_valid_roi (settings->roi.left)){ 224 | omxcam__error ("invalid 'camera.roi.left' value"); 225 | return -1; 226 | } 227 | if (!omxcam__camera_is_valid_roi (settings->roi.width)){ 228 | omxcam__error ("invalid 'camera.roi.width' value"); 229 | return -1; 230 | } 231 | if (!omxcam__camera_is_valid_roi (settings->roi.height)){ 232 | omxcam__error ("invalid 'camera.roi.height' value"); 233 | return -1; 234 | } 235 | if (video && !omxcam__camera_is_valid_framerate (settings->framerate)){ 236 | omxcam__error ("invalid 'camera.framerate' value"); 237 | return -1; 238 | } 239 | 240 | return 0; 241 | } 242 | 243 | int omxcam__camera_set_sharpness (int32_t sharpness){ 244 | OMX_ERRORTYPE error; 245 | OMX_CONFIG_SHARPNESSTYPE st; 246 | omxcam__omx_struct_init (st); 247 | st.nPortIndex = OMX_ALL; 248 | st.nSharpness = sharpness; 249 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 250 | OMX_IndexConfigCommonSharpness, &st))){ 251 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCommonSharpness: %s", 252 | omxcam__dump_OMX_ERRORTYPE (error)); 253 | return -1; 254 | } 255 | return 0; 256 | } 257 | 258 | int omxcam__camera_set_contrast (int32_t contrast){ 259 | OMX_ERRORTYPE error; 260 | OMX_CONFIG_CONTRASTTYPE st; 261 | omxcam__omx_struct_init (st); 262 | st.nPortIndex = OMX_ALL; 263 | st.nContrast = contrast; 264 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 265 | OMX_IndexConfigCommonContrast, &st))){ 266 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCommonContrast: %s", 267 | omxcam__dump_OMX_ERRORTYPE (error)); 268 | return -1; 269 | } 270 | return 0; 271 | } 272 | 273 | int omxcam__camera_set_brightness (uint32_t brightness){ 274 | OMX_ERRORTYPE error; 275 | OMX_CONFIG_BRIGHTNESSTYPE st; 276 | omxcam__omx_struct_init (st); 277 | st.nPortIndex = OMX_ALL; 278 | st.nBrightness = brightness; 279 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 280 | OMX_IndexConfigCommonBrightness, &st))){ 281 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCommonBrightness: %s", 282 | omxcam__dump_OMX_ERRORTYPE (error)); 283 | return -1; 284 | } 285 | return 0; 286 | } 287 | 288 | int omxcam__camera_set_saturation (int32_t saturation){ 289 | OMX_ERRORTYPE error; 290 | OMX_CONFIG_SATURATIONTYPE st; 291 | omxcam__omx_struct_init (st); 292 | st.nPortIndex = OMX_ALL; 293 | st.nSaturation = saturation; 294 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 295 | OMX_IndexConfigCommonSaturation, &st))){ 296 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCommonSaturation: %s", 297 | omxcam__dump_OMX_ERRORTYPE (error)); 298 | return -1; 299 | } 300 | return 0; 301 | } 302 | 303 | int omxcam__camera_set_iso (omxcam_iso iso){ 304 | OMX_ERRORTYPE error; 305 | OMX_CONFIG_EXPOSUREVALUETYPE st; 306 | omxcam__omx_struct_init (st); 307 | st.nPortIndex = OMX_ALL; 308 | if ((error = OMX_GetConfig (omxcam__ctx.camera.handle, 309 | OMX_IndexConfigCommonExposureValue, &st))){ 310 | omxcam__error ("OMX_GetConfig - OMX_IndexConfigCommonExposureValue: " 311 | "%s", omxcam__dump_OMX_ERRORTYPE (error)); 312 | return -1; 313 | } 314 | st.nSensitivity = iso; 315 | st.bAutoSensitivity = !iso; 316 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 317 | OMX_IndexConfigCommonExposureValue, &st))){ 318 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCommonExposureValue: " 319 | "%s", omxcam__dump_OMX_ERRORTYPE (error)); 320 | return -1; 321 | } 322 | return 0; 323 | } 324 | 325 | int omxcam__camera_set_exposure (omxcam_exposure exposure){ 326 | OMX_ERRORTYPE error; 327 | OMX_CONFIG_EXPOSURECONTROLTYPE st; 328 | omxcam__omx_struct_init (st); 329 | st.nPortIndex = OMX_ALL; 330 | st.eExposureControl = exposure; 331 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 332 | OMX_IndexConfigCommonExposure, &st))){ 333 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCommonExposure: %s", 334 | omxcam__dump_OMX_ERRORTYPE (error)); 335 | return -1; 336 | } 337 | return 0; 338 | } 339 | 340 | int omxcam__camera_set_exposure_compensation (int32_t exposure_compensation){ 341 | OMX_ERRORTYPE error; 342 | OMX_CONFIG_EXPOSUREVALUETYPE st; 343 | omxcam__omx_struct_init (st); 344 | st.nPortIndex = OMX_ALL; 345 | if ((error = OMX_GetConfig (omxcam__ctx.camera.handle, 346 | OMX_IndexConfigCommonExposureValue, &st))){ 347 | omxcam__error ("OMX_GetConfig - OMX_IndexConfigCommonExposureValue: " 348 | "%s", omxcam__dump_OMX_ERRORTYPE (error)); 349 | return -1; 350 | } 351 | st.xEVCompensation = (exposure_compensation << 16)/6; 352 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 353 | OMX_IndexConfigCommonExposureValue, &st))){ 354 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCommonExposureValue: " 355 | "%s", omxcam__dump_OMX_ERRORTYPE (error)); 356 | return -1; 357 | } 358 | return 0; 359 | } 360 | 361 | int omxcam__camera_set_mirror (omxcam_mirror mirror, int video){ 362 | OMX_ERRORTYPE error; 363 | OMX_CONFIG_MIRRORTYPE st; 364 | omxcam__omx_struct_init (st); 365 | st.nPortIndex = video ? 71 : 72; 366 | st.eMirror = mirror; 367 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 368 | OMX_IndexConfigCommonMirror, &st))){ 369 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCommonMirror: %s", 370 | omxcam__dump_OMX_ERRORTYPE (error)); 371 | return -1; 372 | } 373 | return 0; 374 | } 375 | 376 | int omxcam__camera_set_rotation (omxcam_rotation rotation, int video){ 377 | OMX_ERRORTYPE error; 378 | OMX_CONFIG_ROTATIONTYPE st; 379 | omxcam__omx_struct_init (st); 380 | st.nPortIndex = video ? 71 : 72; 381 | st.nRotation = rotation; 382 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 383 | OMX_IndexConfigCommonRotate, &st))){ 384 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCommonRotate: %s", 385 | omxcam__dump_OMX_ERRORTYPE (error)); 386 | return -1; 387 | } 388 | return 0; 389 | } 390 | 391 | int omxcam__camera_set_color_effects ( 392 | omxcam_color_effects_t* color_effects){ 393 | OMX_ERRORTYPE error; 394 | OMX_CONFIG_COLORENHANCEMENTTYPE st; 395 | omxcam__omx_struct_init (st); 396 | st.nPortIndex = OMX_ALL; 397 | st.bColorEnhancement = color_effects->enabled; 398 | st.nCustomizedU = color_effects->u; 399 | st.nCustomizedV = color_effects->v; 400 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 401 | OMX_IndexConfigCommonColorEnhancement, &st))){ 402 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCommonColorEnhancement: %s", 403 | omxcam__dump_OMX_ERRORTYPE (error)); 404 | return -1; 405 | } 406 | return 0; 407 | } 408 | 409 | int omxcam__camera_set_color_denoise (omxcam_bool color_denoise){ 410 | OMX_ERRORTYPE error; 411 | OMX_CONFIG_BOOLEANTYPE st; 412 | omxcam__omx_struct_init (st); 413 | st.bEnabled = !!color_denoise; 414 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 415 | OMX_IndexConfigStillColourDenoiseEnable, &st))){ 416 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigStillColourDenoiseEnable: " 417 | "%s", omxcam__dump_OMX_ERRORTYPE (error)); 418 | return -1; 419 | } 420 | return 0; 421 | } 422 | 423 | int omxcam__camera_set_metering (omxcam_metering metering){ 424 | OMX_ERRORTYPE error; 425 | OMX_CONFIG_EXPOSUREVALUETYPE st; 426 | omxcam__omx_struct_init (st); 427 | st.nPortIndex = OMX_ALL; 428 | if ((error = OMX_GetConfig (omxcam__ctx.camera.handle, 429 | OMX_IndexConfigCommonExposureValue, &st))){ 430 | omxcam__error ("OMX_GetConfig - OMX_IndexConfigCommonExposureValue: " 431 | "%s", omxcam__dump_OMX_ERRORTYPE (error)); 432 | return -1; 433 | } 434 | st.eMetering = metering; 435 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 436 | OMX_IndexConfigCommonExposureValue, &st))){ 437 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCommonExposureValue: " 438 | "%s", omxcam__dump_OMX_ERRORTYPE (error)); 439 | return -1; 440 | } 441 | return 0; 442 | } 443 | 444 | int omxcam__camera_set_white_balance (omxcam_white_balance_t* white_balance){ 445 | OMX_ERRORTYPE error; 446 | OMX_CONFIG_WHITEBALCONTROLTYPE st; 447 | omxcam__omx_struct_init (st); 448 | st.nPortIndex = OMX_ALL; 449 | st.eWhiteBalControl = white_balance->mode; 450 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 451 | OMX_IndexConfigCommonWhiteBalance, &st))){ 452 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCommonWhiteBalance: %s", 453 | omxcam__dump_OMX_ERRORTYPE (error)); 454 | return -1; 455 | } 456 | if (white_balance->mode == OMXCAM_WHITE_BALANCE_OFF){ 457 | OMX_CONFIG_CUSTOMAWBGAINSTYPE gain_st; 458 | omxcam__omx_struct_init (gain_st); 459 | gain_st.xGainR = (white_balance->red_gain << 16)/1000; 460 | gain_st.xGainB = (white_balance->blue_gain << 16)/1000; 461 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 462 | OMX_IndexConfigCustomAwbGains, &gain_st))){ 463 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCustomAwbGains: %s", 464 | omxcam__dump_OMX_ERRORTYPE (error)); 465 | return -1; 466 | } 467 | } 468 | return 0; 469 | } 470 | 471 | int omxcam__camera_set_image_filter (omxcam_image_filter image_filter){ 472 | OMX_ERRORTYPE error; 473 | OMX_CONFIG_IMAGEFILTERTYPE st; 474 | omxcam__omx_struct_init (st); 475 | st.nPortIndex = OMX_ALL; 476 | st.eImageFilter = image_filter; 477 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 478 | OMX_IndexConfigCommonImageFilter, &st))){ 479 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCommonImageFilter: %s", 480 | omxcam__dump_OMX_ERRORTYPE (error)); 481 | return -1; 482 | } 483 | return 0; 484 | } 485 | 486 | int omxcam__camera_set_roi (omxcam_roi_t* roi){ 487 | OMX_ERRORTYPE error; 488 | OMX_CONFIG_INPUTCROPTYPE st; 489 | omxcam__omx_struct_init (st); 490 | st.nPortIndex = OMX_ALL; 491 | st.xLeft = (roi->left << 16)/100; 492 | st.xTop = (roi->top << 16)/100; 493 | st.xWidth = (roi->width << 16)/100; 494 | st.xHeight = (roi->height << 16)/100; 495 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 496 | OMX_IndexConfigInputCropPercentages, &st))){ 497 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigInputCropPercentages: %s", 498 | omxcam__dump_OMX_ERRORTYPE (error)); 499 | return -1; 500 | } 501 | return 0; 502 | } 503 | 504 | int omxcam__camera_set_drc (omxcam_drc drc){ 505 | OMX_ERRORTYPE error; 506 | OMX_CONFIG_DYNAMICRANGEEXPANSIONTYPE st; 507 | omxcam__omx_struct_init (st); 508 | st.eMode = drc; 509 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 510 | OMX_IndexConfigDynamicRangeExpansion, &st))){ 511 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigDynamicRangeExpansion: " 512 | "%s", omxcam__dump_OMX_ERRORTYPE (error)); 513 | return -1; 514 | } 515 | return 0; 516 | } 517 | 518 | int omxcam__camera_set_frame_stabilisation (omxcam_bool frame_stabilisation){ 519 | OMX_ERRORTYPE error; 520 | OMX_CONFIG_FRAMESTABTYPE st; 521 | omxcam__omx_struct_init (st); 522 | st.nPortIndex = OMX_ALL; 523 | st.bStab = !!frame_stabilisation; 524 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 525 | OMX_IndexConfigCommonFrameStabilisation, &st))){ 526 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCommonFrameStabilisation: " 527 | "%s", omxcam__dump_OMX_ERRORTYPE (error)); 528 | return -1; 529 | } 530 | return 0; 531 | } 532 | 533 | int omxcam__camera_configure_omx ( 534 | omxcam_camera_settings_t* settings, 535 | int video){ 536 | omxcam__trace ("configuring '%s' settings", omxcam__ctx.camera.name); 537 | 538 | if (omxcam__camera_set_sharpness (settings->sharpness)) return -1; 539 | if (omxcam__camera_set_contrast (settings->contrast)) return -1; 540 | if (omxcam__camera_set_brightness (settings->brightness)) return -1; 541 | if (omxcam__camera_set_saturation (settings->saturation)) return -1; 542 | if (omxcam__camera_set_exposure (settings->exposure)) return -1; 543 | if (omxcam__camera_set_mirror (settings->mirror, video)) return -1; 544 | if (omxcam__camera_set_rotation (settings->rotation, video)) return -1; 545 | if (omxcam__camera_set_color_effects (&settings->color_effects)){ 546 | return -1; 547 | } 548 | if (!video && omxcam__camera_set_color_denoise (settings->color_denoise)){ 549 | return -1; 550 | } 551 | if (omxcam__camera_set_white_balance (&settings->white_balance)) return -1; 552 | if (omxcam__camera_set_image_filter (settings->image_filter)) return -1; 553 | if (omxcam__camera_set_roi (&settings->roi)) return -1; 554 | if (!video && omxcam__camera_set_drc (settings->drc)) return -1; 555 | if (video && omxcam__camera_set_frame_stabilisation ( 556 | settings->frame_stabilisation)){ 557 | return -1; 558 | } 559 | 560 | OMX_ERRORTYPE error; 561 | OMX_CONFIG_EXPOSUREVALUETYPE exposure_st; 562 | omxcam__omx_struct_init (exposure_st); 563 | exposure_st.nPortIndex = OMX_ALL; 564 | exposure_st.eMetering = settings->metering; 565 | exposure_st.xEVCompensation = (settings->exposure_compensation << 16)/6; 566 | //Despite the name says it's in milliseconds, it's in microseconds 567 | exposure_st.nShutterSpeedMsec = settings->shutter_speed; 568 | exposure_st.bAutoShutterSpeed = !settings->shutter_speed; 569 | exposure_st.nSensitivity = settings->iso; 570 | exposure_st.bAutoSensitivity = !settings->iso; 571 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 572 | OMX_IndexConfigCommonExposureValue, &exposure_st))){ 573 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCommonExposureValue: " 574 | "%s", omxcam__dump_OMX_ERRORTYPE (error)); 575 | return -1; 576 | } 577 | 578 | return 0; 579 | } 580 | 581 | int omxcam__camera_is_valid_width (uint32_t width, int video){ 582 | return width >= OMXCAM_MIN_WIDTH && 583 | width <= (video ? OMXCAM_VIDEO_MAX_WIDTH : OMXCAM_STILL_MAX_WIDTH); 584 | } 585 | 586 | int omxcam__camera_is_valid_height (uint32_t height, int video){ 587 | return height >= OMXCAM_MIN_HEIGHT && 588 | height <= (video ? OMXCAM_VIDEO_MAX_HEIGHT : OMXCAM_STILL_MAX_HEIGHT); 589 | } 590 | 591 | int omxcam__camera_is_valid_sharpness (int32_t sharpness){ 592 | return sharpness >= -100 && sharpness <= 100; 593 | } 594 | 595 | int omxcam__camera_is_valid_contrast (int32_t contrast){ 596 | return contrast >= -100 && contrast <= 100; 597 | } 598 | 599 | int omxcam__camera_is_valid_brightness (uint32_t brightness){ 600 | return brightness <= 100; 601 | } 602 | 603 | int omxcam__camera_is_valid_saturation (int32_t saturation){ 604 | return saturation >= -100 && saturation <= 100; 605 | } 606 | 607 | int omxcam__camera_is_valid_exposure_compensation ( 608 | int32_t exposure_compensation){ 609 | return exposure_compensation >= -24 && exposure_compensation <= 24; 610 | } 611 | 612 | int omxcam__camera_is_valid_color_effects (uint32_t color){ 613 | return color <= 255; 614 | } 615 | 616 | int omxcam__camera_is_valid_roi (uint32_t roi){ 617 | return roi <= 100; 618 | } 619 | 620 | int omxcam__camera_is_valid_framerate (uint32_t framerate){ 621 | //640x480 @90fps is the upper limit, but let the firmware deal with it 622 | return framerate >= 1; 623 | } 624 | 625 | #define OMXCAM_FN(X, DEF, fn, ret, name, name_upper_case) \ 626 | ret omxcam__camera_ ## fn ## _ ## name (omxcam_ ## name name){ \ 627 | switch (name){ \ 628 | OMXCAM_ ## name_upper_case ## _MAP (X) \ 629 | DEF (OMXCAM_ ## name_upper_case) \ 630 | } \ 631 | } 632 | 633 | #define OMXCAM_CREATE_FN(_, value) \ 634 | case value: return 1; 635 | #define OMXCAM_DEFAULT(_) \ 636 | default: return 0; 637 | 638 | OMXCAM_FN (OMXCAM_CREATE_FN, OMXCAM_DEFAULT, is_valid, int, iso, ISO) 639 | OMXCAM_FN (OMXCAM_CREATE_FN, OMXCAM_DEFAULT, is_valid, int, exposure, EXPOSURE) 640 | OMXCAM_FN (OMXCAM_CREATE_FN, OMXCAM_DEFAULT, is_valid, int, mirror, MIRROR) 641 | OMXCAM_FN (OMXCAM_CREATE_FN, OMXCAM_DEFAULT, is_valid, int, rotation, ROTATION) 642 | OMXCAM_FN (OMXCAM_CREATE_FN, OMXCAM_DEFAULT, is_valid, int, metering, METERING) 643 | OMXCAM_FN (OMXCAM_CREATE_FN, OMXCAM_DEFAULT, is_valid, int, white_balance, 644 | WHITE_BALANCE) 645 | OMXCAM_FN (OMXCAM_CREATE_FN, OMXCAM_DEFAULT, is_valid, int, image_filter, 646 | IMAGE_FILTER) 647 | OMXCAM_FN (OMXCAM_CREATE_FN, OMXCAM_DEFAULT, is_valid, int, drc, DRC) 648 | 649 | #undef OMXCAM_DEFAULT 650 | #undef OMXCAM_CREATE_FN 651 | 652 | #define OMXCAM_STR_FN(name, value) \ 653 | case value: return OMXCAM_STR(OMXCAM_ ## name); 654 | #define OMXCAM_DEFAULT(name_upper_case) \ 655 | default: return "unknown " #name_upper_case; 656 | 657 | OMXCAM_FN (OMXCAM_STR_FN, OMXCAM_DEFAULT, str, const char*, iso, ISO) 658 | OMXCAM_FN (OMXCAM_STR_FN, OMXCAM_DEFAULT, str, const char*, exposure, EXPOSURE) 659 | OMXCAM_FN (OMXCAM_STR_FN, OMXCAM_DEFAULT, str, const char*, mirror, MIRROR) 660 | OMXCAM_FN (OMXCAM_STR_FN, OMXCAM_DEFAULT, str, const char*, rotation, ROTATION) 661 | OMXCAM_FN (OMXCAM_STR_FN, OMXCAM_DEFAULT, str, const char*, metering, METERING) 662 | OMXCAM_FN (OMXCAM_STR_FN, OMXCAM_DEFAULT, str, const char*, white_balance, 663 | WHITE_BALANCE) 664 | OMXCAM_FN (OMXCAM_STR_FN, OMXCAM_DEFAULT, str, const char*, image_filter, 665 | IMAGE_FILTER) 666 | 667 | #undef OMXCAM_DEFAULT 668 | #undef OMXCAM_STR_FN 669 | 670 | #undef OMXCAM_FN -------------------------------------------------------------------------------- /src/core.c: -------------------------------------------------------------------------------- 1 | #include "omxcam.h" 2 | #include "internal.h" 3 | 4 | OMX_ERRORTYPE event_handler ( 5 | OMX_HANDLETYPE comp, 6 | OMX_PTR app_data, 7 | OMX_EVENTTYPE event, 8 | OMX_U32 data1, 9 | OMX_U32 data2, 10 | OMX_PTR event_data){ 11 | omxcam__component_t* component = (omxcam__component_t*)app_data; 12 | omxcam__event evt = -1; 13 | OMX_ERRORTYPE error = OMX_ErrorNone; 14 | 15 | switch (event){ 16 | case OMX_EventCmdComplete: 17 | switch (data1){ 18 | case OMX_CommandStateSet: 19 | omxcam__trace ("event: OMX_CommandStateSet, state: %s", 20 | omxcam__dump_OMX_STATETYPE (data2)); 21 | evt = OMXCAM_EVENT_STATE_SET; 22 | break; 23 | case OMX_CommandPortDisable: 24 | omxcam__trace ("event: OMX_CommandPortDisable, port: %d", data2); 25 | evt = OMXCAM_EVENT_PORT_DISABLE; 26 | break; 27 | case OMX_CommandPortEnable: 28 | omxcam__trace ("event: OMX_CommandPortEnable, port: %d", data2); 29 | evt = OMXCAM_EVENT_PORT_ENABLE; 30 | break; 31 | case OMX_CommandFlush: 32 | omxcam__trace ("event: OMX_CommandFlush, port: %d", data2); 33 | evt = OMXCAM_EVENT_FLUSH; 34 | break; 35 | case OMX_CommandMarkBuffer: 36 | omxcam__trace ("event: OMX_CommandMarkBuffer, port: %d", data2); 37 | evt = OMXCAM_EVENT_MARK_BUFFER; 38 | break; 39 | } 40 | break; 41 | case OMX_EventError: 42 | omxcam__trace ("event: %s", omxcam__dump_OMX_ERRORTYPE (data1)); 43 | omxcam__error ("OMX_EventError: %s", omxcam__dump_OMX_ERRORTYPE (data1)); 44 | evt = OMXCAM_EVENT_ERROR; 45 | error = data1; 46 | break; 47 | case OMX_EventMark: 48 | omxcam__trace ("event: OMX_EventMark"); 49 | evt = OMXCAM_EVENT_MARK; 50 | break; 51 | case OMX_EventPortSettingsChanged: 52 | omxcam__trace ("event: OMX_EventPortSettingsChanged, port: %d", data1); 53 | evt = OMXCAM_EVENT_PORT_SETTINGS_CHANGED; 54 | break; 55 | case OMX_EventParamOrConfigChanged: 56 | omxcam__trace ("event: OMX_EventParamOrConfigChanged, data1: %d, data2: " 57 | "%X", data1, data2); 58 | evt = OMXCAM_EVENT_PARAM_OR_CONFIG_CHANGED; 59 | break; 60 | case OMX_EventBufferFlag: 61 | omxcam__trace ("event: OMX_EventBufferFlag, port: %d", data1); 62 | evt = OMXCAM_EVENT_BUFFER_FLAG; 63 | break; 64 | case OMX_EventResourcesAcquired: 65 | omxcam__trace ("event: OMX_EventResourcesAcquired"); 66 | evt = OMXCAM_EVENT_RESOURCES_ACQUIRED; 67 | break; 68 | case OMX_EventDynamicResourcesAvailable: 69 | omxcam__trace ("event: OMX_EventDynamicResourcesAvailable"); 70 | evt = OMXCAM_EVENT_DYNAMIC_RESOURCES_AVAILABLE; 71 | break; 72 | default: 73 | //This should never execute, log and ignore 74 | omxcam__error ("event: unknown (%X)", event); 75 | return OMX_ErrorNone; 76 | } 77 | 78 | if (omxcam__event_wake (component, evt, error)){ 79 | omxcam__event_error (component); 80 | } 81 | 82 | return OMX_ErrorNone; 83 | } 84 | 85 | OMX_ERRORTYPE fill_buffer_done ( 86 | OMX_HANDLETYPE comp, 87 | OMX_PTR app_data, 88 | OMX_BUFFERHEADERTYPE* buffer){ 89 | omxcam__component_t* component = (omxcam__component_t*)app_data; 90 | 91 | omxcam__trace ("event: FillBufferDone"); 92 | if (omxcam__event_wake (component, OMXCAM_EVENT_FILL_BUFFER_DONE, 93 | OMX_ErrorNone)){ 94 | omxcam__event_error (component); 95 | } 96 | 97 | return OMX_ErrorNone; 98 | } 99 | 100 | int omxcam__component_port_enable ( 101 | omxcam__component_t* component, 102 | uint32_t port){ 103 | omxcam__trace ("enabling port %d ('%s')", port, component->name); 104 | 105 | OMX_ERRORTYPE error; 106 | 107 | if ((error = OMX_SendCommand (component->handle, OMX_CommandPortEnable, 108 | port, 0))){ 109 | omxcam__error ("OMX_SendCommand: %s", omxcam__dump_OMX_ERRORTYPE (error)); 110 | return -1; 111 | } 112 | 113 | return 0; 114 | } 115 | 116 | int omxcam__component_port_disable ( 117 | omxcam__component_t* component, 118 | uint32_t port){ 119 | omxcam__trace ("disabling port %d ('%s')", port, component->name); 120 | 121 | OMX_ERRORTYPE error; 122 | 123 | if ((error = OMX_SendCommand (component->handle, OMX_CommandPortDisable, 124 | port, 0))){ 125 | omxcam__error ("OMX_SendCommand: %s", omxcam__dump_OMX_ERRORTYPE (error)); 126 | return -1; 127 | } 128 | 129 | return 0; 130 | } 131 | 132 | int omxcam__component_init (omxcam__component_t* component){ 133 | omxcam__trace ("initializing component '%s'", component->name); 134 | 135 | OMX_ERRORTYPE error; 136 | 137 | if (omxcam__event_create (component)) return -1; 138 | 139 | OMX_CALLBACKTYPE callbacks; 140 | callbacks.EventHandler = event_handler; 141 | callbacks.FillBufferDone = fill_buffer_done; 142 | 143 | if ((error = OMX_GetHandle (&component->handle, component->name, component, 144 | &callbacks))){ 145 | omxcam__error ("OMX_GetHandle: %s", omxcam__dump_OMX_ERRORTYPE (error)); 146 | return -1; 147 | } 148 | 149 | //Disable all the ports 150 | OMX_INDEXTYPE component_types[] = { 151 | OMX_IndexParamAudioInit, 152 | OMX_IndexParamVideoInit, 153 | OMX_IndexParamImageInit, 154 | OMX_IndexParamOtherInit 155 | }; 156 | OMX_PORT_PARAM_TYPE ports_st; 157 | omxcam__omx_struct_init (ports_st); 158 | 159 | int i; 160 | for (i=0; i<4; i++){ 161 | if ((error = OMX_GetParameter (component->handle, component_types[i], 162 | &ports_st))){ 163 | omxcam__error ("OMX_GetParameter - %s: %s", 164 | omxcam__dump_OMX_ERRORTYPE (error), 165 | omxcam__dump_OMX_INDEXTYPE (component_types[i])); 166 | return -1; 167 | } 168 | 169 | OMX_U32 port; 170 | for (port=ports_st.nStartPortNumber; 171 | portname); 184 | 185 | OMX_ERRORTYPE error; 186 | 187 | if (omxcam__event_destroy (component)) return -1; 188 | 189 | if ((error = OMX_FreeHandle (component->handle))){ 190 | omxcam__error ("OMX_FreeHandle: %s", omxcam__dump_OMX_ERRORTYPE (error)); 191 | return -1; 192 | } 193 | 194 | return 0; 195 | } 196 | 197 | int omxcam__component_change_state ( 198 | omxcam__component_t* component, 199 | omxcam__state state){ 200 | omxcam__trace ("changing '%s' state to %s", component->name, 201 | omxcam__dump_OMX_STATETYPE (state)); 202 | 203 | OMX_ERRORTYPE error; 204 | 205 | if ((error = OMX_SendCommand (component->handle, OMX_CommandStateSet, state, 206 | 0))){ 207 | omxcam__error ("OMX_SendCommand: %s", omxcam__dump_OMX_ERRORTYPE (error)); 208 | return -1; 209 | } 210 | 211 | return 0; 212 | } 213 | 214 | int omxcam__buffer_alloc (omxcam__component_t* component, uint32_t port){ 215 | omxcam__trace ("allocating '%s' output buffer", component->name); 216 | 217 | OMX_ERRORTYPE error; 218 | 219 | OMX_PARAM_PORTDEFINITIONTYPE def_st; 220 | omxcam__omx_struct_init (def_st); 221 | def_st.nPortIndex = port; 222 | if ((error = OMX_GetParameter (component->handle, 223 | OMX_IndexParamPortDefinition, &def_st))){ 224 | omxcam__error ("OMX_GetParameter - OMX_IndexParamPortDefinition: %s", 225 | omxcam__dump_OMX_ERRORTYPE (error)); 226 | return -1; 227 | } 228 | 229 | if ((error = OMX_AllocateBuffer (component->handle, 230 | &omxcam__ctx.output_buffer, port, 0, def_st.nBufferSize))){ 231 | omxcam__error ("OMX_AllocateBuffer: %s", 232 | omxcam__dump_OMX_ERRORTYPE (error)); 233 | return -1; 234 | } 235 | 236 | return 0; 237 | } 238 | 239 | int omxcam__buffer_free (omxcam__component_t* component, uint32_t port){ 240 | omxcam__trace ("releasing '%s' output buffer", component->name); 241 | 242 | OMX_ERRORTYPE error; 243 | 244 | if ((error = OMX_FreeBuffer (component->handle, port, 245 | omxcam__ctx.output_buffer))){ 246 | omxcam__error ("OMX_FreeBuffer: %s", omxcam__dump_OMX_ERRORTYPE (error)); 247 | return -1; 248 | } 249 | 250 | return 0; 251 | } 252 | 253 | int omxcam__exit (int code){ 254 | omxcam__ctx.state.running = 0; 255 | omxcam__ctx.state.joined = 0; 256 | omxcam__ctx.state.stopping = 0; 257 | omxcam__ctx.state.ready = 0; 258 | omxcam__ctx.video = 0; 259 | return code; 260 | } 261 | 262 | int omxcam__exit_npt (int code){ 263 | omxcam__ctx.no_pthread = 0; 264 | omxcam__ctx.state.running = 0; 265 | omxcam__ctx.state.stopping = 0; 266 | omxcam__ctx.state.ready = 0; 267 | omxcam__ctx.video = 0; 268 | return code; 269 | } 270 | 271 | int omxcam__init (){ 272 | omxcam__ctx.camera.name = OMXCAM_CAMERA_NAME; 273 | omxcam__ctx.image_encode.name = OMXCAM_IMAGE_ENCODE_NAME; 274 | omxcam__ctx.video_encode.name = OMXCAM_VIDEO_ENCODE_NAME; 275 | omxcam__ctx.null_sink.name = OMXCAM_NULL_SINK_NAME; 276 | 277 | bcm_host_init (); 278 | 279 | if (omxcam__camera_check ()){ 280 | omxcam__set_last_error (OMXCAM_ERROR_CAMERA_MODULE); 281 | return -1; 282 | } 283 | 284 | OMX_ERRORTYPE error; 285 | 286 | if ((error = OMX_Init ())){ 287 | omxcam__error ("OMX_Init: %s", omxcam__dump_OMX_ERRORTYPE (error)); 288 | omxcam__set_last_error (OMXCAM_ERROR_INIT); 289 | return -1; 290 | } 291 | 292 | return 0; 293 | } 294 | 295 | int omxcam__deinit (){ 296 | OMX_ERRORTYPE error; 297 | 298 | if ((error = OMX_Deinit ())){ 299 | omxcam__error ("OMX_Deinit: %s", omxcam__dump_OMX_ERRORTYPE (error)); 300 | omxcam__set_last_error (OMXCAM_ERROR_DEINIT); 301 | return -1; 302 | } 303 | 304 | bcm_host_deinit (); 305 | 306 | return 0; 307 | } -------------------------------------------------------------------------------- /src/debug.c: -------------------------------------------------------------------------------- 1 | #include "omxcam.h" 2 | #include "internal.h" 3 | 4 | void omxcam__trace (const char* fmt, ...){ 5 | #ifdef OMXCAM_DEBUG 6 | char buffer[256]; 7 | va_list args; 8 | va_start (args, fmt); 9 | vsprintf (buffer, fmt, args); 10 | va_end (args); 11 | 12 | printf ("omxcam: %s\n", buffer); 13 | #endif 14 | } -------------------------------------------------------------------------------- /src/dump_omx.c: -------------------------------------------------------------------------------- 1 | #include "omxcam.h" 2 | #include "internal.h" 3 | 4 | #define OMXCAM_DUMP_CASE(x) case x: return #x; 5 | 6 | const char* omxcam__dump_OMX_COLOR_FORMATTYPE (OMX_COLOR_FORMATTYPE type){ 7 | switch (type){ 8 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatUnused) 9 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatMonochrome) 10 | OMXCAM_DUMP_CASE (OMX_COLOR_Format8bitRGB332) 11 | OMXCAM_DUMP_CASE (OMX_COLOR_Format12bitRGB444) 12 | OMXCAM_DUMP_CASE (OMX_COLOR_Format16bitARGB4444) 13 | OMXCAM_DUMP_CASE (OMX_COLOR_Format16bitARGB1555) 14 | OMXCAM_DUMP_CASE (OMX_COLOR_Format16bitRGB565) 15 | OMXCAM_DUMP_CASE (OMX_COLOR_Format16bitBGR565) 16 | OMXCAM_DUMP_CASE (OMX_COLOR_Format18bitRGB666) 17 | OMXCAM_DUMP_CASE (OMX_COLOR_Format18bitARGB1665) 18 | OMXCAM_DUMP_CASE (OMX_COLOR_Format19bitARGB1666) 19 | OMXCAM_DUMP_CASE (OMX_COLOR_Format24bitRGB888) 20 | OMXCAM_DUMP_CASE (OMX_COLOR_Format24bitBGR888) 21 | OMXCAM_DUMP_CASE (OMX_COLOR_Format24bitARGB1887) 22 | OMXCAM_DUMP_CASE (OMX_COLOR_Format25bitARGB1888) 23 | OMXCAM_DUMP_CASE (OMX_COLOR_Format32bitBGRA8888) 24 | OMXCAM_DUMP_CASE (OMX_COLOR_Format32bitARGB8888) 25 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatYUV411Planar) 26 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatYUV411PackedPlanar) 27 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatYUV420Planar) 28 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatYUV420PackedPlanar) 29 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatYUV420SemiPlanar) 30 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatYUV422Planar) 31 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatYUV422PackedPlanar) 32 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatYUV422SemiPlanar) 33 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatYCbYCr) 34 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatYCrYCb) 35 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatCbYCrY) 36 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatCrYCbY) 37 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatYUV444Interleaved) 38 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatRawBayer8bit) 39 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatRawBayer10bit) 40 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatRawBayer8bitcompressed) 41 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatL2) 42 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatL4) 43 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatL8) 44 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatL16) 45 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatL24) 46 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatL32) 47 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatYUV420PackedSemiPlanar) 48 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatYUV422PackedSemiPlanar) 49 | OMXCAM_DUMP_CASE (OMX_COLOR_Format18BitBGR666) 50 | OMXCAM_DUMP_CASE (OMX_COLOR_Format24BitARGB6666) 51 | OMXCAM_DUMP_CASE (OMX_COLOR_Format24BitABGR6666) 52 | OMXCAM_DUMP_CASE (OMX_COLOR_Format32bitABGR8888) 53 | OMXCAM_DUMP_CASE (OMX_COLOR_Format8bitPalette) 54 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatYUVUV128) 55 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatRawBayer12bit) 56 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatBRCMEGL) 57 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatBRCMOpaque) 58 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatYVU420PackedPlanar) 59 | OMXCAM_DUMP_CASE (OMX_COLOR_FormatYVU420PackedSemiPlanar) 60 | default: return "unknown OMX_COLOR_FORMATTYPE"; 61 | } 62 | } 63 | 64 | const char* omxcam__dump_OMX_OTHER_FORMATTYPE (OMX_OTHER_FORMATTYPE type){ 65 | switch (type){ 66 | OMXCAM_DUMP_CASE (OMX_OTHER_FormatTime); 67 | OMXCAM_DUMP_CASE (OMX_OTHER_FormatPower); 68 | OMXCAM_DUMP_CASE (OMX_OTHER_FormatStats); 69 | OMXCAM_DUMP_CASE (OMX_OTHER_FormatBinary); 70 | OMXCAM_DUMP_CASE (OMX_OTHER_FormatText); 71 | OMXCAM_DUMP_CASE (OMX_OTHER_FormatTextSKM2); 72 | OMXCAM_DUMP_CASE (OMX_OTHER_FormatText3GP5); 73 | default: return "unknown OMX_OTHER_FORMATTYPE"; 74 | } 75 | } 76 | 77 | const char* omxcam__dump_OMX_AUDIO_CODINGTYPE (OMX_AUDIO_CODINGTYPE type){ 78 | switch (type){ 79 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingUnused) 80 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingAutoDetect) 81 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingPCM) 82 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingADPCM) 83 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingAMR) 84 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingGSMFR) 85 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingGSMEFR) 86 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingGSMHR) 87 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingPDCFR) 88 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingPDCEFR) 89 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingPDCHR) 90 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingTDMAFR) 91 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingTDMAEFR) 92 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingQCELP8) 93 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingQCELP13) 94 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingEVRC) 95 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingSMV) 96 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingG711) 97 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingG723) 98 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingG726) 99 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingG729) 100 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingAAC) 101 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingMP3) 102 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingSBC) 103 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingVORBIS) 104 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingWMA) 105 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingRA) 106 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingMIDI) 107 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingFLAC) 108 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingDDP) 109 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingDTS) 110 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingWMAPRO) 111 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingATRAC3) 112 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingATRACX) 113 | OMXCAM_DUMP_CASE (OMX_AUDIO_CodingATRACAAL) 114 | default: return "unknown OMX_AUDIO_CODINGTYPE"; 115 | } 116 | } 117 | 118 | const char* omxcam__dump_OMX_VIDEO_CODINGTYPE (OMX_VIDEO_CODINGTYPE type){ 119 | switch (type){ 120 | OMXCAM_DUMP_CASE (OMX_VIDEO_CodingUnused) 121 | OMXCAM_DUMP_CASE (OMX_VIDEO_CodingAutoDetect) 122 | OMXCAM_DUMP_CASE (OMX_VIDEO_CodingMPEG2) 123 | OMXCAM_DUMP_CASE (OMX_VIDEO_CodingH263) 124 | OMXCAM_DUMP_CASE (OMX_VIDEO_CodingMPEG4) 125 | OMXCAM_DUMP_CASE (OMX_VIDEO_CodingWMV) 126 | OMXCAM_DUMP_CASE (OMX_VIDEO_CodingRV) 127 | OMXCAM_DUMP_CASE (OMX_VIDEO_CodingAVC) 128 | OMXCAM_DUMP_CASE (OMX_VIDEO_CodingMJPEG) 129 | OMXCAM_DUMP_CASE (OMX_VIDEO_CodingVP6) 130 | OMXCAM_DUMP_CASE (OMX_VIDEO_CodingVP7) 131 | OMXCAM_DUMP_CASE (OMX_VIDEO_CodingVP8) 132 | OMXCAM_DUMP_CASE (OMX_VIDEO_CodingYUV) 133 | OMXCAM_DUMP_CASE (OMX_VIDEO_CodingSorenson) 134 | OMXCAM_DUMP_CASE (OMX_VIDEO_CodingTheora) 135 | OMXCAM_DUMP_CASE (OMX_VIDEO_CodingMVC) 136 | default: return "unknown OMX_VIDEO_CODINGTYPE"; 137 | } 138 | } 139 | 140 | const char* omxcam__dump_OMX_IMAGE_CODINGTYPE (OMX_IMAGE_CODINGTYPE type){ 141 | switch (type){ 142 | OMXCAM_DUMP_CASE (OMX_IMAGE_CodingUnused) 143 | OMXCAM_DUMP_CASE (OMX_IMAGE_CodingAutoDetect) 144 | OMXCAM_DUMP_CASE (OMX_IMAGE_CodingJPEG) 145 | OMXCAM_DUMP_CASE (OMX_IMAGE_CodingJPEG2K) 146 | OMXCAM_DUMP_CASE (OMX_IMAGE_CodingEXIF) 147 | OMXCAM_DUMP_CASE (OMX_IMAGE_CodingTIFF) 148 | OMXCAM_DUMP_CASE (OMX_IMAGE_CodingGIF) 149 | OMXCAM_DUMP_CASE (OMX_IMAGE_CodingPNG) 150 | OMXCAM_DUMP_CASE (OMX_IMAGE_CodingLZW) 151 | OMXCAM_DUMP_CASE (OMX_IMAGE_CodingBMP) 152 | OMXCAM_DUMP_CASE (OMX_IMAGE_CodingTGA) 153 | OMXCAM_DUMP_CASE (OMX_IMAGE_CodingPPM) 154 | default: return "unknown OMX_IMAGE_CODINGTYPE"; 155 | } 156 | } 157 | 158 | const char* omxcam__dump_OMX_STATETYPE (OMX_STATETYPE type){ 159 | switch (type){ 160 | OMXCAM_DUMP_CASE (OMX_StateInvalid) 161 | OMXCAM_DUMP_CASE (OMX_StateLoaded) 162 | OMXCAM_DUMP_CASE (OMX_StateIdle) 163 | OMXCAM_DUMP_CASE (OMX_StateExecuting) 164 | OMXCAM_DUMP_CASE (OMX_StatePause) 165 | OMXCAM_DUMP_CASE (OMX_StateWaitForResources) 166 | default: return "unknown OMX_STATETYPE"; 167 | } 168 | } 169 | 170 | const char* omxcam__dump_OMX_ERRORTYPE (OMX_ERRORTYPE type){ 171 | switch (type){ 172 | OMXCAM_DUMP_CASE (OMX_ErrorNone) 173 | OMXCAM_DUMP_CASE (OMX_ErrorInsufficientResources) 174 | OMXCAM_DUMP_CASE (OMX_ErrorUndefined) 175 | OMXCAM_DUMP_CASE (OMX_ErrorInvalidComponentName) 176 | OMXCAM_DUMP_CASE (OMX_ErrorComponentNotFound) 177 | OMXCAM_DUMP_CASE (OMX_ErrorInvalidComponent) 178 | OMXCAM_DUMP_CASE (OMX_ErrorBadParameter) 179 | OMXCAM_DUMP_CASE (OMX_ErrorNotImplemented) 180 | OMXCAM_DUMP_CASE (OMX_ErrorUnderflow) 181 | OMXCAM_DUMP_CASE (OMX_ErrorOverflow) 182 | OMXCAM_DUMP_CASE (OMX_ErrorHardware) 183 | OMXCAM_DUMP_CASE (OMX_ErrorInvalidState) 184 | OMXCAM_DUMP_CASE (OMX_ErrorStreamCorrupt) 185 | OMXCAM_DUMP_CASE (OMX_ErrorPortsNotCompatible) 186 | OMXCAM_DUMP_CASE (OMX_ErrorResourcesLost) 187 | OMXCAM_DUMP_CASE (OMX_ErrorNoMore) 188 | OMXCAM_DUMP_CASE (OMX_ErrorVersionMismatch) 189 | OMXCAM_DUMP_CASE (OMX_ErrorNotReady) 190 | OMXCAM_DUMP_CASE (OMX_ErrorTimeout) 191 | OMXCAM_DUMP_CASE (OMX_ErrorSameState) 192 | OMXCAM_DUMP_CASE (OMX_ErrorResourcesPreempted) 193 | OMXCAM_DUMP_CASE (OMX_ErrorPortUnresponsiveDuringAllocation) 194 | OMXCAM_DUMP_CASE (OMX_ErrorPortUnresponsiveDuringDeallocation) 195 | OMXCAM_DUMP_CASE (OMX_ErrorPortUnresponsiveDuringStop) 196 | OMXCAM_DUMP_CASE (OMX_ErrorIncorrectStateTransition) 197 | OMXCAM_DUMP_CASE (OMX_ErrorIncorrectStateOperation) 198 | OMXCAM_DUMP_CASE (OMX_ErrorUnsupportedSetting) 199 | OMXCAM_DUMP_CASE (OMX_ErrorUnsupportedIndex) 200 | OMXCAM_DUMP_CASE (OMX_ErrorBadPortIndex) 201 | OMXCAM_DUMP_CASE (OMX_ErrorPortUnpopulated) 202 | OMXCAM_DUMP_CASE (OMX_ErrorComponentSuspended) 203 | OMXCAM_DUMP_CASE (OMX_ErrorDynamicResourcesUnavailable) 204 | OMXCAM_DUMP_CASE (OMX_ErrorMbErrorsInFrame) 205 | OMXCAM_DUMP_CASE (OMX_ErrorFormatNotDetected) 206 | OMXCAM_DUMP_CASE (OMX_ErrorContentPipeOpenFailed) 207 | OMXCAM_DUMP_CASE (OMX_ErrorContentPipeCreationFailed) 208 | OMXCAM_DUMP_CASE (OMX_ErrorSeperateTablesUsed) 209 | OMXCAM_DUMP_CASE (OMX_ErrorTunnelingUnsupported) 210 | OMXCAM_DUMP_CASE (OMX_ErrorDiskFull) 211 | OMXCAM_DUMP_CASE (OMX_ErrorMaxFileSize) 212 | OMXCAM_DUMP_CASE (OMX_ErrorDrmUnauthorised) 213 | OMXCAM_DUMP_CASE (OMX_ErrorDrmExpired) 214 | OMXCAM_DUMP_CASE (OMX_ErrorDrmGeneral) 215 | default: return "unknown OMX_ERRORTYPE"; 216 | } 217 | } 218 | 219 | const char* omxcam__dump_OMX_EVENTTYPE (OMX_EVENTTYPE type){ 220 | switch (type){ 221 | OMXCAM_DUMP_CASE (OMX_EventCmdComplete) 222 | OMXCAM_DUMP_CASE (OMX_EventError) 223 | OMXCAM_DUMP_CASE (OMX_EventMark) 224 | OMXCAM_DUMP_CASE (OMX_EventPortSettingsChanged) 225 | OMXCAM_DUMP_CASE (OMX_EventBufferFlag) 226 | OMXCAM_DUMP_CASE (OMX_EventResourcesAcquired) 227 | OMXCAM_DUMP_CASE (OMX_EventComponentResumed) 228 | OMXCAM_DUMP_CASE (OMX_EventDynamicResourcesAvailable) 229 | OMXCAM_DUMP_CASE (OMX_EventPortFormatDetected) 230 | OMXCAM_DUMP_CASE (OMX_EventParamOrConfigChanged) 231 | default: return "unkonwn OMX_EVENTTYPE"; 232 | } 233 | } 234 | 235 | const char* omxcam__dump_OMX_INDEXTYPE (OMX_INDEXTYPE type){ 236 | switch (type){ 237 | OMXCAM_DUMP_CASE (OMX_IndexParamAudioInit) 238 | OMXCAM_DUMP_CASE (OMX_IndexParamVideoInit) 239 | OMXCAM_DUMP_CASE (OMX_IndexParamImageInit) 240 | OMXCAM_DUMP_CASE (OMX_IndexParamOtherInit) 241 | default: return "other OMX_INDEXTYPE"; 242 | } 243 | } 244 | 245 | #undef OMXCAM_DUMP_CASE 246 | 247 | void omxcam__dump_OMX_PARAM_PORTDEFINITIONTYPE ( 248 | OMX_PARAM_PORTDEFINITIONTYPE* type){ 249 | char domain[512]; 250 | char domain_info[512]; 251 | 252 | switch (type->eDomain){ 253 | case OMX_PortDomainAudio: 254 | strcpy (domain, "OMX_PortDomainAudio"); 255 | sprintf (domain_info, 256 | " cMIMEType: %s\n" 257 | " bFlagErrorConcealment: %s\n" 258 | " eEncoding: %s\n", 259 | type->format.video.cMIMEType, 260 | omxcam__strbool (type->format.image.bFlagErrorConcealment), 261 | omxcam__dump_OMX_AUDIO_CODINGTYPE ( 262 | type->format.audio.eEncoding)); 263 | break; 264 | case OMX_PortDomainVideo: 265 | strcpy (domain, "OMX_PortDomainVideo"); 266 | sprintf (domain_info, 267 | " cMIMEType: %s\n" 268 | " nFrameWidth: %d\n" 269 | " nFrameHeight: %d\n" 270 | " nStride: %d\n" 271 | " nSliceHeight: %d\n" 272 | " nBitrate: %d\n" 273 | " xFramerate: %d\n" 274 | " bFlagErrorConcealment: %s\n" 275 | " eCompressionFormat: %s\n" 276 | " eColorFormat: %s\n" 277 | , type->format.video.cMIMEType, 278 | type->format.video.nFrameWidth, 279 | type->format.video.nFrameHeight, 280 | type->format.video.nStride, 281 | type->format.video.nSliceHeight, 282 | type->format.video.nBitrate, 283 | type->format.video.xFramerate, 284 | omxcam__strbool (type->format.image.bFlagErrorConcealment), 285 | omxcam__dump_OMX_VIDEO_CODINGTYPE ( 286 | type->format.video.eCompressionFormat), 287 | omxcam__dump_OMX_COLOR_FORMATTYPE ( 288 | type->format.video.eColorFormat)); 289 | break; 290 | case OMX_PortDomainImage: 291 | strcpy (domain, "OMX_PortDomainImage"); 292 | sprintf (domain_info, 293 | " cMIMEType: %s\n" 294 | " nFrameWidth: %d\n" 295 | " nFrameHeight: %d\n" 296 | " nStride: %d\n" 297 | " nSliceHeight: %d\n" 298 | " bFlagErrorConcealment: %s\n" 299 | " eCompressionFormat: %s\n" 300 | " eColorFormat: %s\n" 301 | , type->format.image.cMIMEType, 302 | type->format.image.nFrameWidth, 303 | type->format.image.nFrameHeight, 304 | type->format.image.nStride, 305 | type->format.image.nSliceHeight, 306 | omxcam__strbool (type->format.image.bFlagErrorConcealment), 307 | omxcam__dump_OMX_IMAGE_CODINGTYPE ( 308 | type->format.image.eCompressionFormat), 309 | omxcam__dump_OMX_COLOR_FORMATTYPE ( 310 | type->format.image.eColorFormat)); 311 | break; 312 | case OMX_PortDomainOther: 313 | strcpy (domain, "OMX_PortDomainOther"); 314 | sprintf (domain_info, 315 | " eFormat: %s\n", 316 | omxcam__dump_OMX_OTHER_FORMATTYPE ( 317 | type->format.other.eFormat)); 318 | break; 319 | default: 320 | strcpy (domain, "unknown"); 321 | strcpy (domain_info, " unknown"); 322 | break; 323 | } 324 | 325 | printf ( 326 | "nSize: %d\n" 327 | "nPortIndex: %d\n" 328 | "eDir: %s\n" 329 | "nBufferCountActual: %d\n" 330 | "nBufferCountMin: %d\n" 331 | "nBufferSize: %d\n" 332 | "bEnabled: %s\n" 333 | "bPopulated: %s\n" 334 | "eDomain: %s\n" 335 | " format:\n" 336 | "%s" 337 | "bBuffersContiguous: %s\n" 338 | "nBufferAlignment: %d\n", 339 | type->nSize, 340 | type->nPortIndex, 341 | type->eDir == OMX_DirInput ? "input" : "output", 342 | type->nBufferCountActual, 343 | type->nBufferCountMin, 344 | type->nBufferSize, 345 | omxcam__strbool (type->bEnabled), 346 | omxcam__strbool (type->bPopulated), 347 | domain, 348 | domain_info, 349 | omxcam__strbool (type->bBuffersContiguous), 350 | type->nBufferAlignment); 351 | } 352 | 353 | void omxcam__dump_OMX_IMAGE_PARAM_PORTFORMATTYPE ( 354 | OMX_IMAGE_PARAM_PORTFORMATTYPE* type){ 355 | printf ( 356 | "nSize: %d\n" 357 | "nPortIndex: %d\n" 358 | "nIndex: %d\n" 359 | "eCompressionFormat: %s\n" 360 | "eColorFormat: %s\n", 361 | type->nSize, 362 | type->nPortIndex, 363 | type->nIndex, 364 | omxcam__dump_OMX_IMAGE_CODINGTYPE (type->eCompressionFormat), 365 | omxcam__dump_OMX_COLOR_FORMATTYPE (type->eColorFormat)); 366 | } 367 | 368 | void omxcam__dump_OMX_BUFFERHEADERTYPE (OMX_BUFFERHEADERTYPE* type){ 369 | long long int timestamp = (long long int)type->nTimeStamp.nHighPart; 370 | timestamp = timestamp << 32; 371 | timestamp |= (long long int)type->nTimeStamp.nLowPart; 372 | 373 | printf ( 374 | "nSize: %d\n" 375 | "nAllocLen: %d\n" 376 | "nFilledLen: %d\n" 377 | "nOffset: %d\n" 378 | "hMarkTargetComponent: %s\n" 379 | "nTickCount: %d\n" 380 | "nTimeStamp: %lld\n" 381 | "nFlags: %X\n" 382 | "nOutputPortIndex: %d\n" 383 | "nInputPortIndex: %d\n", 384 | type->nSize, 385 | type->nAllocLen, 386 | type->nFilledLen, 387 | type->nOffset, 388 | type->hMarkTargetComponent ? "not null" : "null (no mark)", 389 | type->nTickCount, 390 | timestamp, 391 | type->nFlags, 392 | type->nOutputPortIndex, 393 | type->nInputPortIndex); 394 | } -------------------------------------------------------------------------------- /src/error.c: -------------------------------------------------------------------------------- 1 | #include "omxcam.h" 2 | #include "internal.h" 3 | 4 | static omxcam_errno last_error = OMXCAM_ERROR_NONE; 5 | 6 | void omxcam__error_ ( 7 | const char* fmt, 8 | const char* fn, 9 | const char* file, 10 | int line, 11 | ...){ 12 | char buffer[256]; 13 | va_list args; 14 | va_start (args, line); 15 | vsprintf (buffer, fmt, args); 16 | va_end (args); 17 | 18 | omxcam__trace ("error: %s (function: '%s', file: '%s', line: %d)", buffer, 19 | fn, file, line); 20 | } 21 | 22 | #define OMXCAM_NAME_FN(_, name, __) \ 23 | case OMXCAM_ ## name: return "OMXCAM_" #name; 24 | 25 | const char* omxcam_error_name (omxcam_errno error){ 26 | switch (error){ 27 | OMXCAM_ERRNO_MAP (OMXCAM_NAME_FN) 28 | default: return 0; 29 | } 30 | } 31 | 32 | #undef OMXCAM_NAME_FN 33 | 34 | #define OMXCAM_STRERROR_FN(_, name, msg) \ 35 | case OMXCAM_ ## name: return msg; 36 | 37 | const char* omxcam_strerror (omxcam_errno error){ 38 | switch (error){ 39 | OMXCAM_ERRNO_MAP (OMXCAM_STRERROR_FN) 40 | default: return "unknown omxcam error"; 41 | } 42 | } 43 | 44 | #undef OMXCAM_STRERROR_FN 45 | 46 | omxcam_errno omxcam_last_error (){ 47 | return last_error; 48 | } 49 | 50 | void omxcam__set_last_error (omxcam_errno error){ 51 | last_error = error; 52 | } 53 | 54 | void omxcam_perror (){ 55 | fprintf (stderr, "omxcam: %s: %s\n", omxcam_error_name (last_error), 56 | omxcam_strerror (last_error)); 57 | } -------------------------------------------------------------------------------- /src/event.c: -------------------------------------------------------------------------------- 1 | #include "omxcam.h" 2 | #include "internal.h" 3 | 4 | void omxcam__event_error (omxcam__component_t* component){ 5 | component->event.fn_error = -1; 6 | } 7 | 8 | int omxcam__event_create (omxcam__component_t* component){ 9 | if (pthread_mutex_init (&component->event.mutex, 0)){ 10 | omxcam__error ("pthread_mutex_init"); 11 | return -1; 12 | } 13 | 14 | if (pthread_cond_init (&component->event.cond, 0)){ 15 | omxcam__error ("pthread_cond_init"); 16 | return -1; 17 | } 18 | 19 | component->event.fn_error = component->event.flags = 0; 20 | 21 | return 0; 22 | } 23 | 24 | int omxcam__event_destroy (omxcam__component_t* component){ 25 | if (pthread_mutex_destroy (&component->event.mutex)){ 26 | omxcam__error ("pthread_mutex_destroy"); 27 | return -1; 28 | } 29 | 30 | if (pthread_cond_destroy (&component->event.cond)){ 31 | omxcam__error ("pthread_cond_destroy"); 32 | return -1; 33 | } 34 | 35 | return 0; 36 | } 37 | 38 | int omxcam__event_wake ( 39 | omxcam__component_t* component, 40 | omxcam__event event, 41 | OMX_ERRORTYPE omx_error){ 42 | if (pthread_mutex_lock (&component->event.mutex)){ 43 | omxcam__error ("pthread_mutex_lock"); 44 | return -1; 45 | } 46 | 47 | component->event.flags |= event; 48 | component->event.omx_error = omx_error; 49 | 50 | if (pthread_cond_signal (&component->event.cond)){ 51 | omxcam__error ("pthread_cond_signal"); 52 | return -1; 53 | } 54 | 55 | if (pthread_mutex_unlock (&component->event.mutex)){ 56 | omxcam__error ("pthread_mutex_unlock"); 57 | return -1; 58 | } 59 | 60 | return 0; 61 | } 62 | 63 | int omxcam__event_wait ( 64 | omxcam__component_t* component, 65 | omxcam__event events, 66 | omxcam__event* current_events, 67 | OMX_ERRORTYPE* omx_error){ 68 | //Wait for the events 69 | if (pthread_mutex_lock (&component->event.mutex)){ 70 | omxcam__error ("pthread_mutex_lock"); 71 | return -1; 72 | } 73 | 74 | if (!((events | OMXCAM_EVENT_ERROR) & component->event.flags)){ 75 | //Include the events to wait for 76 | component->event.flags |= events; 77 | 78 | if (pthread_cond_wait (&component->event.cond, &component->event.mutex)){ 79 | omxcam__error ("pthread_cond_wait"); 80 | return -1; 81 | } 82 | } 83 | 84 | uint32_t flags = component->event.flags; 85 | component->event.flags &= ~events; 86 | 87 | if (pthread_mutex_unlock (&component->event.mutex)){ 88 | omxcam__error ("pthread_mutex_unlock"); 89 | return -1; 90 | } 91 | 92 | if (current_events){ 93 | *current_events = flags; 94 | } 95 | 96 | if (flags & OMXCAM_EVENT_ERROR){ 97 | //omxcam__error() was called from the EventHandler 98 | if (omx_error){ 99 | *omx_error = component->event.omx_error; 100 | } 101 | return -1; 102 | } 103 | 104 | return component->event.fn_error; 105 | } -------------------------------------------------------------------------------- /src/h264.c: -------------------------------------------------------------------------------- 1 | #include "omxcam.h" 2 | #include "internal.h" 3 | 4 | void omxcam__h264_init (omxcam_h264_settings_t* settings){ 5 | //Decent bitrate for 1080p 6 | settings->bitrate = 17000000; 7 | //If the IDR period is set to off, only one IDR frame will be inserted at the 8 | //beginning of the stream 9 | settings->idr_period = OMXCAM_H264_IDR_PERIOD_OFF; 10 | settings->sei = OMXCAM_FALSE; 11 | settings->eede.enabled = OMXCAM_FALSE; 12 | settings->eede.loss_rate = 0; 13 | settings->qp.enabled = OMXCAM_FALSE; 14 | settings->qp.i = OMXCAM_H264_QP_OFF; 15 | settings->qp.p = OMXCAM_H264_QP_OFF; 16 | settings->profile = OMXCAM_H264_AVC_PROFILE_HIGH; 17 | settings->inline_headers = OMXCAM_FALSE; 18 | settings->inline_motion_vectors = OMXCAM_FALSE; 19 | } 20 | 21 | int omxcam__h264_validate (omxcam_h264_settings_t* settings){ 22 | if (!omxcam__h264_is_valid_bitrate (settings->bitrate)){ 23 | omxcam__error ("invalid 'h264.bitrate' value"); 24 | return -1; 25 | } 26 | if (!omxcam__h264_is_valid_eede_loss_rate (settings->eede.loss_rate)){ 27 | omxcam__error ("invalid 'h264.eede.loss_rate' value"); 28 | return -1; 29 | } 30 | if (!omxcam__h264_is_valid_quantization (settings->qp.i)){ 31 | omxcam__error ("invalid 'h264.eede.i' value"); 32 | return -1; 33 | } 34 | if (!omxcam__h264_is_valid_quantization (settings->qp.p)){ 35 | omxcam__error ("invalid 'h264.eede.p' value"); 36 | return -1; 37 | } 38 | if (!omxcam__h264_is_valid_avc_profile (settings->profile)){ 39 | omxcam__error ("invalid 'h264.profile' value"); 40 | return -1; 41 | } 42 | return 0; 43 | } 44 | 45 | int omxcam__h264_is_valid_bitrate (uint32_t bitrate){ 46 | return bitrate >= 1 && bitrate <= 25000000; 47 | } 48 | 49 | int omxcam__h264_is_valid_eede_loss_rate (uint32_t loss_rate){ 50 | return loss_rate <= 100; 51 | } 52 | 53 | int omxcam__h264_is_valid_quantization (uint32_t qp){ 54 | return qp <= 51; 55 | } 56 | 57 | int omxcam__h264_configure_omx (omxcam_h264_settings_t* settings){ 58 | omxcam__trace ("configuring '%s' settings", omxcam__ctx.video_encode.name); 59 | 60 | OMX_ERRORTYPE error; 61 | 62 | if (!settings->qp.enabled){ 63 | //Bitrate 64 | OMX_VIDEO_PARAM_BITRATETYPE bitrate_st; 65 | omxcam__omx_struct_init (bitrate_st); 66 | bitrate_st.eControlRate = OMX_Video_ControlRateVariable; 67 | bitrate_st.nTargetBitrate = settings->bitrate; 68 | bitrate_st.nPortIndex = 201; 69 | if ((error = OMX_SetParameter (omxcam__ctx.video_encode.handle, 70 | OMX_IndexParamVideoBitrate, &bitrate_st))){ 71 | omxcam__error ("OMX_SetParameter - OMX_IndexParamVideoBitrate: %s", 72 | omxcam__dump_OMX_ERRORTYPE (error)); 73 | return -1; 74 | } 75 | }else{ 76 | //Quantization parameters 77 | OMX_VIDEO_PARAM_QUANTIZATIONTYPE quantization_st; 78 | omxcam__omx_struct_init (quantization_st); 79 | quantization_st.nPortIndex = 201; 80 | //nQpB returns an error, it cannot be modified 81 | quantization_st.nQpI = settings->qp.i; 82 | quantization_st.nQpP = settings->qp.p; 83 | if ((error = OMX_SetParameter (omxcam__ctx.video_encode.handle, 84 | OMX_IndexParamVideoQuantization, &quantization_st))){ 85 | omxcam__error ("OMX_SetParameter - OMX_IndexParamVideoQuantization: %s", 86 | omxcam__dump_OMX_ERRORTYPE (error)); 87 | return -1; 88 | } 89 | } 90 | 91 | //Codec 92 | OMX_VIDEO_PARAM_PORTFORMATTYPE format_st; 93 | omxcam__omx_struct_init (format_st); 94 | format_st.nPortIndex = 201; 95 | //H.264/AVC 96 | format_st.eCompressionFormat = OMX_VIDEO_CodingAVC; 97 | if ((error = OMX_SetParameter (omxcam__ctx.video_encode.handle, 98 | OMX_IndexParamVideoPortFormat, &format_st))){ 99 | omxcam__error ("OMX_SetParameter - OMX_IndexParamVideoPortFormat: %s", 100 | omxcam__dump_OMX_ERRORTYPE (error)); 101 | return -1; 102 | } 103 | 104 | //IDR period 105 | OMX_VIDEO_CONFIG_AVCINTRAPERIOD idr_st; 106 | omxcam__omx_struct_init (idr_st); 107 | idr_st.nPortIndex = 201; 108 | if ((error = OMX_GetConfig (omxcam__ctx.video_encode.handle, 109 | OMX_IndexConfigVideoAVCIntraPeriod, &idr_st))){ 110 | omxcam__error ("OMX_GetConfig - OMX_IndexConfigVideoAVCIntraPeriod: %s", 111 | omxcam__dump_OMX_ERRORTYPE (error)); 112 | return -1; 113 | } 114 | idr_st.nIDRPeriod = settings->idr_period; 115 | if ((error = OMX_SetConfig (omxcam__ctx.video_encode.handle, 116 | OMX_IndexConfigVideoAVCIntraPeriod, &idr_st))){ 117 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigVideoAVCIntraPeriod: %s", 118 | omxcam__dump_OMX_ERRORTYPE (error)); 119 | return -1; 120 | } 121 | 122 | //SEI 123 | OMX_PARAM_BRCMVIDEOAVCSEIENABLETYPE sei_st; 124 | omxcam__omx_struct_init (sei_st); 125 | sei_st.nPortIndex = 201; 126 | sei_st.bEnable = !!settings->sei; 127 | if ((error = OMX_SetParameter (omxcam__ctx.video_encode.handle, 128 | OMX_IndexParamBrcmVideoAVCSEIEnable, &sei_st))){ 129 | omxcam__error ("OMX_SetParameter - OMX_IndexParamBrcmVideoAVCSEIEnable: %s", 130 | omxcam__dump_OMX_ERRORTYPE (error)); 131 | return -1; 132 | } 133 | 134 | //EEDE 135 | OMX_VIDEO_EEDE_ENABLE eede_st; 136 | omxcam__omx_struct_init (eede_st); 137 | eede_st.nPortIndex = 201; 138 | eede_st.enable = !!settings->eede.enabled; 139 | if ((error = OMX_SetParameter (omxcam__ctx.video_encode.handle, 140 | OMX_IndexParamBrcmEEDEEnable, &eede_st))){ 141 | omxcam__error ("OMX_SetParameter - OMX_IndexParamBrcmEEDEEnable: %s", 142 | omxcam__dump_OMX_ERRORTYPE (error)); 143 | return -1; 144 | } 145 | 146 | OMX_VIDEO_EEDE_LOSSRATE eede_loss_rate_st; 147 | omxcam__omx_struct_init (eede_loss_rate_st); 148 | eede_loss_rate_st.nPortIndex = 201; 149 | eede_loss_rate_st.loss_rate = settings->eede.loss_rate; 150 | if ((error = OMX_SetParameter (omxcam__ctx.video_encode.handle, 151 | OMX_IndexParamBrcmEEDELossRate, &eede_loss_rate_st))){ 152 | omxcam__error ("OMX_SetParameter - OMX_IndexParamBrcmEEDELossRate: %s", 153 | omxcam__dump_OMX_ERRORTYPE (error)); 154 | return -1; 155 | } 156 | 157 | //AVC Profile 158 | OMX_VIDEO_PARAM_AVCTYPE avc_profile_st; 159 | omxcam__omx_struct_init (avc_profile_st); 160 | avc_profile_st.nPortIndex = 201; 161 | if ((error = OMX_GetParameter (omxcam__ctx.video_encode.handle, 162 | OMX_IndexParamVideoAvc, &avc_profile_st))){ 163 | omxcam__error ("OMX_GetParameter - OMX_IndexParamVideoAvc: %s", 164 | omxcam__dump_OMX_ERRORTYPE (error)); 165 | return -1; 166 | } 167 | avc_profile_st.eProfile = settings->profile; 168 | if ((error = OMX_SetParameter (omxcam__ctx.video_encode.handle, 169 | OMX_IndexParamVideoAvc, &avc_profile_st))){ 170 | omxcam__error ("OMX_SetParameter - OMX_IndexParamVideoAvc: %s", 171 | omxcam__dump_OMX_ERRORTYPE (error)); 172 | return -1; 173 | } 174 | 175 | //Inline SPS/PPS 176 | OMX_CONFIG_PORTBOOLEANTYPE headers_st; 177 | omxcam__omx_struct_init (headers_st); 178 | headers_st.nPortIndex = 201; 179 | headers_st.bEnabled = !!settings->inline_headers; 180 | if ((error = OMX_SetParameter (omxcam__ctx.video_encode.handle, 181 | OMX_IndexParamBrcmVideoAVCInlineHeaderEnable, &headers_st))){ 182 | omxcam__error ("OMX_SetParameter - " 183 | "OMX_IndexParamBrcmVideoAVCInlineHeaderEnable: %s", 184 | omxcam__dump_OMX_ERRORTYPE (error)); 185 | return -1; 186 | } 187 | 188 | //Inline motion vectors 189 | OMX_CONFIG_PORTBOOLEANTYPE motion_st; 190 | omxcam__omx_struct_init (motion_st); 191 | motion_st.nPortIndex = 201; 192 | motion_st.bEnabled = !!settings->inline_motion_vectors; 193 | if ((error = OMX_SetParameter (omxcam__ctx.video_encode.handle, 194 | OMX_IndexParamBrcmVideoAVCInlineVectorsEnable, &motion_st))){ 195 | omxcam__error ("OMX_SetParameter - " 196 | "OMX_IndexParamBrcmVideoAVCInlineVectorsEnable: %s", 197 | omxcam__dump_OMX_ERRORTYPE (error)); 198 | return -1; 199 | } 200 | 201 | return 0; 202 | } 203 | 204 | #define OMXCAM_FN(X, name, name_upper_case) \ 205 | int omxcam__h264_is_valid_ ## name (omxcam_ ## name name){ \ 206 | switch (name){ \ 207 | OMXCAM_ ## name_upper_case ## _MAP (X) \ 208 | default: return 0; \ 209 | } \ 210 | } 211 | 212 | #define OMXCAM_CASE_FN(_, value) \ 213 | case value: return 1; 214 | 215 | OMXCAM_FN (OMXCAM_CASE_FN, avc_profile, H264_AVC_PROFILE) 216 | 217 | #undef OMXCAM_CASE_FN 218 | #undef OMXCAM_FN -------------------------------------------------------------------------------- /src/internal.h: -------------------------------------------------------------------------------- 1 | #ifndef OMXCAM_INTERNAL_H 2 | #define OMXCAM_INTERNAL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #define omxcam__omx_struct_init(x) \ 17 | memset (&(x), 0, sizeof (x)); \ 18 | (x).nSize = sizeof (x); \ 19 | (x).nVersion.nVersion = OMX_VERSION; \ 20 | (x).nVersion.s.nVersionMajor = OMX_VERSION_MAJOR; \ 21 | (x).nVersion.s.nVersionMinor = OMX_VERSION_MINOR; \ 22 | (x).nVersion.s.nRevision = OMX_VERSION_REVISION; \ 23 | (x).nVersion.s.nStep = OMX_VERSION_STEP; 24 | 25 | #define OMXCAM_CAMERA_NAME "OMX.broadcom.camera" 26 | #define OMXCAM_IMAGE_ENCODE_NAME "OMX.broadcom.image_encode" 27 | #define OMXCAM_VIDEO_ENCODE_NAME "OMX.broadcom.video_encode" 28 | #define OMXCAM_NULL_SINK_NAME "OMX.broadcom.null_sink" 29 | 30 | #define OMXCAM_MIN_GPU_MEM 128 //MB 31 | #define OMXCAM_VIDEO_MAX_WIDTH 1920 32 | #define OMXCAM_VIDEO_MAX_HEIGHT 1080 33 | #define OMXCAM_STILL_MAX_WIDTH 2592 34 | #define OMXCAM_STILL_MAX_HEIGHT 1944 35 | #define OMXCAM_MIN_WIDTH 16 36 | #define OMXCAM_MIN_HEIGHT 16 37 | 38 | #ifdef OMXCAM_DEBUG 39 | #define omxcam__error(message, ...) \ 40 | omxcam__error_(message, __func__, __FILE__, __LINE__, ## __VA_ARGS__) 41 | #else 42 | #define omxcam__error(message, ...) //Empty 43 | #endif 44 | 45 | #define OMXCAM_STR(x) #x 46 | #define OMXCAM_STR_VALUE(x) OMXCAM_STR(x) 47 | 48 | /* 49 | * Enumeration with a mapping between all the OpenMAX IL events and a unique 50 | * number. The id allows them to be bitwise-or'ed, e.g. 51 | * OMXCAM_EVENT_ERROR | OMXCAM_EVENT_PORT_ENABLE == 0x3 52 | */ 53 | typedef enum { 54 | OMXCAM_EVENT_ERROR = 0x1, 55 | OMXCAM_EVENT_PORT_ENABLE = 0x2, 56 | OMXCAM_EVENT_PORT_DISABLE = 0x4, 57 | OMXCAM_EVENT_STATE_SET = 0x8, 58 | OMXCAM_EVENT_FLUSH = 0x10, 59 | OMXCAM_EVENT_MARK_BUFFER = 0x20, 60 | OMXCAM_EVENT_MARK = 0x40, 61 | OMXCAM_EVENT_PORT_SETTINGS_CHANGED = 0x80, 62 | OMXCAM_EVENT_PARAM_OR_CONFIG_CHANGED = 0x100, 63 | OMXCAM_EVENT_BUFFER_FLAG = 0x200, 64 | OMXCAM_EVENT_RESOURCES_ACQUIRED = 0x400, 65 | OMXCAM_EVENT_DYNAMIC_RESOURCES_AVAILABLE = 0x800, 66 | OMXCAM_EVENT_FILL_BUFFER_DONE = 0x1000 67 | } omxcam__event; 68 | 69 | typedef enum { 70 | OMXCAM_STATE_LOADED = OMX_StateLoaded, 71 | OMXCAM_STATE_IDLE = OMX_StateIdle, 72 | OMXCAM_STATE_EXECUTING = OMX_StateExecuting, 73 | OMXCAM_STATE_PAUSE = OMX_StatePause, 74 | OMXCAM_STATE_WAIT_FOR_RESOURCES = OMX_StateWaitForResources, 75 | OMXCAM_STATE_INVALID = OMX_StateInvalid 76 | } omxcam__state; 77 | 78 | /* 79 | * Component's event flags. 80 | */ 81 | typedef struct { 82 | pthread_mutex_t mutex; 83 | pthread_cond_t cond; 84 | uint32_t flags; 85 | OMX_ERRORTYPE omx_error; 86 | int fn_error; 87 | } omxcam__event_t; 88 | 89 | /* 90 | * Wrapper for an OpenMAX IL component. 91 | */ 92 | typedef struct { 93 | OMX_HANDLETYPE handle; 94 | omxcam__event_t event; 95 | OMX_STRING name; 96 | } omxcam__component_t; 97 | 98 | /* 99 | * Program's global context. 100 | */ 101 | typedef struct { 102 | omxcam__component_t camera; 103 | omxcam__component_t image_encode; 104 | omxcam__component_t video_encode; 105 | omxcam__component_t null_sink; 106 | OMX_BUFFERHEADERTYPE* output_buffer; 107 | void (*on_stop)(); 108 | int video; 109 | int inline_motion_vectors; 110 | int no_pthread; 111 | int use_encoder; 112 | struct { 113 | int running; 114 | int joined; 115 | int stopping; 116 | int ready; 117 | } state; 118 | } omxcam__context_t; 119 | 120 | //Context's global variable 121 | omxcam__context_t omxcam__ctx; 122 | 123 | /* 124 | * Returns 'true' if OMXCAM_TRUE, 'false' if OMXCAM_FALSE. 125 | */ 126 | const char* omxcam__strbool (omxcam_bool value); 127 | 128 | /* 129 | * Prints an error message to the stdout along with the file, line and function 130 | * name from where this function is called. It is printed if the cflag 131 | * OMXCAM_DEBUG is enabled. Use the omxcam__error() macro instead. 132 | */ 133 | void omxcam__error_ ( 134 | const char* fmt, 135 | const char* fn, 136 | const char* file, 137 | int line, 138 | ...); 139 | 140 | /* 141 | * Sets the last error. 142 | */ 143 | void omxcam__set_last_error (omxcam_errno error); 144 | 145 | /* 146 | * OpenMAX IL event handlers. 147 | */ 148 | OMX_ERRORTYPE event_handler ( 149 | OMX_HANDLETYPE comp, 150 | OMX_PTR app_data, 151 | OMX_EVENTTYPE event, 152 | OMX_U32 data1, 153 | OMX_U32 data2, 154 | OMX_PTR event_data); 155 | OMX_ERRORTYPE fill_buffer_done ( 156 | OMX_HANDLETYPE comp, 157 | OMX_PTR app_data, 158 | OMX_BUFFERHEADERTYPE* buffer); 159 | 160 | /* 161 | * OpenMAX IL miscellaneous dump functions. 162 | */ 163 | const char* omxcam__dump_OMX_COLOR_FORMATTYPE (OMX_COLOR_FORMATTYPE type); 164 | const char* omxcam__dump_OMX_OTHER_FORMATTYPE (OMX_OTHER_FORMATTYPE type); 165 | const char* omxcam__dump_OMX_AUDIO_CODINGTYPE (OMX_AUDIO_CODINGTYPE type); 166 | const char* omxcam__dump_OMX_VIDEO_CODINGTYPE (OMX_VIDEO_CODINGTYPE type); 167 | const char* omxcam__dump_OMX_IMAGE_CODINGTYPE (OMX_IMAGE_CODINGTYPE type); 168 | const char* omxcam__dump_OMX_STATETYPE (OMX_STATETYPE type); 169 | const char* omxcam__dump_OMX_ERRORTYPE (OMX_ERRORTYPE type); 170 | const char* omxcam__dump_OMX_EVENTTYPE (OMX_EVENTTYPE type); 171 | const char* omxcam__dump_OMX_INDEXTYPE (OMX_INDEXTYPE type); 172 | void omxcam__dump_OMX_PARAM_PORTDEFINITIONTYPE ( 173 | OMX_PARAM_PORTDEFINITIONTYPE* type); 174 | void omxcam__dump_OMX_IMAGE_PARAM_PORTFORMATTYPE ( 175 | OMX_IMAGE_PARAM_PORTFORMATTYPE* type); 176 | void omxcam__dump_OMX_BUFFERHEADERTYPE (OMX_BUFFERHEADERTYPE* type); 177 | 178 | /* 179 | * Prints a debug message to the stdout. It is printed if the cflag OMXCAM_DEBUG 180 | * is enabled. 181 | */ 182 | void omxcam__trace (const char* fmt, ...); 183 | 184 | /* 185 | * Sets an error originated from the EventHandler. 186 | */ 187 | void omxcam__event_error (omxcam__component_t* component); 188 | 189 | /* 190 | * Creates the event flags handler for the component. 191 | */ 192 | int omxcam__event_create (omxcam__component_t* component); 193 | 194 | /* 195 | * Destroys the event flags handler for the component. 196 | */ 197 | int omxcam__event_destroy (omxcam__component_t* component); 198 | 199 | /* 200 | * Sets some events. 201 | * 202 | * Unlocks the current thread if there are events waiting to the given events. 203 | */ 204 | int omxcam__event_wake ( 205 | omxcam__component_t* component, 206 | omxcam__event event, 207 | OMX_ERRORTYPE omx_error); 208 | 209 | /* 210 | * Retrieve some events. 211 | * 212 | * Waits until the specified events have been set. For example, if 213 | * OMXCAM_EVENT_BUFFER_FLAG | OMXCAM_EVENT_MARK are passed, the thread will be 214 | * locked until it is woken up with the OMXCAM_EVENT_BUFFER_FLAG or 215 | * OMXCAM_EVENT_MARK events. When unlocked, the current events set are returned 216 | * in the 'current_events' pointer (null is allowed). 217 | * 218 | * OMXCAM_EVENT_ERROR is automatically handled. 219 | */ 220 | int omxcam__event_wait ( 221 | omxcam__component_t* component, 222 | omxcam__event events, 223 | omxcam__event* current_events, 224 | OMX_ERRORTYPE* omx_error); 225 | 226 | /* 227 | * Enables and disables the port of a component. 228 | */ 229 | int omxcam__component_port_enable ( 230 | omxcam__component_t* component, 231 | uint32_t port); 232 | int omxcam__component_port_disable ( 233 | omxcam__component_t* component, 234 | uint32_t port); 235 | 236 | /* 237 | * Performs cleanup tasks before exit. These tasks doesn't return any error. 238 | * The main usage is to call this function in the return of the function that 239 | * was called by the user. The return is always the 'code' parameter. 240 | * 241 | * For example: 242 | * 243 | * int omxcam_video_start(...){ 244 | * ... 245 | * return omxcam__exit (omxcam_video_stop ()); 246 | * } 247 | */ 248 | int omxcam__exit (int code); 249 | 250 | /* 251 | * Same as 'omxcam__exit()' but used with the 'no pthread' functions. 252 | */ 253 | int omxcam__exit_npt (int code); 254 | 255 | /* 256 | * Initializes a component. All its ports are enabled and the OpenMAX IL event 257 | * handlers are configured, plus other things. 258 | */ 259 | int omxcam__component_init (omxcam__component_t* component); 260 | 261 | /* 262 | * Deinitializes a component. All its ports are disabled, plus other things. 263 | */ 264 | int omxcam__component_deinit (omxcam__component_t* component); 265 | 266 | /* 267 | * Changes the state of a component. 268 | */ 269 | int omxcam__component_change_state ( 270 | omxcam__component_t* component, 271 | omxcam__state state); 272 | 273 | /* 274 | * Allocates and frees an OpenMAX buffer for the given port. 275 | */ 276 | int omxcam__buffer_alloc (omxcam__component_t* component, uint32_t port); 277 | int omxcam__buffer_free (omxcam__component_t* component, uint32_t port); 278 | 279 | /* 280 | * Initializes and deinitializes OpenMAX IL. They must be the first and last 281 | * api calls. 282 | */ 283 | int omxcam__init (); 284 | int omxcam__deinit (); 285 | 286 | /* 287 | * Loads the camera drivers. After this call the red led is turned on and the 288 | * OpenMAX IL layer is ready to be configured. 289 | */ 290 | int omxcam__camera_load_drivers (); 291 | 292 | /* 293 | * Checks if the camera is ready to be used. It checks the available gpu memory 294 | * and whether it is supported and detected. 295 | */ 296 | int omxcam__camera_check (); 297 | 298 | /* 299 | * The camera needs to know which output port is going to be used to consume the 300 | * data. The capture port must be enabled just before the buffers are going to 301 | * be consumed, that is, when the state of the camera and all the enabled 302 | * components are OMX_StateExecuting. 303 | * 304 | * video = 71 305 | * still = 72 306 | */ 307 | int omxcam__camera_capture_port_set (uint32_t port); 308 | int omxcam__camera_capture_port_reset (uint32_t port); 309 | 310 | /* 311 | * Sets the default settings for the camera. 312 | */ 313 | void omxcam__camera_init ( 314 | omxcam_camera_settings_t* settings, 315 | uint32_t width, 316 | uint32_t height); 317 | 318 | /* 319 | * Configures the OpenMAX IL camera component. 320 | */ 321 | int omxcam__camera_configure_omx ( 322 | omxcam_camera_settings_t* settings, 323 | int video); 324 | 325 | /* 326 | * Configures the camera settings. 327 | */ 328 | int omxcam__camera_set_sharpness (int32_t sharpness); 329 | int omxcam__camera_set_contrast (int32_t contrast); 330 | int omxcam__camera_set_brightness (uint32_t brightness); 331 | int omxcam__camera_set_saturation (int32_t saturation); 332 | int omxcam__camera_set_iso (omxcam_iso iso); 333 | int omxcam__camera_set_exposure (omxcam_exposure exposure); 334 | int omxcam__camera_set_exposure_compensation (int32_t exposure_compensation); 335 | int omxcam__camera_set_mirror (omxcam_mirror mirror, int video); 336 | int omxcam__camera_set_rotation (omxcam_rotation rotation, int video); 337 | int omxcam__camera_set_color_effects ( 338 | omxcam_color_effects_t* color_effects); 339 | int omxcam__camera_set_color_denoise (omxcam_bool color_denoise); 340 | int omxcam__camera_set_metering (omxcam_metering metering); 341 | int omxcam__camera_set_white_balance (omxcam_white_balance_t* white_balance); 342 | int omxcam__camera_set_image_filter (omxcam_image_filter image_filter); 343 | int omxcam__camera_set_roi (omxcam_roi_t* roi); 344 | int omxcam__camera_set_frame_stabilisation (omxcam_bool frame_stabilisation); 345 | 346 | /* 347 | * Validates the settings. 348 | */ 349 | int omxcam__still_validate (omxcam_still_settings_t* settings); 350 | int omxcam__video_validate (omxcam_video_settings_t* settings); 351 | int omxcam__camera_validate (omxcam_camera_settings_t* settings, int video); 352 | int omxcam__jpeg_validate (omxcam_jpeg_settings_t* settings); 353 | int omxcam__h264_validate (omxcam_h264_settings_t* settings); 354 | 355 | /* 356 | * Validates each camera setting. Returns 1 if it's valid, 0 otherwise. 357 | */ 358 | int omxcam__camera_is_valid_width (uint32_t width, int video); 359 | int omxcam__camera_is_valid_height (uint32_t height, int video); 360 | int omxcam__camera_is_valid_sharpness (int32_t sharpness); 361 | int omxcam__camera_is_valid_contrast (int32_t contrast); 362 | int omxcam__camera_is_valid_brightness (uint32_t brightness); 363 | int omxcam__camera_is_valid_saturation (int32_t saturation); 364 | int omxcam__camera_is_valid_iso (omxcam_iso iso); 365 | int omxcam__camera_is_valid_exposure (omxcam_exposure exposure); 366 | int omxcam__camera_is_valid_exposure_compensation ( 367 | int32_t exposure_compensation); 368 | int omxcam__camera_is_valid_mirror (omxcam_mirror mirror); 369 | int omxcam__camera_is_valid_rotation (omxcam_rotation rotation); 370 | int omxcam__camera_is_valid_color_effects (uint32_t color); 371 | int omxcam__camera_is_valid_metering (omxcam_metering metering); 372 | int omxcam__camera_is_valid_white_balance (omxcam_white_balance white_balance); 373 | int omxcam__camera_is_valid_image_filter (omxcam_image_filter image_filter); 374 | int omxcam__camera_is_valid_drc (omxcam_drc drc); 375 | int omxcam__camera_is_valid_roi (uint32_t roi); 376 | int omxcam__camera_is_valid_framerate (uint32_t framerate); 377 | 378 | /* 379 | * Returns the string name of the given camera setting. 380 | */ 381 | const char* omxcam__camera_str_iso (omxcam_iso iso); 382 | const char* omxcam__camera_str_exposure (omxcam_exposure exposure); 383 | const char* omxcam__camera_str_mirror (omxcam_mirror mirror); 384 | const char* omxcam__camera_str_rotation (omxcam_rotation rotation); 385 | const char* omxcam__camera_str_metering (omxcam_metering metering); 386 | const char* omxcam__camera_str_white_balance ( 387 | omxcam_white_balance white_balance); 388 | const char* omxcam__camera_str_image_filter (omxcam_image_filter image_filter); 389 | 390 | /* 391 | * Sets the default settings for the jpeg encoder. 392 | */ 393 | void omxcam__jpeg_init (omxcam_jpeg_settings_t* settings); 394 | 395 | /* 396 | * Adds an exif tag to the jpeg metadata. 397 | */ 398 | int omxcam__jpeg_add_tag (char* key, char* value); 399 | 400 | /* 401 | * Configures the OpenMAX IL image_encode component with the jpeg settings. 402 | */ 403 | int omxcam__jpeg_configure_omx (omxcam_jpeg_settings_t* settings); 404 | 405 | /* 406 | * Validates each jpeg setting. Returns 1 if it's valid, 0 otherwise. 407 | */ 408 | int omxcam__jpeg_is_valid_quality (uint32_t quality); 409 | int omxcam__jpeg_is_valid_thumbnail (uint32_t dimension); 410 | 411 | /* 412 | * Sets the default settings for the h264 encoder. 413 | */ 414 | void omxcam__h264_init (omxcam_h264_settings_t* settings); 415 | 416 | /* 417 | * Configures the OpenMAX IL video_encode component with the h264 settings. 418 | */ 419 | int omxcam__h264_configure_omx (omxcam_h264_settings_t* settings); 420 | 421 | /* 422 | * Returns the string name of the given h246 setting. 423 | */ 424 | const char* omxcam__h264_str_avc_profile (omxcam_avc_profile profile); 425 | 426 | /* 427 | * Validates each h264 setting. Returns 1 if it's valid, 0 otherwise. 428 | */ 429 | int omxcam__h264_is_valid_bitrate (uint32_t bitrate); 430 | int omxcam__h264_is_valid_eede_loss_rate (uint32_t loss_rate); 431 | int omxcam__h264_is_valid_quantization (uint32_t qp); 432 | int omxcam__h264_is_valid_avc_profile (omxcam_avc_profile profile); 433 | 434 | #endif -------------------------------------------------------------------------------- /src/jpeg.c: -------------------------------------------------------------------------------- 1 | #include "omxcam.h" 2 | #include "internal.h" 3 | 4 | void omxcam__jpeg_init (omxcam_jpeg_settings_t* settings){ 5 | settings->quality = 75; 6 | settings->exif.enabled = OMXCAM_TRUE; 7 | settings->exif.tags = 0; 8 | settings->exif.valid_tags = 0; 9 | settings->ijg = OMXCAM_FALSE; 10 | settings->thumbnail.enabled = OMXCAM_TRUE; 11 | settings->thumbnail.width = OMXCAM_JPEG_THUMBNAIL_WIDTH_AUTO; 12 | settings->thumbnail.height = OMXCAM_JPEG_THUMBNAIL_HEIGHT_AUTO; 13 | settings->thumbnail.preview = OMXCAM_FALSE; 14 | settings->raw_bayer = OMXCAM_FALSE; 15 | } 16 | 17 | int omxcam__jpeg_validate (omxcam_jpeg_settings_t* settings){ 18 | if (!omxcam__jpeg_is_valid_quality (settings->quality)){ 19 | omxcam__error ("invalid 'jpeg.quality' value"); 20 | return -1; 21 | } 22 | if (settings->thumbnail.enabled && !settings->thumbnail.preview){ 23 | if (!omxcam__jpeg_is_valid_thumbnail (settings->thumbnail.width)){ 24 | omxcam__error ("invalid 'jpeg.thumbnail.width' value"); 25 | return -1; 26 | } 27 | if (!omxcam__jpeg_is_valid_thumbnail (settings->thumbnail.height)){ 28 | omxcam__error ("invalid 'jpeg.thumbnail.height' value"); 29 | return -1; 30 | } 31 | } 32 | return 0; 33 | } 34 | 35 | int omxcam__jpeg_is_valid_quality (uint32_t quality){ 36 | return quality >= 1 && quality <= 100; 37 | } 38 | 39 | int omxcam__jpeg_is_valid_thumbnail (uint32_t dimension){ 40 | return dimension <= 1024; 41 | } 42 | 43 | int omxcam__jpeg_add_tag (char* key, char* value){ 44 | int key_length = strlen (key); 45 | int value_length = strlen (value); 46 | 47 | struct { 48 | //These two fields need to be together 49 | OMX_CONFIG_METADATAITEMTYPE metadata_st; 50 | char metadata_padding[value_length]; 51 | } item; 52 | 53 | omxcam__omx_struct_init (item.metadata_st); 54 | item.metadata_st.nSize = sizeof (item); 55 | item.metadata_st.eScopeMode = OMX_MetadataScopePortLevel; 56 | item.metadata_st.nScopeSpecifier = 341; 57 | item.metadata_st.eKeyCharset = OMX_MetadataCharsetASCII; 58 | item.metadata_st.nKeySizeUsed = key_length; 59 | memcpy (item.metadata_st.nKey, key, key_length); 60 | item.metadata_st.eValueCharset = OMX_MetadataCharsetASCII; 61 | item.metadata_st.nValueMaxSize = sizeof (item.metadata_padding); 62 | item.metadata_st.nValueSizeUsed = value_length; 63 | memcpy (item.metadata_st.nValue, value, value_length); 64 | 65 | OMX_ERRORTYPE error; 66 | 67 | if ((error = OMX_SetConfig (omxcam__ctx.image_encode.handle, 68 | OMX_IndexConfigMetadataItem, &item))){ 69 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigMetadataItem: %s", 70 | omxcam__dump_OMX_ERRORTYPE (error)); 71 | return -1; 72 | } 73 | 74 | return 0; 75 | } 76 | 77 | int omxcam__jpeg_configure_omx (omxcam_jpeg_settings_t* settings){ 78 | omxcam__trace ("configuring '%s' settings", omxcam__ctx.image_encode.name); 79 | 80 | OMX_ERRORTYPE error; 81 | 82 | //Quality 83 | OMX_IMAGE_PARAM_QFACTORTYPE quality_st; 84 | omxcam__omx_struct_init (quality_st); 85 | quality_st.nPortIndex = 341; 86 | quality_st.nQFactor = settings->quality; 87 | if ((error = OMX_SetParameter (omxcam__ctx.image_encode.handle, 88 | OMX_IndexParamQFactor, &quality_st))){ 89 | omxcam__error ("OMX_SetParameter - OMX_IndexParamQFactor: %s", 90 | omxcam__dump_OMX_ERRORTYPE (error)); 91 | return -1; 92 | } 93 | 94 | //Disable EXIF tags 95 | OMX_CONFIG_BOOLEANTYPE exif_st; 96 | omxcam__omx_struct_init (exif_st); 97 | exif_st.bEnabled = !settings->exif.enabled; 98 | if ((error = OMX_SetParameter (omxcam__ctx.image_encode.handle, 99 | OMX_IndexParamBrcmDisableEXIF, &exif_st))){ 100 | omxcam__error ("OMX_SetParameter - OMX_IndexParamBrcmDisableEXIF: %s", 101 | omxcam__dump_OMX_ERRORTYPE (error)); 102 | return -1; 103 | } 104 | 105 | //Bayer data 106 | if (settings->raw_bayer){ 107 | //The filename is not relevant 108 | char dummy[] = "dummy"; 109 | struct { 110 | //These two fields need to be together 111 | OMX_PARAM_CONTENTURITYPE uri_st; 112 | char padding[5]; 113 | } raw; 114 | omxcam__omx_struct_init (raw.uri_st); 115 | raw.uri_st.nSize = sizeof (raw); 116 | memcpy (raw.uri_st.contentURI, dummy, 5); 117 | if ((error = OMX_SetConfig (omxcam__ctx.camera.handle, 118 | OMX_IndexConfigCaptureRawImageURI, &raw))){ 119 | omxcam__error ("OMX_SetConfig - OMX_IndexConfigCaptureRawImageURI: %s", 120 | omxcam__dump_OMX_ERRORTYPE (error)); 121 | return -1; 122 | } 123 | } 124 | 125 | //Enable IJG table 126 | OMX_PARAM_IJGSCALINGTYPE ijg_st; 127 | omxcam__omx_struct_init (ijg_st); 128 | ijg_st.nPortIndex = 341; 129 | ijg_st.bEnabled = settings->ijg; 130 | if ((error = OMX_SetParameter (omxcam__ctx.image_encode.handle, 131 | OMX_IndexParamBrcmEnableIJGTableScaling, &ijg_st))){ 132 | omxcam__error ("OMX_SetParameter - OMX_IndexParamBrcmEnableIJGTableScaling: " 133 | "%s", omxcam__dump_OMX_ERRORTYPE (error)); 134 | return -1; 135 | } 136 | 137 | if (!settings->exif.enabled) return 0; 138 | 139 | //EXIF tags 140 | //See firmware/documentation/ilcomponents/image_decode.html for valid keys 141 | //See http://www.media.mit.edu/pia/Research/deepview/exif.html#IFD0Tags 142 | //for valid keys and their description 143 | char timestamp[20]; 144 | time_t now; 145 | struct tm ts; 146 | time (&now); 147 | ts = *localtime (&now); 148 | strftime (timestamp, sizeof (timestamp), "%Y:%m:%d %H:%M:%S", &ts); 149 | 150 | if (omxcam__jpeg_add_tag ("EXIF.DateTimeOriginal", timestamp)) return -1; 151 | if (omxcam__jpeg_add_tag ("EXIF.DateTimeDigitized", timestamp)) return -1; 152 | if (omxcam__jpeg_add_tag ("IFD0.DateTime", timestamp)) return -1; 153 | 154 | uint32_t i; 155 | for (i=0; iexif.valid_tags; i++){ 156 | if (omxcam__jpeg_add_tag (settings->exif.tags[i].key, 157 | settings->exif.tags[i].value)){ 158 | return -1; 159 | } 160 | } 161 | 162 | //Thumbnail 163 | OMX_PARAM_BRCMTHUMBNAILTYPE thumbnail_st; 164 | omxcam__omx_struct_init (thumbnail_st); 165 | thumbnail_st.bEnable = settings->thumbnail.enabled; 166 | thumbnail_st.bUsePreview = settings->thumbnail.preview; 167 | thumbnail_st.nWidth = settings->thumbnail.width; 168 | thumbnail_st.nHeight = settings->thumbnail.height; 169 | if ((error = OMX_SetParameter (omxcam__ctx.image_encode.handle, 170 | OMX_IndexParamBrcmThumbnail, &thumbnail_st))){ 171 | omxcam__error ("OMX_SetParameter - OMX_IndexParamBrcmThumbnail: %s", 172 | omxcam__dump_OMX_ERRORTYPE (error)); 173 | return -1; 174 | } 175 | 176 | return 0; 177 | } -------------------------------------------------------------------------------- /src/still.c: -------------------------------------------------------------------------------- 1 | #include "omxcam.h" 2 | #include "internal.h" 3 | 4 | static int omxcam__still_change_state (omxcam__state state, int use_encoder){ 5 | if (omxcam__component_change_state (&omxcam__ctx.camera, state)){ 6 | return -1; 7 | } 8 | OMX_ERRORTYPE error; 9 | if (omxcam__event_wait (&omxcam__ctx.camera, OMXCAM_EVENT_STATE_SET, 10 | 0, &error)){ 11 | printf("%X\n", error); 12 | if (error == OMX_ErrorInsufficientResources){ 13 | //It's most likely that the camera is already running by another IL 14 | //client. Very ugly but needs to be done this way in order to set the last 15 | //error 16 | return -2; 17 | } 18 | return -1; 19 | } 20 | 21 | if (omxcam__component_change_state (&omxcam__ctx.null_sink, state)){ 22 | return -1; 23 | } 24 | if (omxcam__event_wait (&omxcam__ctx.null_sink, OMXCAM_EVENT_STATE_SET, 0, 25 | 0)){ 26 | return -1; 27 | } 28 | 29 | if (!use_encoder) return 0; 30 | 31 | if (omxcam__component_change_state (&omxcam__ctx.image_encode, state)){ 32 | return -1; 33 | } 34 | if (omxcam__event_wait (&omxcam__ctx.image_encode, OMXCAM_EVENT_STATE_SET, 35 | 0, 0)){ 36 | return -1; 37 | } 38 | 39 | return 0; 40 | } 41 | 42 | void omxcam_still_init (omxcam_still_settings_t* settings){ 43 | omxcam__camera_init (&settings->camera, OMXCAM_STILL_MAX_WIDTH, 44 | OMXCAM_STILL_MAX_HEIGHT); 45 | settings->format = OMXCAM_FORMAT_JPEG; 46 | omxcam__jpeg_init (&settings->jpeg); 47 | settings->on_data = 0; 48 | } 49 | 50 | int omxcam__still_validate (omxcam_still_settings_t* settings){ 51 | if (omxcam__camera_validate (&settings->camera, 0)) return -1; 52 | if (omxcam__jpeg_validate (&settings->jpeg)) return -1; 53 | return 0; 54 | } 55 | 56 | int omxcam_still_start (omxcam_still_settings_t* settings){ 57 | omxcam__trace ("starting still capture"); 58 | 59 | omxcam__set_last_error (OMXCAM_ERROR_NONE); 60 | 61 | if (omxcam__ctx.state.running){ 62 | omxcam__error ("camera is already running"); 63 | omxcam__set_last_error (OMXCAM_ERROR_CAMERA_RUNNING); 64 | return -1; 65 | } 66 | 67 | if (omxcam__still_validate (settings)){ 68 | omxcam__set_last_error (OMXCAM_ERROR_BAD_PARAMETER); 69 | return -1; 70 | } 71 | 72 | if (omxcam__init ()) return -1; 73 | 74 | int use_encoder; 75 | OMX_COLOR_FORMATTYPE color_format; 76 | omxcam__component_t* fill_component; 77 | OMX_ERRORTYPE error; 78 | 79 | OMX_U32 width_rounded = omxcam_round (settings->camera.width, 32); 80 | OMX_U32 height_rounded = omxcam_round (settings->camera.height, 16); 81 | OMX_U32 width = width_rounded; 82 | OMX_U32 height = height_rounded; 83 | OMX_U32 stride = width_rounded; 84 | 85 | //Stride is byte-per-pixel*width 86 | //See mmal/util/mmal_util.c, mmal_encoding_width_to_stride() 87 | 88 | switch (settings->format){ 89 | case OMXCAM_FORMAT_RGB888: 90 | use_encoder = 0; 91 | color_format = OMX_COLOR_Format24bitRGB888; 92 | stride = stride*3; 93 | fill_component = &omxcam__ctx.camera; 94 | break; 95 | case OMXCAM_FORMAT_RGBA8888: 96 | use_encoder = 0; 97 | color_format = OMX_COLOR_Format32bitABGR8888; 98 | stride = stride*4; 99 | fill_component = &omxcam__ctx.camera; 100 | break; 101 | case OMXCAM_FORMAT_YUV420: 102 | use_encoder = 0; 103 | color_format = OMX_COLOR_FormatYUV420PackedPlanar; 104 | fill_component = &omxcam__ctx.camera; 105 | break; 106 | case OMXCAM_FORMAT_JPEG: 107 | use_encoder = 1; 108 | color_format = OMX_COLOR_FormatYUV420PackedPlanar; 109 | width = settings->camera.width; 110 | height = settings->camera.height; 111 | fill_component = &omxcam__ctx.image_encode; 112 | break; 113 | default: 114 | omxcam__set_last_error (OMXCAM_ERROR_FORMAT); 115 | return -1; 116 | } 117 | 118 | omxcam__trace ("%dx%d", settings->camera.width, settings->camera.height); 119 | 120 | if (omxcam__component_init (&omxcam__ctx.camera)){ 121 | omxcam__set_last_error (OMXCAM_ERROR_INIT_CAMERA); 122 | return -1; 123 | } 124 | if (omxcam__component_init (&omxcam__ctx.null_sink)){ 125 | omxcam__set_last_error (OMXCAM_ERROR_INIT_NULL_SINK); 126 | return -1; 127 | } 128 | if (use_encoder && omxcam__component_init (&omxcam__ctx.image_encode)){ 129 | omxcam__set_last_error (OMXCAM_ERROR_INIT_IMAGE_ENCODER); 130 | return -1; 131 | } 132 | 133 | if (omxcam__camera_load_drivers ()){ 134 | omxcam__set_last_error (OMXCAM_ERROR_DRIVERS); 135 | return -1; 136 | } 137 | 138 | //Configure camera sensor 139 | omxcam__trace ("configuring '%s' sensor", omxcam__ctx.camera.name); 140 | 141 | OMX_PARAM_SENSORMODETYPE sensor_st; 142 | omxcam__omx_struct_init (sensor_st); 143 | sensor_st.nPortIndex = OMX_ALL; 144 | omxcam__omx_struct_init (sensor_st.sFrameSize); 145 | sensor_st.sFrameSize.nPortIndex = OMX_ALL; 146 | if ((error = OMX_GetParameter (omxcam__ctx.camera.handle, 147 | OMX_IndexParamCommonSensorMode, &sensor_st))){ 148 | omxcam__error ("OMX_GetParameter - OMX_IndexParamCommonSensorMode: %s", 149 | omxcam__dump_OMX_ERRORTYPE (error)); 150 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 151 | return -1; 152 | } 153 | sensor_st.bOneShot = OMX_TRUE; 154 | //sensor.sFrameSize.nWidth and sensor.sFrameSize.nHeight can be ignored, 155 | //they are configured with the port definition 156 | if ((error = OMX_SetParameter (omxcam__ctx.camera.handle, 157 | OMX_IndexParamCommonSensorMode, &sensor_st))){ 158 | omxcam__error ("OMX_SetParameter - OMX_IndexParamCommonSensorMode: %s", 159 | omxcam__dump_OMX_ERRORTYPE (error)); 160 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 161 | return -1; 162 | } 163 | 164 | //Configure camera port definition 165 | omxcam__trace ("configuring '%s' port definition", omxcam__ctx.camera.name); 166 | 167 | OMX_PARAM_PORTDEFINITIONTYPE port_st; 168 | omxcam__omx_struct_init (port_st); 169 | port_st.nPortIndex = 72; 170 | if ((error = OMX_GetParameter (omxcam__ctx.camera.handle, 171 | OMX_IndexParamPortDefinition, &port_st))){ 172 | omxcam__error ("OMX_GetParameter - OMX_IndexParamPortDefinition: %s", 173 | omxcam__dump_OMX_ERRORTYPE (error)); 174 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 175 | return -1; 176 | } 177 | 178 | port_st.format.image.nFrameWidth = width; 179 | port_st.format.image.nFrameHeight = height; 180 | port_st.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused; 181 | port_st.format.image.eColorFormat = color_format; 182 | port_st.format.image.nStride = stride; 183 | if ((error = OMX_SetParameter (omxcam__ctx.camera.handle, 184 | OMX_IndexParamPortDefinition, &port_st))){ 185 | omxcam__error ("OMX_SetParameter - OMX_IndexParamPortDefinition: %s", 186 | omxcam__dump_OMX_ERRORTYPE (error)); 187 | omxcam__set_last_error (error == OMX_ErrorBadParameter 188 | ? OMXCAM_ERROR_BAD_PARAMETER 189 | : OMXCAM_ERROR_STILL); 190 | return -1; 191 | } 192 | 193 | //Configure preview port 194 | //In theory the fastest resolution and framerate are 1920x1080 @30fps because 195 | //these are the default settings for the preview port, so the frames don't 196 | //need to be resized. In practice, this is not true. The fastest way to 197 | //produce stills is setting the lowest resolution, that is, 640x480 @30fps. 198 | //The difference between 1920x1080 @30fps and 640x480 @30fps is a speed boost 199 | //of ~4%, from ~1083ms to ~1039ms 200 | port_st.nPortIndex = 70; 201 | port_st.format.video.nFrameWidth = 640; 202 | port_st.format.video.nFrameHeight = 480; 203 | port_st.format.video.eCompressionFormat = OMX_IMAGE_CodingUnused; 204 | port_st.format.video.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar; 205 | //Setting the framerate to 0 unblocks the shutter speed from 66ms to 772ms 206 | //The higher the speed, the higher the capture time 207 | port_st.format.video.xFramerate = 0; 208 | port_st.format.video.nStride = 640; 209 | if ((error = OMX_SetParameter (omxcam__ctx.camera.handle, 210 | OMX_IndexParamPortDefinition, &port_st))){ 211 | omxcam__error ("OMX_SetParameter - OMX_IndexParamPortDefinition: %s", 212 | omxcam__dump_OMX_ERRORTYPE (error)); 213 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 214 | return -1; 215 | } 216 | 217 | //Configure camera settings 218 | if (omxcam__camera_configure_omx (&settings->camera, 0)){ 219 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 220 | return -1; 221 | } 222 | 223 | if (use_encoder){ 224 | omxcam__trace ("configuring '%s' port definition", 225 | omxcam__ctx.image_encode.name); 226 | 227 | omxcam__omx_struct_init (port_st); 228 | port_st.nPortIndex = 341; 229 | if ((error = OMX_GetParameter (omxcam__ctx.image_encode.handle, 230 | OMX_IndexParamPortDefinition, &port_st))){ 231 | omxcam__error ("OMX_GetParameter - OMX_IndexParamPortDefinition: %s", 232 | omxcam__dump_OMX_ERRORTYPE (error)); 233 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 234 | return -1; 235 | } 236 | port_st.format.image.nFrameWidth = settings->camera.width; 237 | port_st.format.image.nFrameHeight = settings->camera.height; 238 | port_st.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG; 239 | port_st.format.image.eColorFormat = OMX_COLOR_FormatUnused; 240 | port_st.format.image.nStride = stride; 241 | if ((error = OMX_SetParameter (omxcam__ctx.image_encode.handle, 242 | OMX_IndexParamPortDefinition, &port_st))){ 243 | omxcam__error ("OMX_SetParameter - OMX_IndexParamPortDefinition: %s", 244 | omxcam__dump_OMX_ERRORTYPE (error)); 245 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 246 | return -1; 247 | } 248 | 249 | //Configure JPEG settings 250 | if (omxcam__jpeg_configure_omx (&settings->jpeg)){ 251 | omxcam__set_last_error (OMXCAM_ERROR_JPEG); 252 | return -1; 253 | } 254 | 255 | //Setup tunnel: camera (still) -> image_encode 256 | omxcam__trace ("configuring tunnel '%s' -> '%s'", omxcam__ctx.camera.name, 257 | omxcam__ctx.image_encode.name); 258 | 259 | if ((error = OMX_SetupTunnel (omxcam__ctx.camera.handle, 72, 260 | omxcam__ctx.image_encode.handle, 340))){ 261 | omxcam__error ("OMX_SetupTunnel: %s", omxcam__dump_OMX_ERRORTYPE (error)); 262 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 263 | return -1; 264 | } 265 | } 266 | 267 | //Setup tunnel: camera (preview) -> null_sink 268 | omxcam__trace ("configuring tunnel '%s' -> '%s'", omxcam__ctx.camera.name, 269 | omxcam__ctx.null_sink.name); 270 | 271 | if ((error = OMX_SetupTunnel (omxcam__ctx.camera.handle, 70, 272 | omxcam__ctx.null_sink.handle, 240))){ 273 | omxcam__error ("OMX_SetupTunnel: %s", omxcam__dump_OMX_ERRORTYPE (error)); 274 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 275 | return -1; 276 | } 277 | 278 | //Change to Idle 279 | int r; 280 | if ((r = omxcam__still_change_state (OMXCAM_STATE_IDLE, use_encoder))){ 281 | //If r == -2, the camera is already running by another IL client. Very ugly 282 | //but needs to be done this way in order to set the last error 283 | if (r == -1){ 284 | omxcam__set_last_error (OMXCAM_ERROR_IDLE); 285 | }else{ 286 | omxcam__set_last_error (OMXCAM_ERROR_CAMERA_RUNNING); 287 | } 288 | return -1; 289 | } 290 | 291 | //Enable the ports 292 | if (omxcam__component_port_enable (&omxcam__ctx.camera, 72)){ 293 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 294 | return -1; 295 | } 296 | if (!use_encoder && omxcam__buffer_alloc (&omxcam__ctx.camera, 72)){ 297 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 298 | return -1; 299 | } 300 | if (omxcam__event_wait (&omxcam__ctx.camera, OMXCAM_EVENT_PORT_ENABLE, 0, 0)){ 301 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 302 | return -1; 303 | } 304 | if (omxcam__component_port_enable (&omxcam__ctx.camera, 70)){ 305 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 306 | return -1; 307 | } 308 | if (omxcam__event_wait (&omxcam__ctx.camera, OMXCAM_EVENT_PORT_ENABLE, 0, 0)){ 309 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 310 | return -1; 311 | } 312 | if (omxcam__component_port_enable (&omxcam__ctx.null_sink, 240)){ 313 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 314 | return -1; 315 | } 316 | if (omxcam__event_wait (&omxcam__ctx.null_sink, OMXCAM_EVENT_PORT_ENABLE, 0, 317 | 0)){ 318 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 319 | return -1; 320 | } 321 | 322 | if (use_encoder){ 323 | if (omxcam__component_port_enable (&omxcam__ctx.image_encode, 340)){ 324 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 325 | return -1; 326 | } 327 | if (omxcam__event_wait (&omxcam__ctx.image_encode, OMXCAM_EVENT_PORT_ENABLE, 328 | 0, 0)){ 329 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 330 | return -1; 331 | } 332 | if (omxcam__component_port_enable (&omxcam__ctx.image_encode, 341)){ 333 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 334 | return -1; 335 | } 336 | if (omxcam__buffer_alloc (&omxcam__ctx.image_encode, 341)){ 337 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 338 | return -1; 339 | } 340 | if (omxcam__event_wait (&omxcam__ctx.image_encode, OMXCAM_EVENT_PORT_ENABLE, 341 | 0, 0)){ 342 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 343 | return -1; 344 | } 345 | } 346 | 347 | //Change to Executing 348 | if (omxcam__still_change_state (OMXCAM_STATE_EXECUTING, use_encoder)){ 349 | omxcam__set_last_error (OMXCAM_ERROR_EXECUTING); 350 | return -1; 351 | } 352 | 353 | //Set camera capture port 354 | if (omxcam__camera_capture_port_set (72)){ 355 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 356 | return -1; 357 | } 358 | 359 | //Start consuming the buffers 360 | uint32_t end_events = 361 | OMXCAM_EVENT_BUFFER_FLAG | OMXCAM_EVENT_FILL_BUFFER_DONE; 362 | uint32_t current_events; 363 | 364 | while (1){ 365 | //Get the buffer data (a slice of the image) 366 | if ((error = OMX_FillThisBuffer (fill_component->handle, 367 | omxcam__ctx.output_buffer))){ 368 | omxcam__error ("OMX_FillThisBuffer: %s", 369 | omxcam__dump_OMX_ERRORTYPE (error)); 370 | omxcam__set_last_error (OMXCAM_ERROR_CAPTURE); 371 | return -1; 372 | } 373 | 374 | //Wait until it's filled 375 | if (omxcam__event_wait (fill_component, OMXCAM_EVENT_FILL_BUFFER_DONE, 376 | ¤t_events, 0)){ 377 | omxcam__set_last_error (OMXCAM_ERROR_CAPTURE); 378 | return -1; 379 | } 380 | 381 | //Emit the buffer 382 | if (omxcam__ctx.output_buffer->nFilledLen){ 383 | omxcam_buffer_t buffer; 384 | buffer.data = omxcam__ctx.output_buffer->pBuffer; 385 | buffer.length = omxcam__ctx.output_buffer->nFilledLen; 386 | settings->on_data (buffer); 387 | } 388 | 389 | //When it's the end of the stream, an OMX_EventBufferFlag is emitted in all 390 | //the components in use. Then the FillBufferDone function is called in the 391 | //last component in the component's chain 392 | if (current_events == end_events){ 393 | //Clear the EOS flags 394 | if (omxcam__event_wait (&omxcam__ctx.camera, OMXCAM_EVENT_BUFFER_FLAG, 395 | 0, 0)){ 396 | omxcam__set_last_error (OMXCAM_ERROR_CAPTURE); 397 | return -1; 398 | } 399 | if (use_encoder && 400 | omxcam__event_wait (&omxcam__ctx.image_encode, 401 | OMXCAM_EVENT_BUFFER_FLAG, 0, 0)){ 402 | omxcam__set_last_error (OMXCAM_ERROR_CAPTURE); 403 | return -1; 404 | } 405 | break; 406 | } 407 | } 408 | 409 | //Reset camera capture port 410 | if (omxcam__camera_capture_port_reset (72)){ 411 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 412 | return -1; 413 | } 414 | 415 | //Change to Idle 416 | if (omxcam__still_change_state (OMXCAM_STATE_IDLE, use_encoder)){ 417 | omxcam__set_last_error (OMXCAM_ERROR_IDLE); 418 | return -1; 419 | } 420 | 421 | //Disable the ports 422 | if (omxcam__component_port_disable (&omxcam__ctx.camera, 72)){ 423 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 424 | return -1; 425 | } 426 | if (!use_encoder && omxcam__buffer_free (&omxcam__ctx.camera, 72)){ 427 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 428 | return -1; 429 | } 430 | if (omxcam__event_wait (&omxcam__ctx.camera, OMXCAM_EVENT_PORT_DISABLE, 0, 431 | 0)){ 432 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 433 | return -1; 434 | } 435 | if (omxcam__component_port_disable (&omxcam__ctx.camera, 70)){ 436 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 437 | return -1; 438 | } 439 | if (omxcam__event_wait (&omxcam__ctx.camera, OMXCAM_EVENT_PORT_DISABLE, 0, 440 | 0)){ 441 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 442 | return -1; 443 | } 444 | if (omxcam__component_port_disable (&omxcam__ctx.null_sink, 240)){ 445 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 446 | return -1; 447 | } 448 | if (omxcam__event_wait (&omxcam__ctx.null_sink, OMXCAM_EVENT_PORT_DISABLE, 449 | 0, 0)){ 450 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 451 | return -1; 452 | } 453 | 454 | if (use_encoder){ 455 | if (omxcam__component_port_disable (&omxcam__ctx.image_encode, 340)){ 456 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 457 | return -1; 458 | } 459 | if (omxcam__event_wait (&omxcam__ctx.image_encode, 460 | OMXCAM_EVENT_PORT_DISABLE, 0, 0)){ 461 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 462 | return -1; 463 | } 464 | if (omxcam__component_port_disable (&omxcam__ctx.image_encode, 341)){ 465 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 466 | return -1; 467 | } 468 | if (omxcam__buffer_free (&omxcam__ctx.image_encode, 341)){ 469 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 470 | return -1; 471 | } 472 | if (omxcam__event_wait (&omxcam__ctx.image_encode, 473 | OMXCAM_EVENT_PORT_DISABLE, 0, 0)){ 474 | omxcam__set_last_error (OMXCAM_ERROR_STILL); 475 | return -1; 476 | } 477 | } 478 | 479 | //Change to Loaded 480 | if (omxcam__still_change_state (OMXCAM_STATE_LOADED, use_encoder)){ 481 | omxcam__set_last_error (OMXCAM_ERROR_LOADED); 482 | return -1; 483 | } 484 | 485 | if (omxcam__component_deinit (&omxcam__ctx.camera)){ 486 | omxcam__set_last_error (OMXCAM_ERROR_DEINIT_CAMERA); 487 | return -1; 488 | } 489 | if (omxcam__component_deinit (&omxcam__ctx.null_sink)){ 490 | omxcam__set_last_error (OMXCAM_ERROR_DEINIT_NULL_SINK); 491 | return -1; 492 | } 493 | if (use_encoder && omxcam__component_deinit (&omxcam__ctx.image_encode)){ 494 | omxcam__set_last_error (OMXCAM_ERROR_DEINIT_IMAGE_ENCODER); 495 | return -1; 496 | } 497 | 498 | if (omxcam__deinit ()) return -1; 499 | 500 | return 0; 501 | } 502 | 503 | int omxcam_still_stop (){ 504 | omxcam__trace ("stopping still capture"); 505 | 506 | omxcam__set_last_error (OMXCAM_ERROR_NONE); 507 | 508 | 509 | 510 | return 0; 511 | } -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | #include "omxcam.h" 2 | #include "internal.h" 3 | 4 | uint32_t omxcam_round (uint32_t value, uint32_t multiplier){ 5 | //Assumed that the rounding value is a power of 2 6 | return (value + multiplier - 1) & ~(multiplier - 1); 7 | } 8 | 9 | void omxcam_yuv_planes ( 10 | uint32_t width, 11 | uint32_t height, 12 | omxcam_yuv_planes_t* planes){ 13 | width = omxcam_round (width, 32); 14 | height = omxcam_round (height, 16); 15 | 16 | planes->offset_y = 0; 17 | planes->length_y = width*height; 18 | planes->offset_u = planes->length_y; 19 | //(width/2)*(height/2) 20 | planes->length_u = (width >> 1)*(height >> 1); 21 | planes->offset_v = planes->length_y + planes->length_u; 22 | planes->length_v = planes->length_u; 23 | } 24 | 25 | void omxcam_yuv_planes_slice ( 26 | uint32_t width, 27 | omxcam_yuv_planes_t* planes){ 28 | width = omxcam_round (width, 32); 29 | 30 | //slice height = 16 31 | planes->offset_y = 0; 32 | planes->length_y = width << 4; 33 | planes->offset_u = planes->length_y; 34 | //(width/2)*(sliceHeight/2) 35 | planes->length_u = width << 2; 36 | planes->offset_v = planes->length_y + planes->length_u; 37 | planes->length_v = planes->length_u; 38 | } 39 | 40 | const char* omxcam__strbool (omxcam_bool value){ 41 | return value ? "true" : "false"; 42 | } -------------------------------------------------------------------------------- /src/version.c: -------------------------------------------------------------------------------- 1 | #include "omxcam.h" 2 | #include "internal.h" 3 | 4 | #define OMXCAM_VERSION \ 5 | ((OMXCAM_VERSION_MAJOR << 16) | \ 6 | (OMXCAM_VERSION_MINOR << 8) | \ 7 | (OMXCAM_VERSION_PATCH)) 8 | 9 | #define OMXCAM_VERSION_STRING \ 10 | OMXCAM_STR_VALUE(OMXCAM_VERSION_MAJOR) "." \ 11 | OMXCAM_STR_VALUE(OMXCAM_VERSION_MINOR) "." \ 12 | OMXCAM_STR_VALUE(OMXCAM_VERSION_PATCH) 13 | 14 | uint32_t omxcam_version (){ 15 | return OMXCAM_VERSION; 16 | } 17 | 18 | const char* omxcam_version_string (){ 19 | return OMXCAM_VERSION_STRING; 20 | } --------------------------------------------------------------------------------