Paparazzi UAS  v5.18.0_stable
Paparazzi is a free software Unmanned Aircraft System.
viewvideo.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012-2014 The Paparazzi Community
3  * 2015 Freek van Tienen <freek.v.tienen@gmail.com>
4  *
5  * This file is part of Paparazzi.
6  *
7  * Paparazzi is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * Paparazzi is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with paparazzi; see the file COPYING. If not, see
19  * <http://www.gnu.org/licenses/>.
20  *
21  */
22 
32 // Own header
35 
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <sys/time.h>
41 #include <math.h>
42 
43 // Video
44 #include "lib/vision/image.h"
45 #include "lib/encoding/jpeg.h"
46 #include "lib/encoding/rtp.h"
47 #include "udp_socket.h"
48 
49 #include BOARD_CONFIG
50 
51 // Downsize factor for video stream
52 #ifndef VIEWVIDEO_DOWNSIZE_FACTOR
53 #define VIEWVIDEO_DOWNSIZE_FACTOR 4
54 #endif
55 PRINT_CONFIG_VAR(VIEWVIDEO_DOWNSIZE_FACTOR)
56 
57 // From 0 to 99 (99=high)
58 #ifndef VIEWVIDEO_QUALITY_FACTOR
59 #define VIEWVIDEO_QUALITY_FACTOR 50
60 #endif
61 PRINT_CONFIG_VAR(VIEWVIDEO_QUALITY_FACTOR)
62 
63 // Define stream framerate
64 #ifndef VIEWVIDEO_FPS
65 #define VIEWVIDEO_FPS 5
66 #endif
67 PRINT_CONFIG_VAR(VIEWVIDEO_FPS)
68 
69 // Define stream priority
70 #ifndef VIEWVIDEO_NICE_LEVEL
71 #define VIEWVIDEO_NICE_LEVEL 5
72 #endif
73 PRINT_CONFIG_VAR(VIEWVIDEO_NICE_LEVEL)
74 
75 // Check if we are using netcat instead of RTP/UDP
76 #ifndef VIEWVIDEO_USE_NETCAT
77 #define VIEWVIDEO_USE_NETCAT FALSE
78 #endif
79 
80 #if !VIEWVIDEO_USE_NETCAT && !(defined VIEWVIDEO_USE_RTP)
81 #define VIEWVIDEO_USE_RTP TRUE
82 #endif
83 
84 #if VIEWVIDEO_USE_NETCAT
85 #include <sys/wait.h>
86 PRINT_CONFIG_MSG("[viewvideo] Using netcat.")
87 #else
90 PRINT_CONFIG_MSG("[viewvideo] Using RTP/UDP stream.")
91 PRINT_CONFIG_VAR(VIEWVIDEO_USE_RTP)
92 #endif
93 
94 /* These are defined with configure */
95 PRINT_CONFIG_VAR(VIEWVIDEO_HOST)
96 PRINT_CONFIG_VAR(VIEWVIDEO_PORT_OUT)
97 PRINT_CONFIG_VAR(VIEWVIDEO_PORT2_OUT)
98 
99 // Initialize the viewvideo structure with the defaults
101  .is_streaming = FALSE,
102  .downsize_factor = VIEWVIDEO_DOWNSIZE_FACTOR,
103  .quality_factor = VIEWVIDEO_QUALITY_FACTOR,
104 #if !VIEWVIDEO_USE_NETCAT
105  .use_rtp = VIEWVIDEO_USE_RTP,
106 #endif
107 };
108 
113 static struct image_t *viewvideo_function(struct UdpSocket *viewvideo_socket, struct image_t *img, uint16_t *rtp_packet_nr, uint32_t *rtp_frame_time,
114  struct image_t *img_small, struct image_t *img_jpeg)
115 {
116  // Resize small image if needed
118  if(img_small->buf != NULL){
119  image_free(img_small);
120  }
121  image_create(img_small,
122  img->w / viewvideo.downsize_factor,
123  img->h / viewvideo.downsize_factor,
124  IMAGE_YUV422);
125  }
126 
127  // Resize JPEG encoded image if needed
128  if(img_jpeg->w != img_small->w || img_jpeg->h != img_small->h)
129  {
130  if(img_jpeg->buf != NULL){
131  image_free(img_jpeg);
132  }
133  image_create(img_jpeg, img_small->w, img_small->h, IMAGE_JPEG);
134  }
135 
136 #if VIEWVIDEO_USE_NETCAT
137  char nc_cmd[64];
138  sprintf(nc_cmd, "nc %s %d 2>/dev/null", STRINGIFY(VIEWVIDEO_HOST), VIEWVIDEO_PORT_OUT);
139 #endif
140 
141  if (viewvideo.is_streaming) {
142  // Only resize when needed
143  if (viewvideo.downsize_factor > 1) {
146  } else {
148  }
149 
150 #if VIEWVIDEO_USE_NETCAT
151  // Open process to send using netcat (in a fork because sometimes kills itself???)
152  pid_t pid = fork();
153 
154  if (pid < 0) {
155  printf("[viewvideo] Could not create netcat fork.\n");
156  } else if (pid == 0) {
157  // We are the child and want to send the image
158  FILE *netcat = popen(nc_cmd, "w");
159  if (netcat != NULL) {
160  fwrite(img_jpeg->buf, sizeof(uint8_t), img_jpeg->buf_size, netcat);
161  pclose(netcat); // Ignore output, because it is too much when not connected
162  } else {
163  printf("[viewvideo] Failed to open netcat process.\n");
164  }
165 
166  // Exit the program since we don't want to continue after transmitting
167  exit(0);
168  } else {
169  // We want to wait until the child is finished
170  wait(NULL);
171  }
172 #else
173  if (viewvideo.use_rtp) {
174  // Send image with RTP
176  viewvideo_socket, // UDP socket
177  img_jpeg,
178  0, // Format 422
179  VIEWVIDEO_QUALITY_FACTOR, // Jpeg-Quality
180  0, // DRI Header
182  //(img->ts.tv_sec * 1000000 + img->ts.tv_usec),
183  rtp_packet_nr,
184  rtp_frame_time
185  );
186  }
187 #endif
188  }
189 
190  return NULL; // No new images were created
191 }
192 
193 #ifdef VIEWVIDEO_CAMERA
194 static struct image_t *viewvideo_function1(struct image_t *img, uint8_t camera_id __attribute__((unused)))
195 {
196  static uint16_t rtp_packet_nr = 0;
197  static uint32_t rtp_frame_time = 0;
198  static struct image_t img_small = {.buf=NULL, .buf_size=0};
199  static struct image_t img_jpeg = {.buf=NULL, .buf_size=0};
200  return viewvideo_function(&video_sock1, img, &rtp_packet_nr, &rtp_frame_time, &img_small, &img_jpeg);
201 }
202 #endif
203 
204 #ifdef VIEWVIDEO_CAMERA2
205 static struct image_t *viewvideo_function2(struct image_t *img, uint8_t camera_id __attribute__((unused)))
206 {
207  static uint16_t rtp_packet_nr = 0;
208  static uint32_t rtp_frame_time = 0;
209  static struct image_t img_small = {.buf=NULL, .buf_size=0};
210  static struct image_t img_jpeg = {.buf=NULL, .buf_size=0};
211  return viewvideo_function(&video_sock2, img, &rtp_packet_nr, &rtp_frame_time, &img_small, &img_jpeg);
212 }
213 #endif
214 
218 void viewvideo_init(void)
219 {
220  viewvideo.is_streaming = true;
221 
222  // safety check
223  if(viewvideo.downsize_factor < 1){
225  }
226 
227  if(viewvideo.quality_factor > 99){
229  }
230 
231 #if VIEWVIDEO_USE_NETCAT
232  // Create an Netcat receiver file for the streaming
233  sprintf(save_name, "%s/netcat-recv.sh", STRINGIFY(VIEWVIDEO_SHOT_PATH));
234  FILE *fp = fopen(save_name, "w");
235  if (fp != NULL) {
236  fprintf(fp, "i=0\n");
237  fprintf(fp, "while true\n");
238  fprintf(fp, "do\n");
239  fprintf(fp, "\tn=$(printf \"%%04d\" $i)\n");
240  fprintf(fp, "\tnc -l 0.0.0.0 %d > img_${n}.jpg\n", (int)(VIEWVIDEO_PORT_OUT));
241  fprintf(fp, "\ti=$((i+1))\n");
242  fprintf(fp, "done\n");
243  fclose(fp);
244  } else {
245  printf("[viewvideo] Failed to create netcat receiver file.\n");
246  }
247 #else
248  // Open udp socket
249 #ifdef VIEWVIDEO_CAMERA
250  if (udp_socket_create(&video_sock1, STRINGIFY(VIEWVIDEO_HOST), VIEWVIDEO_PORT_OUT, -1, VIEWVIDEO_BROADCAST)) {
251  printf("[viewvideo]: failed to open view video socket, HOST=%s, port=%d\n", STRINGIFY(VIEWVIDEO_HOST),
252  VIEWVIDEO_PORT_OUT);
253  }
254 #endif
255 
256 #ifdef VIEWVIDEO_CAMERA2
257  if (udp_socket_create(&video_sock2, STRINGIFY(VIEWVIDEO_HOST), VIEWVIDEO_PORT2_OUT, -1, VIEWVIDEO_BROADCAST)) {
258  printf("[viewvideo]: failed to open view video socket, HOST=%s, port=%d\n", STRINGIFY(VIEWVIDEO_HOST),
259  VIEWVIDEO_PORT2_OUT);
260  }
261 #endif
262 #endif
263 
264 #ifdef VIEWVIDEO_CAMERA
265  cv_add_to_device_async(&VIEWVIDEO_CAMERA, viewvideo_function1,
267  fprintf(stderr, "[viewvideo] Added asynchronous video streamer listener for CAMERA1 at %u FPS \n", VIEWVIDEO_FPS);
268 #endif
269 
270 #ifdef VIEWVIDEO_CAMERA2
271  cv_add_to_device_async(&VIEWVIDEO_CAMERA2, viewvideo_function2,
273  fprintf(stderr, "[viewvideo] Added asynchronous video streamer listener for CAMERA2 at %u FPS \n", VIEWVIDEO_FPS);
274 #endif
275 }
uint16_t
unsigned short uint16_t
Definition: types.h:16
image_create
void image_create(struct image_t *img, uint16_t width, uint16_t height, enum image_type type)
Create a new image.
Definition: image.c:43
jpeg_encode_image
void jpeg_encode_image(struct image_t *in, struct image_t *out, uint32_t quality_factor, bool add_dri_header)
Encode an YUV422 image.
Definition: jpeg.c:408
viewvideo_t
Definition: viewvideo.h:38
udp_socket_create
int udp_socket_create(struct UdpSocket *sock, char *host, int port_out, int port_in, bool broadcast)
Create UDP socket and bind it.
Definition: udp_socket.c:49
VIEWVIDEO_DOWNSIZE_FACTOR
#define VIEWVIDEO_DOWNSIZE_FACTOR
Definition: viewvideo.c:53
uint32_t
unsigned long uint32_t
Definition: types.h:18
viewvideo
struct viewvideo_t viewvideo
Definition: viewvideo.c:100
image_free
void image_free(struct image_t *img)
Free the image.
Definition: image.c:75
cv_add_to_device_async
struct video_listener * cv_add_to_device_async(struct video_config_t *device, cv_function func, int nice_level, uint16_t fps, uint8_t id)
Definition: cv.c:83
rtp_frame_send
void rtp_frame_send(struct UdpSocket *udp, struct image_t *img, uint8_t format_code, uint8_t quality_code, uint8_t has_dri_header, float average_frame_rate, uint16_t *packet_number, uint32_t *rtp_time_counter)
Send an RTP frame.
Definition: rtp.c:127
viewvideo_t::use_rtp
bool use_rtp
Stream over RTP.
Definition: viewvideo.h:42
image_t::w
uint16_t w
Image width.
Definition: image.h:46
VIEWVIDEO_QUALITY_FACTOR
#define VIEWVIDEO_QUALITY_FACTOR
Definition: viewvideo.c:59
video_sock1
struct UdpSocket video_sock1
Definition: viewvideo.c:88
image_t::buf_size
uint32_t buf_size
The buffer size.
Definition: image.h:53
udp_socket.h
image_t::h
uint16_t h
Image height.
Definition: image.h:47
VIEWVIDEO_FPS
#define VIEWVIDEO_FPS
Definition: viewvideo.c:65
cv.h
VIEWVIDEO_USE_NETCAT
#define VIEWVIDEO_USE_NETCAT
Definition: viewvideo.c:77
image_yuv422_downsample
void image_yuv422_downsample(struct image_t *input, struct image_t *output, uint8_t downsample)
Simplified high-speed low CPU downsample function without averaging downsample factor must be 1,...
Definition: image.c:311
viewvideo_init
void viewvideo_init(void)
Initialize the view video.
Definition: viewvideo.c:218
viewvideo_function
static struct image_t * viewvideo_function(struct UdpSocket *viewvideo_socket, struct image_t *img, uint16_t *rtp_packet_nr, uint32_t *rtp_frame_time, struct image_t *img_small, struct image_t *img_jpeg)
Handles all the video streaming and saving of the image shots This is a separate thread,...
Definition: viewvideo.c:113
uint8_t
unsigned char uint8_t
Definition: types.h:14
IMAGE_JPEG
@ IMAGE_JPEG
An JPEG encoded image (not per pixel encoded)
Definition: image.h:38
VIEWVIDEO_NICE_LEVEL
#define VIEWVIDEO_NICE_LEVEL
Definition: viewvideo.c:71
image.h
VIEWVIDEO_USE_RTP
#define VIEWVIDEO_USE_RTP
Definition: viewvideo.c:81
rtp.h
PRINT_CONFIG_MSG
PRINT_CONFIG_MSG("USE_INS_NAV_INIT defaulting to TRUE")
viewvideo_t::quality_factor
uint8_t quality_factor
Quality factor during the stream.
Definition: viewvideo.h:41
viewvideo.h
viewvideo_t::is_streaming
volatile bool is_streaming
When the device is streaming.
Definition: viewvideo.h:39
IMAGE_YUV422
@ IMAGE_YUV422
UYVY format (uint16 per pixel)
Definition: image.h:36
video_sock2
struct UdpSocket video_sock2
Definition: viewvideo.c:89
image_t::buf
void * buf
Image buffer (depending on the image_type)
Definition: image.h:54
FALSE
#define FALSE
Definition: std.h:5
UdpSocket
Definition: udp_socket.h:34
viewvideo_t::downsize_factor
uint8_t downsize_factor
Downsize factor during the stream.
Definition: viewvideo.h:40
image_t
Definition: image.h:44
jpeg.h