├── 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 | }
--------------------------------------------------------------------------------