mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-08-18 13:47:20 +02:00
Add support for RTMP with custom url formatters
This commit is contained in:
parent
249f3b347e
commit
fb51c594a2
@ -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
|
||||||
|
@ -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:'])
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user