Paparazzi UAS  v5.8.2_stable-0-g6260b7c
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
video_thread.c
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2015
3 *
4 * This file is part of Paparazzi.
5 *
6 * Paparazzi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * Paparazzi is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with paparazzi; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21 
26 // Own header
29 
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/time.h>
35 #include <math.h>
36 
37 // Video
38 #include "lib/v4l/v4l2.h"
39 #include "lib/vision/image.h"
40 #include "lib/vision/bayer.h"
41 #include "lib/encoding/jpeg.h"
43 
44 #include "mcu_periph/sys_time.h"
45 
46 // include board for bottom_camera and front_camera on ARDrone2 and Bebop
47 #include BOARD_CONFIG
48 
49 #if JPEG_WITH_EXIF_HEADER
50 #include "lib/exif/exif_module.h"
51 #endif
52 
53 // Threaded computer vision
54 #include <pthread.h>
55 #include "rt_priority.h"
56 
58 #ifndef VIDEO_THREAD_CAMERA
59 #warning "Are you sure you don't want to use the bottom_camera or front_camera?"
60 // The video device buffers (the amount of V4L2 buffers)
61 #ifndef VIDEO_THREAD_DEVICE_BUFFERS
62 #define VIDEO_THREAD_DEVICE_BUFFERS 10
63 #endif
64 PRINT_CONFIG_VAR(VIDEO_THREAD_DEVICE_BUFFERS)
65 #ifndef VIDEO_THREAD_SUBDEV
66 #define VIDEO_THREAD_SUBDEV NULL
67 #endif
68 #ifndef VIDEO_THREAD_FILTERS
69 #define VIDEO_THREAD_FILTERS 0
70 #endif
72  .w = VIDEO_THREAD_VIDEO_WIDTH,
73  .h = VIDEO_THREAD_VIDEO_HEIGHT,
74  .dev_name = STRINGIFY(VIDEO_THREAD_DEVICE),
75  .subdev_name = VIDEO_THREAD_SUBDEV,
76  .buf_cnt = VIDEO_THREAD_DEVICE_BUFFERS,
77  .filters = VIDEO_THREAD_FILTERS
78 };
79 #define VIDEO_THREAD_CAMERA custom_camera
80 #endif
81 PRINT_CONFIG_VAR(VIDEO_THREAD_CAMERA)
82 
83 
84 // Frames Per Seconds
85 #ifndef VIDEO_THREAD_FPS
86 #define VIDEO_THREAD_FPS 4
87 #endif
88 PRINT_CONFIG_VAR(VIDEO_THREAD_FPS)
89 
90 // The place where the shots are saved (without slash on the end)
91 #ifndef VIDEO_THREAD_SHOT_PATH
92 #define VIDEO_THREAD_SHOT_PATH "/data/video/images"
93 #endif
94 PRINT_CONFIG_VAR(VIDEO_THREAD_SHOT_PATH)
95 
96 // Main thread
97 static void *video_thread_function(void *data);
98 void video_thread_periodic(void) { }
99 
100 // Initialize the video_thread structure with the defaults
102  .is_running = FALSE,
103  .fps = VIDEO_THREAD_FPS,
104  .take_shot = FALSE,
105  .shot_number = 0
106 };
107 
108 static void video_thread_save_shot(struct image_t *img, struct image_t *img_jpeg)
109 {
110 
111  // Search for a file where we can write to
112  char save_name[128];
113  for (; video_thread.shot_number < 99999; video_thread.shot_number++) {
114  sprintf(save_name, "%s/img_%05d.jpg", STRINGIFY(VIDEO_THREAD_SHOT_PATH), video_thread.shot_number);
115  // Check if file exists or not
116  if (access(save_name, F_OK) == -1) {
117 
118  // Create a high quality image (99% JPEG encoded)
119  jpeg_encode_image(img, img_jpeg, 99, TRUE);
120 
121 #if JPEG_WITH_EXIF_HEADER
122  write_exif_jpeg(save_name, img_jpeg->buf, img_jpeg->buf_size, img_jpeg->w, img_jpeg->h);
123 #else
124  FILE *fp = fopen(save_name, "w");
125  if (fp == NULL) {
126  printf("[video_thread-thread] Could not write shot %s.\n", save_name);
127  } else {
128  // Save it to the file and close it
129  fwrite(img_jpeg->buf, sizeof(uint8_t), img_jpeg->buf_size, fp);
130  fclose(fp);
131  }
132 #endif
133 
134  // We don't need to seek for a next index anymore
135  break;
136  }
137  }
138 }
139 
140 
145 static void *video_thread_function(void *data)
146 {
147  struct video_config_t *vid = (struct video_config_t *)&(VIDEO_THREAD_CAMERA);
148 
149  struct image_t img_jpeg;
150  struct image_t img_color;
151 
152  // create the images
153  if (vid->filters) {
154  // fixme: don't hardcode size, works for bebop front camera for now
155 #define IMG_FLT_SIZE 272
158  }
159  else {
160  image_create(&img_jpeg, vid->w, vid->h, IMAGE_JPEG);
161  }
162 
163  // Start the streaming of the V4L2 device
164  if (!v4l2_start_capture(video_thread.dev)) {
165  printf("[video_thread-thread] Could not start capture of %s.\n", video_thread.dev->name);
166  return 0;
167  }
168 
169  // be nice to the more important stuff
170  set_nice_level(10);
171 
172  // Initialize timing
173  struct timespec time_now;
174  struct timespec time_prev;
175  clock_gettime(CLOCK_MONOTONIC, &time_prev);
176 
177  // Start streaming
178  video_thread.is_running = TRUE;
179  while (video_thread.is_running) {
180 
181  // get time in us since last run
182  clock_gettime(CLOCK_MONOTONIC, &time_now);
183  unsigned int dt_us = sys_time_elapsed_us(&time_prev, &time_now);
184  time_prev = time_now;
185 
186  // sleep remaining time to limit to specified fps
187  uint32_t fps_period_us = (uint32_t)(1000000. / (float)video_thread.fps);
188  if (dt_us < fps_period_us) {
189  usleep(fps_period_us - dt_us);
190  }
191  else {
192  fprintf(stderr, "video_thread: desired %i fps, only managing %.1f fps\n",
193  video_thread.fps, 1000000.f / dt_us);
194  }
195 
196  // Wait for a new frame (blocking)
197  struct image_t img;
198  v4l2_image_get(video_thread.dev, &img);
199 
200  // pointer to the final image to pass for saving and further processing
201  struct image_t *img_final = &img;
202 
203  // run selected filters
204  if (vid->filters) {
205  if (vid->filters & VIDEO_FILTER_DEBAYER) {
206  BayerToYUV(&img, &img_color, 0, 0);
207  }
208  // use color image for further processing
209  img_final = &img_color;
210  }
211 
212  // Check if we need to take a shot
213  if (video_thread.take_shot) {
214  video_thread_save_shot(img_final, &img_jpeg);
215  video_thread.take_shot = FALSE;
216  }
217 
218  // Run processing if required
219  cv_run(img_final);
220 
221  // Free the image
222  v4l2_image_free(video_thread.dev, &img);
223  }
224 
225  image_free(&img_jpeg);
226  image_free(&img_color);
227 
228  return 0;
229 }
230 
235 {
236  struct video_config_t *vid = (struct video_config_t *)&(VIDEO_THREAD_CAMERA);
237 
238  // Initialize the V4L2 subdevice if needed
239  if (vid->subdev_name != NULL) {
240  // FIXME! add subdev format to config, only needed on bebop front camera so far
241  if (!v4l2_init_subdev(vid->subdev_name, 0, 0, V4L2_MBUS_FMT_SGBRG10_1X10, vid->w, vid->h)) {
242  printf("[video_thread] Could not initialize the %s subdevice.\n", vid->subdev_name);
243  return;
244  }
245  }
246 
247  // Initialize the V4L2 device
248  video_thread.dev = v4l2_init(vid->dev_name, vid->w, vid->h, vid->buf_cnt, vid->format);
249  if (video_thread.dev == NULL) {
250  printf("[video_thread] Could not initialize the %s V4L2 device.\n", vid->dev_name);
251  return;
252  }
253 
254  // Create the shot directory
255  char save_name[128];
256  sprintf(save_name, "mkdir -p %s", STRINGIFY(VIDEO_THREAD_SHOT_PATH));
257  if (system(save_name) != 0) {
258  printf("[video_thread] Could not create shot directory %s.\n", STRINGIFY(VIDEO_THREAD_SHOT_PATH));
259  return;
260  }
261 }
262 
267 {
268  // Check if we are already running
269  if (video_thread.is_running) {
270  return;
271  }
272 
273  // Start the streaming thread
274  pthread_t tid;
275  if (pthread_create(&tid, NULL, video_thread_function, (void*)(&VIDEO_THREAD_CAMERA)) != 0) {
276  printf("[vievideo] Could not create streaming thread.\n");
277  return;
278  }
279 }
280 
286 {
287  // Check if not already stopped streaming
288  if (!video_thread.is_running) {
289  return;
290  }
291 
292  // Stop the streaming thread
293  video_thread.is_running = FALSE;
294 
295  // Stop the capturing
296  if (!v4l2_stop_capture(video_thread.dev)) {
297  printf("[video_thread] Could not stop capture of %s.\n", video_thread.dev->name);
298  return;
299  }
300 
301  // TODO: wait for the thread to finish to be able to start the thread again!
302 }
303 
308 void video_thread_take_shot(bool_t take)
309 {
310  video_thread.take_shot = take;
311 }
#define VIDEO_THREAD_DEVICE_BUFFERS
The camera video config (usually bottom_camera or front_camera)
Definition: video_thread.c:62
uint32_t format
Video format.
Definition: video_device.h:42
void video_thread_stop(void)
Stops the streaming This could take some time, because the thread is stopped asynchronous.
Definition: video_thread.c:285
static void video_thread_save_shot(struct image_t *img, struct image_t *img_jpeg)
Definition: video_thread.c:108
uint32_t buf_size
The buffer size.
Definition: image.h:49
bool_t v4l2_start_capture(struct v4l2_device *dev)
Start capturing images in streaming mode (Thread safe)
Definition: v4l2.c:387
int w
Width.
Definition: video_device.h:38
void v4l2_image_free(struct v4l2_device *dev, struct image_t *img)
Free the image and enqueue the buffer (Thread safe) This must be done after processing the image...
Definition: v4l2.c:366
struct video_config_t custom_camera
Definition: video_thread.c:71
void v4l2_image_get(struct v4l2_device *dev, struct image_t *img)
Get the latest image buffer and lock it (Thread safe, BLOCKING) This functions blocks until image acc...
Definition: v4l2.c:294
int h
Height.
Definition: video_device.h:39
void image_free(struct image_t *img)
Free the image.
Definition: image.c:63
Capture images from a V4L2 device (Video for Linux 2)
#define VIDEO_THREAD_CAMERA
Definition: video_thread.c:79
void image_create(struct image_t *img, uint16_t width, uint16_t height, enum image_type type)
Create a new image.
Definition: image.c:38
Start a Video thread and grab images.
Definition: image.h:42
bool_t v4l2_stop_capture(struct v4l2_device *dev)
Stop capturing of the image stream (Thread safe) This function is blocking until capturing thread is ...
Definition: v4l2.c:446
char * dev_name
path to device
Definition: video_device.h:40
uint8_t filters
filters to use (bitfield with VIDEO_FILTER_x)
Definition: video_device.h:44
Functions to obtain rt priority or set the nice level.
#define FALSE
Definition: std.h:5
uint8_t buf_cnt
Amount of V4L2 video device buffers.
Definition: video_device.h:43
void jpeg_encode_image(struct image_t *in, struct image_t *out, uint32_t quality_factor, bool_t add_dri_header)
Encode an YUV422 image.
Definition: jpeg.c:425
Image helper functions like resizing, color filter, converters...
#define TRUE
Definition: std.h:4
#define VIDEO_THREAD_FPS
Definition: video_thread.c:86
#define VIDEO_THREAD_SUBDEV
Definition: video_thread.c:66
Architecture independent timing functions.
int write_exif_jpeg(char *filename, const unsigned char *image_jpg, const unsigned int image_jpg_len, const unsigned int image_jpg_x, const unsigned int image_jpg_y)
Definition: exif_module.c:146
void video_thread_init(void)
Initialize the view video.
Definition: video_thread.c:234
void BayerToYUV(struct image_t *Input, struct image_t *out, int RedX, int RedY)
Decode Bayer Pattern.
Definition: bayer.h:55
uint16_t w
Image width.
Definition: image.h:44
unsigned long uint32_t
Definition: types.h:18
Computer vision framework for onboard processing.
uint16_t h
Image height.
Definition: image.h:45
char * subdev_name
path to sub device
Definition: video_device.h:41
void * buf
Image buffer (depending on the image_type)
Definition: image.h:50
static unsigned int sys_time_elapsed_us(struct timespec *prev, struct timespec *now)
elapsed time in microsecs between two timespecs
Definition: sys_time_arch.h:61
#define VIDEO_FILTER_DEBAYER
Definition: video_device.h:34
volatile bool_t is_running
When the device is running.
Definition: video_thread.h:37
void video_thread_take_shot(bool_t take)
Take a shot and save it This will only work when the streaming is enabled.
Definition: video_thread.c:308
static void * video_thread_function(void *data)
Handles all the video streaming and saving of the image shots This is a sepereate thread...
Definition: video_thread.c:145
bool_t v4l2_init_subdev(char *subdev_name, uint8_t pad, uint8_t which, uint16_t code, uint16_t width, uint16_t height)
Initialize a V4L2 subdevice.
Definition: v4l2.c:130
Encode images with the use of the JPEG encoding.
#define VIDEO_THREAD_FILTERS
Definition: video_thread.c:69
char * name
The name of the device.
Definition: v4l2.h:49
unsigned char uint8_t
Definition: types.h:14
uint16_t shot_number
The last shot number.
Definition: video_thread.h:42
#define IMG_FLT_SIZE
volatile bool_t take_shot
Wether to take an image.
Definition: video_thread.h:41
UYVY format (uint16 per pixel)
Definition: image.h:35
v4l2 video device settings interface Works on Linux platforms
#define VIDEO_THREAD_SHOT_PATH
Definition: video_thread.c:92
void cv_run(struct image_t *img)
Definition: cv.c:43
uint8_t fps
The amount of frames per second.
Definition: video_thread.h:39
struct v4l2_device * dev
The V4L2 device that is used for the video stream.
Definition: video_thread.h:38
Write JPEG images containing EXIF headers with GPS coordinates.
void video_thread_start(void)
Start with streaming.
Definition: video_thread.c:266
static int set_nice_level(int level)
Definition: rt_priority.h:69
struct v4l2_device * v4l2_init(char *device_name, uint16_t width, uint16_t height, uint8_t buffers_cnt, uint32_t _pixelformat)
Initialize a V4L2(Video for Linux 2) device.
Definition: v4l2.c:177
struct video_thread_t video_thread
Definition: video_thread.c:101
V4L2 device settings.
Definition: video_device.h:37
void video_thread_periodic(void)
A dummy for now.
Definition: video_thread.c:98
An JPEG encoded image (not per pixel encoded)
Definition: image.h:37