mirror of
https://github.com/paparazzi/paparazzi.git
synced 2026-05-23 04:45:37 +08:00
add possibility to stream dual video
This commit is contained in:
@@ -17,7 +17,9 @@
|
||||
<define name="MT9F002_GAIN_GREEN2" value="4"/>
|
||||
<define name="MT9F002_GAIN_RED" value="5"/>
|
||||
<define name="MT9F002_GAIN_BLUE" value="5"/>
|
||||
<define name="MT9F002_OUTPUT_SCALER" value="0.5"/>
|
||||
<define name="MT9F002_OUTPUT_SCALER" value="1."/>
|
||||
<define name="MT9F002_X_ODD_INC_VAL" value="7"/>
|
||||
<define name="MT9F002_Y_ODD_INC_VAL" value="7"/>
|
||||
|
||||
<!--define name="USE_SONAR" value="TRUE"/-->
|
||||
|
||||
@@ -44,9 +46,13 @@
|
||||
<module name="video_thread"/>
|
||||
|
||||
<module name="video_rtp_stream">
|
||||
<define name="VIEWVIDEO_CAMERA" value="front_camera"/>
|
||||
<define name="VIEWVIDEO_CAMERA" value="bottom_camera"/>
|
||||
<define name="VIEWVIDEO_CAMERA2" value="front_camera"/>
|
||||
<define name="VIEWVIDEO_DOWNSIZE_FACTOR" value="2"/>
|
||||
<define name="VIEWVIDEO_QUALITY_FACTOR" value="40"/>
|
||||
|
||||
<configure name="VIEWVIDEO_BROADCAST" value="FALSE"/>
|
||||
<configure name="VIEWVIDEO_HOST" value="192.168.42.98"/>
|
||||
</module>
|
||||
|
||||
<module name="cv_ae_awb"/>
|
||||
|
||||
@@ -68,6 +68,11 @@
|
||||
<program name="IridiumDialer" command="sw/tools/iridium/iridium_link.py"/>
|
||||
<program name="PayloadForward" command="sw/ground_segment/python/payload_forward/payload.py"/>
|
||||
<program name="AeronauticalInfo" command="sw/ground_segment/python/atc/atc.py"/>
|
||||
<program name="RtpViewer" command="sw/tools/rtp_viewer/rtp_viewer.py">
|
||||
<arg flag="-p" constant="5000"/>
|
||||
<arg flag="-s" constant="0.75"/>
|
||||
<arg flag="-r" constant="3"/>
|
||||
</program>
|
||||
</section>
|
||||
|
||||
<section name="sessions">
|
||||
|
||||
@@ -13,9 +13,11 @@
|
||||
<configure name="VIEWVIDEO_USE_NETCAT" value="FALSE|TRUE" description="Use netcat for transfering images instead of RTP stream (default: FALSE)"/>
|
||||
<configure name="VIEWVIDEO_HOST" value="192.168.1.255" description="GCS IP (default: MODEM_HOST)"/>
|
||||
<configure name="VIEWVIDEO_PORT_OUT" value="5000" description="Port (default: 5000)"/>
|
||||
<configure name="VIEWVIDEO_PORT2_OUT" value="6000" description="Port (default: 6000)"/>
|
||||
<configure name="VIEWVIDEO_BROADCAST" value="FALSE|TRUE" description="Enable broadcast of image stream (default: TRUE)"/>
|
||||
|
||||
<define name="VIEWVIDEO_CAMERA" value="front_camera|bottom_camera" description="Video device to use"/>
|
||||
<define name="VIEWVIDEO_CAMERA2" value="front_camera|bottom_camera" description="Video device to use"/>
|
||||
<define name="VIEWVIDEO_DOWNSIZE_FACTOR" value="4" description="Reduction factor of the video stream"/>
|
||||
<define name="VIEWVIDEO_QUALITY_FACTOR" value="50" description="JPEG encoding compression factor [0-99]"/>
|
||||
<define name="VIEWVIDEO_USE_RTP" value="TRUE|FALSE" description="Enable RTP at startup for transfering images (default: TRUE)"/>
|
||||
@@ -47,10 +49,11 @@
|
||||
|
||||
VIEWVIDEO_HOST ?= $(MODEM_HOST)
|
||||
VIEWVIDEO_PORT_OUT ?= 5000
|
||||
VIEWVIDEO_PORT2_OUT ?= 6000
|
||||
VIEWVIDEO_BROADCAST ?= TRUE
|
||||
VIEWVIDEO_USE_NETCAT ?= FALSE
|
||||
|
||||
VIEWVID_CFLAGS = -DVIEWVIDEO_HOST=$(VIEWVIDEO_HOST) -DVIEWVIDEO_PORT_OUT=$(VIEWVIDEO_PORT_OUT)
|
||||
VIEWVID_CFLAGS = -DVIEWVIDEO_HOST=$(VIEWVIDEO_HOST) -DVIEWVIDEO_PORT_OUT=$(VIEWVIDEO_PORT_OUT) -DVIEWVIDEO_PORT2_OUT=$(VIEWVIDEO_PORT2_OUT)
|
||||
ifneq (,$(findstring $(VIEWVIDEO_USE_NETCAT),0 FALSE))
|
||||
ap.CFLAGS += $(VIEWVID_CFLAGS) -DVIEWVIDEO_BROADCAST=$(VIEWVIDEO_BROADCAST)
|
||||
nps.CFLAGS += $(VIEWVID_CFLAGS) -DVIEWVIDEO_BROADCAST=FALSE
|
||||
|
||||
@@ -175,7 +175,7 @@ void cv_run_device(struct video_config_t *device, struct image_t *img)
|
||||
}
|
||||
|
||||
if (listener->async != NULL) {
|
||||
// Send image to asynchronous thread, only update listener if succesful
|
||||
// Send image to asynchronous thread, only update listener if successful
|
||||
if (!cv_async_function(listener->async, img)) {
|
||||
// Store timestamp
|
||||
listener->ts = img->ts;
|
||||
|
||||
@@ -131,7 +131,7 @@ static void *video_thread_function(void *data)
|
||||
if (dt_us < fps_period_us) {
|
||||
usleep(fps_period_us - dt_us);
|
||||
} else {
|
||||
//fprintf(stderr, "[%s] desired %i fps, only managing %.1f fps\n", print_tag, vid->fps, 1000000.f / dt_us);
|
||||
fprintf(stderr, "[%s] desired %i fps, only managing %.1f fps\n", print_tag, vid->fps, 1000000.f / dt_us);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ PRINT_CONFIG_VAR(VIEWVIDEO_RTP_TIME_INC)
|
||||
#ifdef VIDEO_THREAD_SHOT_PATH
|
||||
#define VIEWVIDEO_SHOT_PATH VIDEO_THREAD_SHOT_PATH
|
||||
#else
|
||||
#define VIEWVIDEO_SHOT_PATH /data/video/images
|
||||
#define VIEWVIDEO_SHOT_PATH /data/ftp/internal_000/images
|
||||
#endif
|
||||
#endif
|
||||
PRINT_CONFIG_VAR(VIEWVIDEO_SHOT_PATH)
|
||||
@@ -87,7 +87,7 @@ PRINT_CONFIG_VAR(VIEWVIDEO_FPS)
|
||||
#ifndef VIEWVIDEO_NICE_LEVEL
|
||||
#define VIEWVIDEO_NICE_LEVEL 5
|
||||
#endif
|
||||
PRINT_CONFIG_VAR(VIEWVIDEO_FPS)
|
||||
PRINT_CONFIG_VAR(VIEWVIDEO_NICE_LEVEL)
|
||||
|
||||
// Check if we are using netcat instead of RTP/UDP
|
||||
#ifndef VIEWVIDEO_USE_NETCAT
|
||||
@@ -102,7 +102,8 @@ PRINT_CONFIG_VAR(VIEWVIDEO_FPS)
|
||||
#include <sys/wait.h>
|
||||
PRINT_CONFIG_MSG("[viewvideo] Using netcat.")
|
||||
#else
|
||||
struct UdpSocket video_sock;
|
||||
struct UdpSocket video_sock1;
|
||||
struct UdpSocket video_sock2;
|
||||
PRINT_CONFIG_MSG("[viewvideo] Using RTP/UDP stream.")
|
||||
PRINT_CONFIG_VAR(VIEWVIDEO_USE_RTP)
|
||||
#endif
|
||||
@@ -110,6 +111,7 @@ PRINT_CONFIG_VAR(VIEWVIDEO_USE_RTP)
|
||||
/* These are defined with configure */
|
||||
PRINT_CONFIG_VAR(VIEWVIDEO_HOST)
|
||||
PRINT_CONFIG_VAR(VIEWVIDEO_PORT_OUT)
|
||||
PRINT_CONFIG_VAR(VIEWVIDEO_PORT2_OUT)
|
||||
|
||||
// Initialize the viewvideo structure with the defaults
|
||||
struct viewvideo_t viewvideo = {
|
||||
@@ -121,12 +123,16 @@ struct viewvideo_t viewvideo = {
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(VIEWVIDEO_CAMERA) && defined(VIEWVIDEO_CAMERA2) && VIEWVIDEO_BROADCAST == true
|
||||
#warning Broadcasting dual video stream causes too much udp overhead resulting in unstable streaming
|
||||
#warning We recomment using a static VIEWVIDEO_HOST address and VIEWVIDEO_BROADCAST to false
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Handles all the video streaming and saving of the image shots
|
||||
* This is a sepereate thread, so it needs to be thread safe!
|
||||
* This is a separate thread, so it needs to be thread safe!
|
||||
*/
|
||||
struct image_t *viewvideo_function(struct image_t *img);
|
||||
struct image_t *viewvideo_function(struct image_t *img)
|
||||
static struct image_t *viewvideo_function(struct UdpSocket *socket, struct image_t *img)
|
||||
{
|
||||
// Resize image if needed
|
||||
struct image_t img_small;
|
||||
@@ -178,10 +184,9 @@ struct image_t *viewvideo_function(struct image_t *img)
|
||||
}
|
||||
#else
|
||||
if (viewvideo.use_rtp) {
|
||||
|
||||
// Send image with RTP
|
||||
rtp_frame_send(
|
||||
&video_sock, // UDP socket
|
||||
socket, // UDP socket
|
||||
&img_jpeg,
|
||||
0, // Format 422
|
||||
VIEWVIDEO_QUALITY_FACTOR, // Jpeg-Quality
|
||||
@@ -207,6 +212,20 @@ struct image_t *viewvideo_function(struct image_t *img)
|
||||
return NULL; // No new images were created
|
||||
}
|
||||
|
||||
#ifdef VIEWVIDEO_CAMERA
|
||||
static struct image_t *viewvideo_function1(struct image_t *img)
|
||||
{
|
||||
return viewvideo_function(&video_sock1, img);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VIEWVIDEO_CAMERA2
|
||||
static struct image_t *viewvideo_function2(struct image_t *img)
|
||||
{
|
||||
return viewvideo_function(&video_sock2, img);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize the view video
|
||||
*/
|
||||
@@ -214,9 +233,6 @@ void viewvideo_init(void)
|
||||
{
|
||||
char save_name[512];
|
||||
|
||||
struct video_listener *listener = cv_add_to_device_async(&VIEWVIDEO_CAMERA, viewvideo_function, VIEWVIDEO_NICE_LEVEL);
|
||||
listener->maximum_fps = VIEWVIDEO_FPS;
|
||||
|
||||
viewvideo.is_streaming = true;
|
||||
|
||||
#if VIEWVIDEO_USE_NETCAT
|
||||
@@ -237,8 +253,21 @@ void viewvideo_init(void)
|
||||
}
|
||||
#else
|
||||
// Open udp socket
|
||||
udp_socket_create(&video_sock, STRINGIFY(VIEWVIDEO_HOST), VIEWVIDEO_PORT_OUT, -1, VIEWVIDEO_BROADCAST);
|
||||
#ifdef VIEWVIDEO_CAMERA1
|
||||
if (udp_socket_create(&video_sock1, STRINGIFY(VIEWVIDEO_HOST), VIEWVIDEO_PORT_OUT, -1, VIEWVIDEO_BROADCAST)) {
|
||||
printf("[viewvideo]: failed to open view video socket, HOST=%s, port=%d\n", STRINGIFY(VIEWVIDEO_HOST),
|
||||
VIEWVIDEO_PORT_OUT);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VIEWVIDEO_CAMERA2
|
||||
if (udp_socket_create(&video_sock2, STRINGIFY(VIEWVIDEO_HOST), VIEWVIDEO_PORT2_OUT, -1, VIEWVIDEO_BROADCAST)) {
|
||||
printf("[viewvideo]: failed to open view video socket, HOST=%s, port=%d\n", STRINGIFY(VIEWVIDEO_HOST),
|
||||
VIEWVIDEO_PORT2_OUT);
|
||||
}
|
||||
#endif
|
||||
|
||||
// todo: check what this is for!
|
||||
// Create an SDP file for the streaming
|
||||
sprintf(save_name, "%s/stream.sdp", STRINGIFY(VIEWVIDEO_SHOT_PATH));
|
||||
FILE *fp = fopen(save_name, "w");
|
||||
@@ -251,5 +280,18 @@ void viewvideo_init(void)
|
||||
printf("[viewvideo] Failed to create SDP file.\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef VIEWVIDEO_CAMERA
|
||||
struct video_listener *listener1 = cv_add_to_device_async(&VIEWVIDEO_CAMERA, viewvideo_function1,
|
||||
VIEWVIDEO_NICE_LEVEL);
|
||||
listener1->maximum_fps = VIEWVIDEO_FPS;
|
||||
fprintf(stderr, "[viewvideo] Added asynchronous video streamer lister for CAMERA1\n");
|
||||
#endif
|
||||
|
||||
#ifdef VIEWVIDEO_CAMERA2
|
||||
struct video_listener *listener2 = cv_add_to_device_async(&VIEWVIDEO_CAMERA2, viewvideo_function2,
|
||||
VIEWVIDEO_NICE_LEVEL);
|
||||
listener2->maximum_fps = VIEWVIDEO_FPS;
|
||||
fprintf(stderr, "[viewvideo] Added asynchronous video streamer lister for CAMERA2\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
v=0
|
||||
m=video 6000 RTP/AVP 26
|
||||
c=IN IP4 0.0.0.0
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
import cv2
|
||||
import sys
|
||||
import getopt
|
||||
import re
|
||||
from os import path, getenv
|
||||
|
||||
PPRZ_SRC = getenv("PAPARAZZI_SRC", path.normpath(path.join(path.dirname(path.abspath(__file__)), '../../../')))
|
||||
@@ -10,9 +12,41 @@ sys.path.append(PPRZ_SRC + "/sw/ext/pprzlink/lib/v1.0/python")
|
||||
from pprzlink.ivy import IvyMessagesInterface
|
||||
from pprzlink.message import PprzMessage
|
||||
|
||||
def Usage(scmd):
|
||||
lpathitem = scmd.split('/')
|
||||
fmt = '''Usage: %s [-h | --help] [-p PORT | --port=PORT] [-s SCALE | --scale=SCALE] [-r ROTATE | --rotate=ROTATE] []
|
||||
where
|
||||
\t-h | --help print this message
|
||||
\t-p PORT | --port=PORT where PORT is the port number to open for the RTP stream (5000 or 6000)
|
||||
\t-s SCALE | --scale=SCALE where SCALE is the scaling factor to apply to the incoming video stream (default: 1)
|
||||
\t-r ROTATE | --rotate=ROTATE where ROTATE is the number of clockwise 90deg rotations to apply to the stream [0-3] (default: 0)
|
||||
'''
|
||||
print(fmt % lpathitem[-1])
|
||||
|
||||
def GetOptions():
|
||||
options = {'port':[], 'scale':[], 'rotate':[]}
|
||||
try:
|
||||
optlist, left_args = getopt.getopt(sys.argv[1:],'h:p:s:r:', ['help', 'port=', 'scale=', 'rotate='])
|
||||
except getopt.GetoptError:
|
||||
# print help information and exit:
|
||||
Usage(sys.argv[0])
|
||||
sys.exit(2)
|
||||
for o, a in optlist:
|
||||
if o in ("-h", "--help"):
|
||||
Usage(sys.argv[0])
|
||||
sys.exit()
|
||||
elif o in ("-p", "--port"):
|
||||
options['port'].append(int(a))
|
||||
elif o in ("-s", "--scale"):
|
||||
options['scale'].append(float(a))
|
||||
elif o in ("-r", "--rotate"):
|
||||
options['rotate'].append(int(a))
|
||||
|
||||
return options
|
||||
|
||||
class RtpViewer:
|
||||
running = False
|
||||
scale = 1
|
||||
rotate = 0
|
||||
frame = None
|
||||
mouse = dict()
|
||||
@@ -60,6 +94,10 @@ class RtpViewer:
|
||||
# Draw a rectangle indicating the region of interest
|
||||
cv2.rectangle(self.frame, self.mouse['start'], self.mouse['now'], (0, 255, 0), 2)
|
||||
|
||||
if self.scale != 1:
|
||||
h, w = self.frame.shape[:2]
|
||||
self.frame = cv2.resize(self.frame, (int(self.scale * w), int(self.scale * h)))
|
||||
|
||||
# Show the image in a window
|
||||
cv2.imshow('rtp', self.frame)
|
||||
|
||||
@@ -72,7 +110,7 @@ class RtpViewer:
|
||||
self.mouse['start'] = None
|
||||
|
||||
def on_mouse(self, event, x, y, flags, param):
|
||||
if event == cv2.EVENT_LBUTTONDOWN and self.rotate == 0:
|
||||
if event == cv2.EVENT_LBUTTONDOWN and self.rotate == 0 and False:
|
||||
self.mouse['start'] = (x, y)
|
||||
|
||||
if event == cv2.EVENT_RBUTTONDOWN:
|
||||
@@ -110,11 +148,31 @@ class RtpViewer:
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
viewer = RtpViewer("rtp_stream.sdp")
|
||||
import sys
|
||||
import os
|
||||
|
||||
options = GetOptions()
|
||||
if not options['port']:
|
||||
Usage(sys.argv[0])
|
||||
filename = os.path.dirname(os.path.abspath(__file__)) + "/rtp_" + str(options['port'][0]) + ".sdp"
|
||||
print(filename)
|
||||
|
||||
#set defaults
|
||||
if not options['scale']:
|
||||
options['scale'][0] = 1.
|
||||
if not options['rotate']:
|
||||
options['rotate'][0] = 0
|
||||
|
||||
print(options['scale'][0])
|
||||
print(options['rotate'][0])
|
||||
|
||||
viewer = RtpViewer(filename)
|
||||
viewer.scale = options['scale'][0]
|
||||
viewer.rotate = options['rotate'][0]
|
||||
|
||||
if not viewer.cap.isOpened():
|
||||
viewer.cleanup()
|
||||
sys.exit("Can't open video stream")
|
||||
raise IOError("Can't open video stream")
|
||||
|
||||
viewer.run()
|
||||
viewer.cleanup()
|
||||
|
||||
Reference in New Issue
Block a user