Add support for RTMP with custom url formatters

This commit is contained in:
Kyle Niewiada 2019-11-29 09:03:05 -05:00
parent 249f3b347e
commit fb51c594a2
2 changed files with 72 additions and 17 deletions

View File

@ -22,6 +22,12 @@ cameras:
# urlformat: rtmp://{host}:{port}{path}&user={user}&password={password} # urlformat: rtmp://{host}:{port}{path}&user={user}&password={password}
################
## Optional URL format. Specifying this will override the default RTSP URL format.
## Some cameras support the RTMP protocol which may give better performance.
################
# urlformat: rtmp://{host}:{port}{path}&user={user}&password={password}
################ ################
## Optional mask. Must be the same dimensions as your video feed. ## Optional mask. Must be the same dimensions as your video feed.
## The mask works by looking at the bottom center of the bounding box for the detected ## The mask works by looking at the bottom center of the bounding box for the detected
@ -70,6 +76,29 @@ cameras:
################ ################
# ffmpeg_output_args: [] # ffmpeg_output_args: []
################
## RTMP supports all RTSP arguments
## The RTMP config uses different ffmpeg arguments to make it compatible with frigate.
################
rtmp:
user: viewer
host: 10.0.10.11
port: 1935
# values that begin with a "$" will be replaced with environment variable
password: $RTSP_PASSWORD
path: /cam/realmonitor?channel=1&subtype=2
rtmp:
user: viewer
host: 10.0.10.12
port: 1935
# values that begin with a "$" will be replaced with environment variable
password: $RTSP_PASSWORD
path: /cam/realmonitor?channel=1&subtype=2
urlformat: rtmp://{host}:{port}{path}&user={user}&password={password}
regions: regions:
- size: 350 - size: 350
x_offset: 0 x_offset: 0

View File

@ -4,6 +4,7 @@ import datetime
import cv2 import cv2
import threading import threading
import ctypes import ctypes
import logging
import multiprocessing as mp import multiprocessing as mp
import subprocess as sp import subprocess as sp
import numpy as np import numpy as np
@ -46,10 +47,10 @@ class FrameTracker(threading.Thread):
if (now - k) > 2: if (now - k) > 2:
del self.recent_frames[k] del self.recent_frames[k]
def get_frame_shape(rtsp_url): def get_frame_shape(stream_url):
# capture a single frame and check the frame shape so the correct array # capture a single frame and check the frame shape so the correct array
# size can be allocated in memory # size can be allocated in memory
video = cv2.VideoCapture(rtsp_url) video = cv2.VideoCapture(stream_url)
ret, frame = video.read() ret, frame = video.read()
frame_shape = frame.shape frame_shape = frame.shape
video.release() video.release()
@ -62,6 +63,13 @@ def get_rtsp_url(rtsp_config):
return urlformat.format(host=rtsp_config['host'], port=rtsp_config['port'], return urlformat.format(host=rtsp_config['host'], port=rtsp_config['port'],
path=rtsp_config['path'], user=rtsp_config['user'], password=rtsp_config['password']) path=rtsp_config['path'], user=rtsp_config['user'], password=rtsp_config['password'])
def get_rtmp_url(rtmp_config):
if (rtmp_config['password'].startswith('$')):
rtmp_config['password'] = os.getenv(rtmp_config['password'][1:])
urlformat = rtmp_config.get('urlformat', 'rtmp://{user}:{password}@{host}:{port}{path}')
return urlformat.format(host=rtmp_config['host'], port=rtmp_config['port'],
path=rtmp_config['path'], user=rtmp_config['user'], password=rtmp_config['password'])
class CameraWatchdog(threading.Thread): class CameraWatchdog(threading.Thread):
def __init__(self, camera): def __init__(self, camera):
threading.Thread.__init__(self) threading.Thread.__init__(self)
@ -119,10 +127,9 @@ class Camera:
self.config = config self.config = config
self.detected_objects = [] self.detected_objects = []
self.recent_frames = {} self.recent_frames = {}
self.rtsp_url = get_rtsp_url(self.config['rtsp']) if ('rtsp' in config):
self.take_frame = self.config.get('take_frame', 1) print('Found rtsp camera config.')
self.ffmpeg_log_level = self.config.get('ffmpeg_log_level', 'panic') self.stream_url = get_rtsp_url(self.config['rtsp'])
self.ffmpeg_hwaccel_args = self.config.get('ffmpeg_hwaccel_args', [])
self.ffmpeg_input_args = self.config.get('ffmpeg_input_args', [ self.ffmpeg_input_args = self.config.get('ffmpeg_input_args', [
'-avoid_negative_ts', 'make_zero', '-avoid_negative_ts', 'make_zero',
'-fflags', 'nobuffer', '-fflags', 'nobuffer',
@ -134,12 +141,31 @@ class Camera:
'-stimeout', '5000000', '-stimeout', '5000000',
'-use_wallclock_as_timestamps', '1' '-use_wallclock_as_timestamps', '1'
]) ])
elif ('rtmp' in config):
print('Found rtmp camera config.')
self.stream_url = get_rtmp_url(self.config['rtmp'])
self.ffmpeg_input_args = self.config.get('ffmpeg_input_args', [
'-avoid_negative_ts', 'make_zero',
'-fflags', 'nobuffer',
'-flags', 'low_delay',
'-strict', 'experimental',
'-fflags', '+genpts+discardcorrupt',
'-vsync', 'drop',
'-use_wallclock_as_timestamps', '1'
])
else:
print('No valid camera config found.')
self.take_frame = self.config.get('take_frame', 1)
self.ffmpeg_log_level = self.config.get('ffmpeg_log_level', 'info')
self.ffmpeg_hwaccel_args = self.config.get('ffmpeg_hwaccel_args', [])
self.ffmpeg_output_args = self.config.get('ffmpeg_output_args', [ self.ffmpeg_output_args = self.config.get('ffmpeg_output_args', [
'-f', 'rawvideo', '-f', 'rawvideo',
'-pix_fmt', 'rgb24' '-pix_fmt', 'rgb24'
]) ])
self.regions = self.config['regions'] self.regions = self.config['regions']
self.frame_shape = get_frame_shape(self.rtsp_url) self.frame_shape = get_frame_shape(self.stream_url)
self.frame_size = self.frame_shape[0] * self.frame_shape[1] * self.frame_shape[2] self.frame_size = self.frame_shape[0] * self.frame_shape[1] * self.frame_shape[2]
self.mqtt_client = mqtt_client self.mqtt_client = mqtt_client
self.mqtt_topic_prefix = '{}/{}'.format(mqtt_prefix, self.name) self.mqtt_topic_prefix = '{}/{}'.format(mqtt_prefix, self.name)
@ -243,7 +269,7 @@ class Camera:
ffmpeg_global_args + ffmpeg_global_args +
self.ffmpeg_hwaccel_args + self.ffmpeg_hwaccel_args +
self.ffmpeg_input_args + self.ffmpeg_input_args +
['-i', self.rtsp_url] + ['-i', self.stream_url] +
self.ffmpeg_output_args + self.ffmpeg_output_args +
['pipe:']) ['pipe:'])