mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Add support for NGINX VOD Module
This commit is contained in:
parent
a4e6d9ed9a
commit
aab6a00e4c
5
Makefile
5
Makefile
@ -14,8 +14,11 @@ amd64_wheels:
|
|||||||
amd64_ffmpeg:
|
amd64_ffmpeg:
|
||||||
docker build --tag blakeblackshear/frigate-ffmpeg:1.1.0-amd64 --file docker/Dockerfile.ffmpeg.amd64 .
|
docker build --tag blakeblackshear/frigate-ffmpeg:1.1.0-amd64 --file docker/Dockerfile.ffmpeg.amd64 .
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
docker buildx build --platform linux/arm/v7,linux/arm64/v8,linux/amd64 --tag blakeblackshear/frigate-nginx:1.0.0 --file docker/Dockerfile.nginx .
|
||||||
|
|
||||||
amd64_frigate: version web
|
amd64_frigate: version web
|
||||||
docker build --tag frigate-base --build-arg ARCH=amd64 --build-arg FFMPEG_VERSION=1.1.0 --build-arg WHEELS_VERSION=1.0.3 --file docker/Dockerfile.base .
|
docker build --tag frigate-base --build-arg ARCH=amd64 --build-arg FFMPEG_VERSION=1.1.0 --build-arg WHEELS_VERSION=1.0.3 --build-arg NGINX_VERSION=1.0.0 --file docker/Dockerfile.base .
|
||||||
docker build --tag frigate --file docker/Dockerfile.amd64 .
|
docker build --tag frigate --file docker/Dockerfile.amd64 .
|
||||||
|
|
||||||
amd64_all: amd64_wheels amd64_ffmpeg amd64_frigate
|
amd64_all: amd64_wheels amd64_ffmpeg amd64_frigate
|
||||||
|
@ -23,7 +23,7 @@ services:
|
|||||||
- "5000:5000"
|
- "5000:5000"
|
||||||
- "5001:5001"
|
- "5001:5001"
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
command: /bin/sh -c "sudo service nginx start; while sleep 1000; do :; done"
|
command: /bin/sh -c "sudo /usr/local/nginx/sbin/nginx; while sleep 1000; do :; done"
|
||||||
mqtt:
|
mqtt:
|
||||||
container_name: mqtt
|
container_name: mqtt
|
||||||
image: eclipse-mosquitto:1.6
|
image: eclipse-mosquitto:1.6
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
ARG ARCH=amd64
|
ARG ARCH=amd64
|
||||||
ARG WHEELS_VERSION
|
ARG WHEELS_VERSION
|
||||||
ARG FFMPEG_VERSION
|
ARG FFMPEG_VERSION
|
||||||
|
ARG NGINX_VERSION
|
||||||
FROM blakeblackshear/frigate-wheels:${WHEELS_VERSION}-${ARCH} as wheels
|
FROM blakeblackshear/frigate-wheels:${WHEELS_VERSION}-${ARCH} as wheels
|
||||||
FROM blakeblackshear/frigate-ffmpeg:${FFMPEG_VERSION}-${ARCH} as ffmpeg
|
FROM blakeblackshear/frigate-ffmpeg:${FFMPEG_VERSION}-${ARCH} as ffmpeg
|
||||||
|
FROM blakeblackshear/frigate-nginx:${NGINX_VERSION} as nginx
|
||||||
FROM frigate-web as web
|
FROM frigate-web as web
|
||||||
|
|
||||||
FROM ubuntu:20.04
|
FROM ubuntu:20.04
|
||||||
@ -18,16 +20,13 @@ ENV DEBIAN_FRONTEND=noninteractive
|
|||||||
# Install packages for apt repo
|
# Install packages for apt repo
|
||||||
RUN apt-get -qq update \
|
RUN apt-get -qq update \
|
||||||
&& apt-get upgrade -y \
|
&& apt-get upgrade -y \
|
||||||
&& apt-get -qq install --no-install-recommends -y \
|
&& apt-get -qq install --no-install-recommends -y gnupg wget unzip tzdata libxml2 \
|
||||||
gnupg wget unzip tzdata nginx libnginx-mod-rtmp \
|
&& apt-get -qq install --no-install-recommends -y python3-pip \
|
||||||
&& apt-get -qq install --no-install-recommends -y \
|
|
||||||
python3-pip \
|
|
||||||
&& pip3 install -U /wheels/*.whl \
|
&& pip3 install -U /wheels/*.whl \
|
||||||
&& APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn apt-key adv --fetch-keys https://packages.cloud.google.com/apt/doc/apt-key.gpg \
|
&& APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn apt-key adv --fetch-keys https://packages.cloud.google.com/apt/doc/apt-key.gpg \
|
||||||
&& echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" > /etc/apt/sources.list.d/coral-edgetpu.list \
|
&& echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" > /etc/apt/sources.list.d/coral-edgetpu.list \
|
||||||
&& echo "libedgetpu1-max libedgetpu/accepted-eula select true" | debconf-set-selections \
|
&& echo "libedgetpu1-max libedgetpu/accepted-eula select true" | debconf-set-selections \
|
||||||
&& apt-get -qq update && apt-get -qq install --no-install-recommends -y \
|
&& apt-get -qq update && apt-get -qq install --no-install-recommends -y libedgetpu1-max=15.0 \
|
||||||
libedgetpu1-max=15.0 \
|
|
||||||
&& rm -rf /var/lib/apt/lists/* /wheels \
|
&& rm -rf /var/lib/apt/lists/* /wheels \
|
||||||
&& (apt-get autoremove -y; apt-get autoclean -y)
|
&& (apt-get autoremove -y; apt-get autoclean -y)
|
||||||
|
|
||||||
@ -39,7 +38,8 @@ RUN pip3 install \
|
|||||||
gevent \
|
gevent \
|
||||||
gevent-websocket
|
gevent-websocket
|
||||||
|
|
||||||
COPY nginx/nginx.conf /etc/nginx/nginx.conf
|
COPY --from=nginx /usr/local/nginx/ /usr/local/nginx/
|
||||||
|
COPY nginx/nginx.conf /usr/local/nginx/conf/nginx.conf
|
||||||
|
|
||||||
# get model and labels
|
# get model and labels
|
||||||
COPY labelmap.txt /labelmap.txt
|
COPY labelmap.txt /labelmap.txt
|
||||||
|
46
docker/Dockerfile.nginx
Normal file
46
docker/Dockerfile.nginx
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
FROM ubuntu:20.04 AS base
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
RUN apt-get -yqq update && \
|
||||||
|
apt-get install -yq --no-install-recommends ca-certificates expat libgomp1 && \
|
||||||
|
apt-get autoremove -y && \
|
||||||
|
apt-get clean -y
|
||||||
|
|
||||||
|
FROM base as build
|
||||||
|
|
||||||
|
ARG NGINX_VERSION=1.18.0
|
||||||
|
ARG VOD_MODULE_VERSION=1.28
|
||||||
|
ARG RTMP_MODULE_VERSION=1.2.1
|
||||||
|
|
||||||
|
RUN cp /etc/apt/sources.list /etc/apt/sources.list~ \
|
||||||
|
&& sed -Ei 's/^# deb-src /deb-src /' /etc/apt/sources.list \
|
||||||
|
&& apt-get update
|
||||||
|
|
||||||
|
RUN apt-get -yqq build-dep nginx
|
||||||
|
|
||||||
|
RUN apt-get -yqq install --no-install-recommends curl \
|
||||||
|
&& mkdir /tmp/nginx \
|
||||||
|
&& curl -sL https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz | tar -C /tmp/nginx -zx --strip-components=1 \
|
||||||
|
&& mkdir /tmp/nginx-vod-module \
|
||||||
|
&& curl -sL https://github.com/kaltura/nginx-vod-module/archive/refs/tags/${VOD_MODULE_VERSION}.tar.gz | tar -C /tmp/nginx-vod-module -zx --strip-components=1 \
|
||||||
|
&& mkdir /tmp/nginx-rtmp-module \
|
||||||
|
&& curl -sL https://github.com/arut/nginx-rtmp-module/archive/refs/tags/v${RTMP_MODULE_VERSION}.tar.gz | tar -C /tmp/nginx-rtmp-module -zx --strip-components=1
|
||||||
|
|
||||||
|
WORKDIR /tmp/nginx
|
||||||
|
|
||||||
|
RUN ./configure --prefix=/usr/local/nginx \
|
||||||
|
--with-file-aio \
|
||||||
|
--with-http_sub_module \
|
||||||
|
--with-http_ssl_module \
|
||||||
|
--with-threads \
|
||||||
|
--add-module=../nginx-vod-module \
|
||||||
|
--add-module=../nginx-rtmp-module \
|
||||||
|
--with-cc-opt="-O3 -Wno-error=implicit-fallthrough"
|
||||||
|
|
||||||
|
RUN make && make install
|
||||||
|
RUN rm -rf /usr/local/nginx/html /usr/local/nginx/conf/*.default
|
||||||
|
|
||||||
|
FROM base
|
||||||
|
COPY --from=build /usr/local/nginx /usr/local/nginx
|
||||||
|
ENTRYPOINT ["/usr/local/nginx/sbin/nginx"]
|
||||||
|
CMD ["-g", "daemon off;"]
|
@ -316,7 +316,11 @@ class FrigateApp:
|
|||||||
server = pywsgi.WSGIServer(
|
server = pywsgi.WSGIServer(
|
||||||
("127.0.0.1", 5001), self.flask_app, handler_class=WebSocketHandler
|
("127.0.0.1", 5001), self.flask_app, handler_class=WebSocketHandler
|
||||||
)
|
)
|
||||||
server.serve_forever()
|
|
||||||
|
try:
|
||||||
|
server.serve_forever()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
|
||||||
self.stop()
|
self.stop()
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import base64
|
import base64
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
|
import glob
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
@ -23,7 +24,7 @@ from flask_sockets import Sockets
|
|||||||
from peewee import SqliteDatabase, operator, fn, DoesNotExist
|
from peewee import SqliteDatabase, operator, fn, DoesNotExist
|
||||||
from playhouse.shortcuts import model_to_dict
|
from playhouse.shortcuts import model_to_dict
|
||||||
|
|
||||||
from frigate.const import CLIPS_DIR
|
from frigate.const import CLIPS_DIR, RECORD_DIR
|
||||||
from frigate.models import Event
|
from frigate.models import Event
|
||||||
from frigate.stats import stats_snapshot
|
from frigate.stats import stats_snapshot
|
||||||
from frigate.util import calculate_region
|
from frigate.util import calculate_region
|
||||||
@ -186,13 +187,15 @@ def event(id):
|
|||||||
except DoesNotExist:
|
except DoesNotExist:
|
||||||
return "Event not found", 404
|
return "Event not found", 404
|
||||||
|
|
||||||
@bp.route('/events/<id>', methods=('DELETE',))
|
|
||||||
|
@bp.route("/events/<id>", methods=("DELETE",))
|
||||||
def delete_event(id):
|
def delete_event(id):
|
||||||
try:
|
try:
|
||||||
event = Event.get(Event.id == id)
|
event = Event.get(Event.id == id)
|
||||||
except DoesNotExist:
|
except DoesNotExist:
|
||||||
return make_response(jsonify({"success": False, "message": "Event" + id + " not found"}),404)
|
return make_response(
|
||||||
|
jsonify({"success": False, "message": "Event" + id + " not found"}), 404
|
||||||
|
)
|
||||||
|
|
||||||
media_name = f"{event.camera}-{event.id}"
|
media_name = f"{event.camera}-{event.id}"
|
||||||
if event.has_snapshot:
|
if event.has_snapshot:
|
||||||
@ -203,12 +206,12 @@ def delete_event(id):
|
|||||||
media.unlink(missing_ok=True)
|
media.unlink(missing_ok=True)
|
||||||
|
|
||||||
event.delete_instance()
|
event.delete_instance()
|
||||||
return make_response(jsonify({"success": True, "message": "Event" + id + " deleted"}),200)
|
return make_response(
|
||||||
|
jsonify({"success": True, "message": "Event" + id + " deleted"}), 200
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/events/<id>/thumbnail.jpg")
|
||||||
|
|
||||||
@bp.route('/events/<id>/thumbnail.jpg')
|
|
||||||
def event_thumbnail(id):
|
def event_thumbnail(id):
|
||||||
format = request.args.get("format", "ios")
|
format = request.args.get("format", "ios")
|
||||||
thumbnail_bytes = None
|
thumbnail_bytes = None
|
||||||
@ -446,10 +449,37 @@ def latest_frame(camera_name):
|
|||||||
return "Camera named {} not found".format(camera_name), 404
|
return "Camera named {} not found".format(camera_name), 404
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/vod/<path:path>")
|
||||||
|
def vod(path):
|
||||||
|
if not os.path.isdir(f"{RECORD_DIR}/{path}"):
|
||||||
|
return "Recordings not found.", 404
|
||||||
|
|
||||||
|
files = glob.glob(f"{RECORD_DIR}/{path}/*.mp4")
|
||||||
|
files.sort()
|
||||||
|
|
||||||
|
clips = []
|
||||||
|
durations = []
|
||||||
|
for filename in files:
|
||||||
|
clips.append({"type": "source", "path": filename})
|
||||||
|
video = cv2.VideoCapture(filename)
|
||||||
|
duration = int(
|
||||||
|
video.get(cv2.CAP_PROP_FRAME_COUNT) / video.get(cv2.CAP_PROP_FPS) * 1000
|
||||||
|
)
|
||||||
|
durations.append(duration)
|
||||||
|
|
||||||
|
return jsonify(
|
||||||
|
{
|
||||||
|
"discontinuity": False,
|
||||||
|
"durations": durations,
|
||||||
|
"sequences": [{"clips": clips}],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def imagestream(detected_frames_processor, camera_name, fps, height, draw_options):
|
def imagestream(detected_frames_processor, camera_name, fps, height, draw_options):
|
||||||
while True:
|
while True:
|
||||||
# max out at specified FPS
|
# max out at specified FPS
|
||||||
gevent.sleep(1/fps)
|
gevent.sleep(1 / fps)
|
||||||
frame = detected_frames_processor.get_current_frame(camera_name, draw_options)
|
frame = detected_frames_processor.get_current_frame(camera_name, draw_options)
|
||||||
if frame is None:
|
if frame is None:
|
||||||
frame = np.zeros((height, int(height * 16 / 9), 3), np.uint8)
|
frame = np.zeros((height, int(height * 16 / 9), 3), np.uint8)
|
||||||
|
@ -35,7 +35,7 @@ def log_process(log_queue):
|
|||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
record = log_queue.get(timeout=5)
|
record = log_queue.get(timeout=5)
|
||||||
except queue.Empty:
|
except (queue.Empty, KeyboardInterrupt):
|
||||||
continue
|
continue
|
||||||
logger = logging.getLogger(record.name)
|
logger = logging.getLogger(record.name)
|
||||||
logger.handle(record)
|
logger.handle(record)
|
||||||
|
@ -1,23 +1,24 @@
|
|||||||
worker_processes 1;
|
worker_processes 1;
|
||||||
|
|
||||||
error_log /var/log/nginx/error.log warn;
|
error_log /usr/local/nginx/logs/error.log warn;
|
||||||
pid /var/run/nginx.pid;
|
pid /var/run/nginx.pid;
|
||||||
|
|
||||||
load_module "modules/ngx_rtmp_module.so";
|
# load_module "modules/ngx_rtmp_module.so";
|
||||||
|
# load_module "modules/ngx_http_vod_module.so";
|
||||||
|
|
||||||
events {
|
events {
|
||||||
worker_connections 1024;
|
worker_connections 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
http {
|
http {
|
||||||
include /etc/nginx/mime.types;
|
include mime.types;
|
||||||
default_type application/octet-stream;
|
default_type application/octet-stream;
|
||||||
|
|
||||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
'$status $body_bytes_sent "$http_referer" '
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
|
||||||
access_log /var/log/nginx/access.log main;
|
access_log /usr/local/nginx/logs/access.log main;
|
||||||
|
|
||||||
sendfile on;
|
sendfile on;
|
||||||
|
|
||||||
@ -37,6 +38,39 @@ http {
|
|||||||
server {
|
server {
|
||||||
listen 5000;
|
listen 5000;
|
||||||
|
|
||||||
|
# vod settings
|
||||||
|
vod_mode mapped;
|
||||||
|
vod_max_mapping_response_size 1m;
|
||||||
|
vod_upstream_location /api;
|
||||||
|
vod_last_modified 'Sun, 19 Nov 2000 08:52:00 GMT';
|
||||||
|
vod_last_modified_types *;
|
||||||
|
|
||||||
|
# vod caches
|
||||||
|
vod_metadata_cache metadata_cache 512m;
|
||||||
|
vod_response_cache response_cache 128m;
|
||||||
|
vod_mapping_cache mapping_cache 5m;
|
||||||
|
|
||||||
|
# gzip manifests
|
||||||
|
gzip on;
|
||||||
|
gzip_types application/vnd.apple.mpegurl;
|
||||||
|
|
||||||
|
# file handle caching / aio
|
||||||
|
open_file_cache max=1000 inactive=5m;
|
||||||
|
open_file_cache_valid 2m;
|
||||||
|
open_file_cache_min_uses 1;
|
||||||
|
open_file_cache_errors on;
|
||||||
|
aio on;
|
||||||
|
|
||||||
|
location /vod/ {
|
||||||
|
vod hls;
|
||||||
|
|
||||||
|
add_header Access-Control-Allow-Headers '*';
|
||||||
|
add_header Access-Control-Expose-Headers 'Server,range,Content-Length,Content-Range';
|
||||||
|
add_header Access-Control-Allow-Methods 'GET, HEAD, OPTIONS';
|
||||||
|
add_header Access-Control-Allow-Origin '*';
|
||||||
|
expires 100d;
|
||||||
|
}
|
||||||
|
|
||||||
location /stream/ {
|
location /stream/ {
|
||||||
add_header 'Cache-Control' 'no-cache';
|
add_header 'Cache-Control' 'no-cache';
|
||||||
add_header 'Access-Control-Allow-Origin' "$http_origin" always;
|
add_header 'Access-Control-Allow-Origin' "$http_origin" always;
|
||||||
|
Loading…
Reference in New Issue
Block a user