Paparazzi UAS  v5.12_stable-4-g9b43e9b
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
cv.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 
28 #include <stdlib.h> // for malloc
29 #include <stdio.h>
30 
31 #include "cv.h"
32 #include "rt_priority.h"
33 
34 
35 void cv_attach_listener(struct video_config_t *device, struct video_listener *new_listener);
36 int8_t cv_async_function(struct cv_async *async, struct image_t *img);
37 void *cv_async_thread(void *args);
38 
39 
40 static inline uint32_t timeval_diff(struct timeval *A, struct timeval *B)
41 {
42  return (B->tv_sec - A->tv_sec) * 1000000 + (B->tv_usec - A->tv_usec);
43 }
44 
45 
47 {
48  // Create a new video listener
49  struct video_listener *new_listener = malloc(sizeof(struct video_listener));
50 
51  // Assign function to listener
52  new_listener->active = true;
53  new_listener->func = func;
54  new_listener->next = NULL;
55  new_listener->async = NULL;
56  new_listener->maximum_fps = fps;
57 
58  // Initialise the device that we want our function to use
59  add_video_device(device);
60 
61  // Check if device already has a listener
62  if (device->cv_listener == NULL) {
63  // Add as first listener
64  device->cv_listener = new_listener;
65  } else {
66  // Create pointer to first listener
67  struct video_listener *listener = device->cv_listener;
68 
69  // Loop through linked list to last listener
70  while (listener->next != NULL) {
71  listener = listener->next;
72  }
73 
74  // Add listener to end
75  listener->next = new_listener;
76  }
77 
78  return new_listener;
79 }
80 
81 
82 struct video_listener *cv_add_to_device_async(struct video_config_t *device, cv_function func, int nice_level, uint16_t fps)
83 {
84  // Create a normal listener
85  struct video_listener *listener = cv_add_to_device(device, func, fps);
86 
87  // Add asynchronous structure to override default synchronous behavior
88  listener->async = malloc(sizeof(struct cv_async));
89  listener->async->thread_priority = nice_level;
90 
91  // Explicitly mark img_copy as uninitialized
92  listener->async->img_copy.buf_size = 0;
93 
94  // Initialize mutex and condition variable
95  pthread_mutex_init(&listener->async->img_mutex, NULL);
96  pthread_cond_init(&listener->async->img_available, NULL);
97 
98  // Create new processing thread
99  pthread_create(&listener->async->thread_id, NULL, cv_async_thread, listener);
100 
101  return listener;
102 }
103 
104 
106 {
107  // If the previous image is not yet processed, return
108  if (!async->img_processed || pthread_mutex_trylock(&async->img_mutex) != 0) {
109  return -1;
110  }
111 
112  // If the image has not been initialized, do it
113  if (async->img_copy.buf_size == 0) {
114  image_create(&async->img_copy, img->w, img->h, img->type);
115  }
116 
117  // Copy image
118 // TODO:this takes time causing some thread lag, should be replaced with gpu operation
119  image_copy(img, &async->img_copy);
120 
121  // Inform thread of new image
122  async->img_processed = false;
123  pthread_cond_signal(&async->img_available);
124  pthread_mutex_unlock(&async->img_mutex);
125  return 0;
126 }
127 
128 
129 void *cv_async_thread(void *args)
130 {
131  struct video_listener *listener = args;
132  struct cv_async *async = listener->async;
133  async->thread_running = true;
134 
136 
137  // Request new image from video thread
138  pthread_mutex_lock(&async->img_mutex);
139  async->img_processed = true;
140 
141  while (async->thread_running) {
142  // Wait for img available signal
143  pthread_cond_wait(&async->img_available, &async->img_mutex);
144 
145  // Img might have been processed already (spurious wake-ups)
146  if (async->img_processed) {
147  continue;
148  }
149 
150  // Execute vision function from this thread
151  listener->func(&async->img_copy);
152 
153  // Mark image as processed
154  async->img_processed = true;
155  }
156 
157  pthread_mutex_unlock(&async->img_mutex);
158  pthread_exit(NULL);
159 }
160 
161 
162 void cv_run_device(struct video_config_t *device, struct image_t *img)
163 {
164  struct image_t *result;
165 
166  // Loop through computer vision pipeline
167  for (struct video_listener *listener = device->cv_listener; listener != NULL; listener = listener->next) {
168  // If the listener is not active, skip it
169  if (!listener->active) {
170  continue;
171  }
172 
173  // If the desired frame time for this listener is not reached, skip it
174  if (listener->maximum_fps > 0 && timeval_diff(&listener->ts, &img->ts) < (1000000 / listener->maximum_fps)) {
175  continue;
176  }
177 
178  if (listener->async != NULL) {
179  // Send image to asynchronous thread, only update listener if successful
180  if (!cv_async_function(listener->async, img)) {
181  // Store timestamp
182  listener->ts = img->ts;
183  }
184  } else {
185  // Execute the cvFunction and catch result
186  result = listener->func(img);
187 
188  // If result gives an image pointer, use it in the next stage
189  if (result != NULL) {
190  img = result;
191  }
192  // Store timestamp
193  listener->ts = img->ts;
194  }
195  }
196 }
unsigned short uint16_t
Definition: types.h:16
volatile bool active
Definition: cv.h:59
pthread_t thread_id
Definition: cv.h:42
uint32_t buf_size
The buffer size.
Definition: image.h:52
volatile bool thread_running
Definition: cv.h:43
uint16_t maximum_fps
Definition: cv.h:58
struct cv_async * async
Definition: cv.h:53
void cv_attach_listener(struct video_config_t *device, struct video_listener *new_listener)
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
Definition: image.h:43
void image_copy(struct image_t *input, struct image_t *output)
Copy an image from inut to output This will only work if the formats are the same.
Definition: image.c:77
#define B
struct video_listener * cv_add_to_device(struct video_config_t *device, cv_function func, uint16_t fps)
Definition: cv.c:46
Functions to obtain rt priority or set the nice level.
struct video_listener * listener
Definition: colorfilter.c:43
struct video_listener * cv_listener
The first computer vision listener in the linked list for this video device.
Definition: video_device.h:55
int8_t cv_async_function(struct cv_async *async, struct image_t *img)
Definition: cv.c:105
uint16_t w
Image width.
Definition: image.h:45
unsigned long uint32_t
Definition: types.h:18
Computer vision framework for onboard processing.
uint16_t h
Image height.
Definition: image.h:46
volatile int thread_priority
Definition: cv.h:44
bool add_video_device(struct video_config_t *device)
Keep track of video devices added by modules.
Definition: video_thread.c:195
static uint32_t timeval_diff(struct timeval *A, struct timeval *B)
Definition: cv.c:40
struct video_listener * cv_add_to_device_async(struct video_config_t *device, cv_function func, int nice_level, uint16_t fps)
Definition: cv.c:82
pthread_cond_t img_available
Definition: cv.h:46
struct timeval ts
Definition: cv.h:54
struct image_t *(* cv_function)(struct image_t *img)
Definition: cv.h:39
void cv_run_device(struct video_config_t *device, struct image_t *img)
Definition: cv.c:162
volatile bool img_processed
Definition: cv.h:47
struct timeval ts
The timestamp of creation.
Definition: image.h:47
void * cv_async_thread(void *args)
Definition: cv.c:129
cv_function func
Definition: cv.h:55
pthread_mutex_t img_mutex
Definition: cv.h:45
#define A
struct video_listener * next
Definition: cv.h:52
signed char int8_t
Definition: types.h:15
struct image_t img_copy
Definition: cv.h:48
static int set_nice_level(int level)
Definition: rt_priority.h:69
Definition: cv.h:41
V4L2 device settings.
Definition: video_device.h:44
enum image_type type
The image type.
Definition: image.h:44