mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-14 15:15:22 +03:00
Install multiple ffmpeg versions and add config to make it configurable
This commit is contained in:
parent
641f1244dd
commit
95800ad1e3
@ -201,7 +201,7 @@ ENV ALLOW_RESET=True
|
|||||||
# Disable tokenizer parallelism warning
|
# Disable tokenizer parallelism warning
|
||||||
ENV TOKENIZERS_PARALLELISM=true
|
ENV TOKENIZERS_PARALLELISM=true
|
||||||
|
|
||||||
ENV PATH="/usr/lib/btbn-ffmpeg/bin:/usr/local/go2rtc/bin:/usr/local/tempio/bin:/usr/local/nginx/sbin:${PATH}"
|
ENV ENV LIBAVFORMAT_VERSION_MAJOR=60
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
RUN --mount=type=bind,source=docker/main/install_deps.sh,target=/deps/install_deps.sh \
|
RUN --mount=type=bind,source=docker/main/install_deps.sh,target=/deps/install_deps.sh \
|
||||||
|
|||||||
@ -39,18 +39,26 @@ apt-get -qq install --no-install-recommends --no-install-suggests -y \
|
|||||||
|
|
||||||
# btbn-ffmpeg -> amd64
|
# btbn-ffmpeg -> amd64
|
||||||
if [[ "${TARGETARCH}" == "amd64" ]]; then
|
if [[ "${TARGETARCH}" == "amd64" ]]; then
|
||||||
mkdir -p /usr/lib/btbn-ffmpeg
|
mkdir -p /usr/lib/ffmpeg/5.0
|
||||||
|
mkdir -p /usr/lib/ffmpeg/7.0
|
||||||
|
wget -qO btbn-ffmpeg.tar.xz "https://github.com/NickM-27/FFmpeg-Builds/releases/download/autobuild-2022-07-31-12-37/ffmpeg-n5.1-2-g915ef932a3-linux64-gpl-5.1.tar.xz"
|
||||||
|
tar -xf btbn-ffmpeg.tar.xz -C /usr/lib/ffmpeg/5.0 --strip-components 1
|
||||||
|
rm -rf btbn-ffmpeg.tar.xz /usr/lib/ffmpeg/5.0/doc /usr/lib/ffmpeg/5.0/bin/ffplay
|
||||||
wget -qO btbn-ffmpeg.tar.xz "https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2024-09-13-12-57/ffmpeg-n7.0.2-17-gf705bc5b73-linux64-gpl-7.0.tar.xz"
|
wget -qO btbn-ffmpeg.tar.xz "https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2024-09-13-12-57/ffmpeg-n7.0.2-17-gf705bc5b73-linux64-gpl-7.0.tar.xz"
|
||||||
tar -xf btbn-ffmpeg.tar.xz -C /usr/lib/btbn-ffmpeg --strip-components 1
|
tar -xf btbn-ffmpeg.tar.xz -C /usr/lib/ffmpeg/7.0 --strip-components 1
|
||||||
rm -rf btbn-ffmpeg.tar.xz /usr/lib/btbn-ffmpeg/doc /usr/lib/btbn-ffmpeg/bin/ffplay
|
rm -rf btbn-ffmpeg.tar.xz /usr/lib/ffmpeg/7.0/doc /usr/lib/ffmpeg/7.0/bin/ffplay
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ffmpeg -> arm64
|
# ffmpeg -> arm64
|
||||||
if [[ "${TARGETARCH}" == "arm64" ]]; then
|
if [[ "${TARGETARCH}" == "arm64" ]]; then
|
||||||
mkdir -p /usr/lib/btbn-ffmpeg
|
mkdir -p /usr/lib/ffmpeg/5.0
|
||||||
|
mkdir -p /usr/lib/ffmpeg/7.0
|
||||||
|
wget -qO btbn-ffmpeg.tar.xz "https://github.com/NickM-27/FFmpeg-Builds/releases/download/autobuild-2022-07-31-12-37/ffmpeg-n5.1-2-g915ef932a3-linuxarm64-gpl-5.1.tar.xz"
|
||||||
|
tar -xf btbn-ffmpeg.tar.xz -C /usr/lib/ffmpeg/5.0 --strip-components 1
|
||||||
|
rm -rf btbn-ffmpeg.tar.xz /usr/lib/ffmpeg/5.0/doc /usr/lib/ffmpeg/5.0/bin/ffplay
|
||||||
wget -qO btbn-ffmpeg.tar.xz "https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2024-09-13-12-57/ffmpeg-n7.0.2-17-gf705bc5b73-linuxarm64-gpl-7.0.tar.xz"
|
wget -qO btbn-ffmpeg.tar.xz "https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2024-09-13-12-57/ffmpeg-n7.0.2-17-gf705bc5b73-linuxarm64-gpl-7.0.tar.xz"
|
||||||
tar -xf btbn-ffmpeg.tar.xz -C /usr/lib/btbn-ffmpeg --strip-components 1
|
tar -xf btbn-ffmpeg.tar.xz -C /usr/lib/ffmpeg/7.0 --strip-components 1
|
||||||
rm -rf btbn-ffmpeg.tar.xz /usr/lib/btbn-ffmpeg/doc /usr/lib/btbn-ffmpeg/bin/ffplay
|
rm -rf btbn-ffmpeg.tar.xz /usr/lib/ffmpeg/7.0/doc /usr/lib/ffmpeg/7.0/bin/ffplay
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# arch specific packages
|
# arch specific packages
|
||||||
|
|||||||
@ -44,8 +44,6 @@ function migrate_db_path() {
|
|||||||
|
|
||||||
echo "[INFO] Preparing Frigate..."
|
echo "[INFO] Preparing Frigate..."
|
||||||
migrate_db_path
|
migrate_db_path
|
||||||
export LIBAVFORMAT_VERSION_MAJOR=$(ffmpeg -version | grep -Po 'libavformat\W+\K\d+')
|
|
||||||
|
|
||||||
echo "[INFO] Starting Frigate..."
|
echo "[INFO] Starting Frigate..."
|
||||||
|
|
||||||
cd /opt/frigate || echo "[ERROR] Failed to change working directory to /opt/frigate"
|
cd /opt/frigate || echo "[ERROR] Failed to change working directory to /opt/frigate"
|
||||||
|
|||||||
@ -12,5 +12,7 @@ RUN rm -rf /usr/lib/btbn-ffmpeg/
|
|||||||
RUN --mount=type=bind,source=docker/rpi/install_deps.sh,target=/deps/install_deps.sh \
|
RUN --mount=type=bind,source=docker/rpi/install_deps.sh,target=/deps/install_deps.sh \
|
||||||
/deps/install_deps.sh
|
/deps/install_deps.sh
|
||||||
|
|
||||||
|
ENV LIBAVFORMAT_VERSION_MAJOR=58
|
||||||
|
|
||||||
WORKDIR /opt/frigate/
|
WORKDIR /opt/frigate/
|
||||||
COPY --from=rootfs / /
|
COPY --from=rootfs / /
|
||||||
|
|||||||
@ -14,6 +14,7 @@ from flask import (
|
|||||||
)
|
)
|
||||||
from peewee import DoesNotExist
|
from peewee import DoesNotExist
|
||||||
|
|
||||||
|
from frigate.config import FrigateConfig
|
||||||
from frigate.const import EXPORT_DIR
|
from frigate.const import EXPORT_DIR
|
||||||
from frigate.models import Export, Recordings
|
from frigate.models import Export, Recordings
|
||||||
from frigate.record.export import PlaybackFactorEnum, RecordingExporter
|
from frigate.record.export import PlaybackFactorEnum, RecordingExporter
|
||||||
@ -144,6 +145,7 @@ def export_delete(id: str):
|
|||||||
404,
|
404,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
config: FrigateConfig = current_app.frigate_config
|
||||||
files_in_use = []
|
files_in_use = []
|
||||||
for process in psutil.process_iter():
|
for process in psutil.process_iter():
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -17,6 +17,7 @@ from peewee import DoesNotExist, fn
|
|||||||
from tzlocal import get_localzone_name
|
from tzlocal import get_localzone_name
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
|
|
||||||
|
from frigate.config import FrigateConfig
|
||||||
from frigate.const import (
|
from frigate.const import (
|
||||||
CACHE_DIR,
|
CACHE_DIR,
|
||||||
CLIPS_DIR,
|
CLIPS_DIR,
|
||||||
@ -216,9 +217,10 @@ def get_snapshot_from_recording(camera_name: str, frame_time: str, format: str):
|
|||||||
|
|
||||||
height = request.args.get("height", type=int)
|
height = request.args.get("height", type=int)
|
||||||
codec = "png" if format == "png" else "mjpeg"
|
codec = "png" if format == "png" else "mjpeg"
|
||||||
|
config: FrigateConfig = current_app.frigate_config
|
||||||
|
|
||||||
image_data = get_image_from_recording(
|
image_data = get_image_from_recording(
|
||||||
recording.path, time_in_segment, codec, height
|
config.ffmpeg, recording.path, time_in_segment, codec, height
|
||||||
)
|
)
|
||||||
|
|
||||||
if not image_data:
|
if not image_data:
|
||||||
@ -273,9 +275,10 @@ def submit_recording_snapshot_to_plus(camera_name: str, frame_time: str):
|
|||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
config: FrigateConfig = current_app.frigate_config
|
||||||
recording: Recordings = recording_query.get()
|
recording: Recordings = recording_query.get()
|
||||||
time_in_segment = frame_time - recording.start_time
|
time_in_segment = frame_time - recording.start_time
|
||||||
image_data = get_image_from_recording(recording.path, time_in_segment, "png")
|
image_data = get_image_from_recording(config.ffmpeg, recording.path, time_in_segment, "png")
|
||||||
|
|
||||||
if not image_data:
|
if not image_data:
|
||||||
return make_response(
|
return make_response(
|
||||||
@ -474,9 +477,11 @@ def recording_clip(camera_name, start_ts, end_ts):
|
|||||||
file_name = secure_filename(file_name)
|
file_name = secure_filename(file_name)
|
||||||
path = os.path.join(CLIPS_DIR, f"cache/{file_name}")
|
path = os.path.join(CLIPS_DIR, f"cache/{file_name}")
|
||||||
|
|
||||||
|
config: FrigateConfig = current_app.frigate_config
|
||||||
|
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
ffmpeg_cmd = [
|
ffmpeg_cmd = [
|
||||||
"ffmpeg",
|
config.ffmpeg.executable_path,
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-y",
|
"-y",
|
||||||
"-protocol_whitelist",
|
"-protocol_whitelist",
|
||||||
@ -1141,8 +1146,9 @@ def preview_gif(camera_name: str, start_ts, end_ts, max_cache_age=2592000):
|
|||||||
diff = start_ts - preview.start_time
|
diff = start_ts - preview.start_time
|
||||||
minutes = int(diff / 60)
|
minutes = int(diff / 60)
|
||||||
seconds = int(diff % 60)
|
seconds = int(diff % 60)
|
||||||
|
config: FrigateConfig = current_app.frigate_config
|
||||||
ffmpeg_cmd = [
|
ffmpeg_cmd = [
|
||||||
"ffmpeg",
|
config.ffmpeg.executable_path,
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-loglevel",
|
"-loglevel",
|
||||||
"warning",
|
"warning",
|
||||||
@ -1206,9 +1212,10 @@ def preview_gif(camera_name: str, start_ts, end_ts, max_cache_age=2592000):
|
|||||||
|
|
||||||
last_file = selected_previews[-2]
|
last_file = selected_previews[-2]
|
||||||
selected_previews.append(last_file)
|
selected_previews.append(last_file)
|
||||||
|
config: FrigateConfig = current_app.frigate_config
|
||||||
|
|
||||||
ffmpeg_cmd = [
|
ffmpeg_cmd = [
|
||||||
"ffmpeg",
|
config.ffmpeg.executable_path,
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-loglevel",
|
"-loglevel",
|
||||||
"warning",
|
"warning",
|
||||||
@ -1301,8 +1308,9 @@ def preview_mp4(camera_name: str, start_ts, end_ts, max_cache_age=604800):
|
|||||||
diff = start_ts - preview.start_time
|
diff = start_ts - preview.start_time
|
||||||
minutes = int(diff / 60)
|
minutes = int(diff / 60)
|
||||||
seconds = int(diff % 60)
|
seconds = int(diff % 60)
|
||||||
|
config: FrigateConfig = current_app.frigate_config
|
||||||
ffmpeg_cmd = [
|
ffmpeg_cmd = [
|
||||||
"ffmpeg",
|
config.ffmpeg.executable_path,
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-loglevel",
|
"-loglevel",
|
||||||
"warning",
|
"warning",
|
||||||
@ -1364,9 +1372,10 @@ def preview_mp4(camera_name: str, start_ts, end_ts, max_cache_age=604800):
|
|||||||
|
|
||||||
last_file = selected_previews[-2]
|
last_file = selected_previews[-2]
|
||||||
selected_previews.append(last_file)
|
selected_previews.append(last_file)
|
||||||
|
config: FrigateConfig = current_app.frigate_config
|
||||||
|
|
||||||
ffmpeg_cmd = [
|
ffmpeg_cmd = [
|
||||||
"ffmpeg",
|
config.ffmpeg.executable_path,
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-loglevel",
|
"-loglevel",
|
||||||
"warning",
|
"warning",
|
||||||
|
|||||||
@ -374,7 +374,7 @@ class FrigateApp:
|
|||||||
except PermissionError:
|
except PermissionError:
|
||||||
logger.error("Unable to write to /config to save export state")
|
logger.error("Unable to write to /config to save export state")
|
||||||
|
|
||||||
migrate_exports(self.config.cameras.keys())
|
migrate_exports(self.config.ffmpeg, self.config.cameras.keys())
|
||||||
|
|
||||||
def init_external_event_processor(self) -> None:
|
def init_external_event_processor(self) -> None:
|
||||||
self.external_event_processor = ExternalEventProcessor(self.config)
|
self.external_event_processor = ExternalEventProcessor(self.config)
|
||||||
|
|||||||
@ -866,6 +866,7 @@ class FfmpegOutputArgsConfig(FrigateBaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class FfmpegConfig(FrigateBaseModel):
|
class FfmpegConfig(FrigateBaseModel):
|
||||||
|
path: str = Field(default="default", title="FFmpeg path")
|
||||||
global_args: Union[str, List[str]] = Field(
|
global_args: Union[str, List[str]] = Field(
|
||||||
default=FFMPEG_GLOBAL_ARGS_DEFAULT, title="Global FFmpeg arguments."
|
default=FFMPEG_GLOBAL_ARGS_DEFAULT, title="Global FFmpeg arguments."
|
||||||
)
|
)
|
||||||
@ -884,6 +885,21 @@ class FfmpegConfig(FrigateBaseModel):
|
|||||||
title="Time in seconds to wait before FFmpeg retries connecting to the camera.",
|
title="Time in seconds to wait before FFmpeg retries connecting to the camera.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def executable_path(self) -> str:
|
||||||
|
if self.path == "default":
|
||||||
|
if int(os.getenv("LIBAVFORMAT_VERSION_MAJOR", "59")) >= 59:
|
||||||
|
return "/usr/lib/ffmpeg/7.0/bin/ffmpeg"
|
||||||
|
else:
|
||||||
|
return "ffmpeg"
|
||||||
|
elif self.path == "7.0":
|
||||||
|
return "/usr/lib/ffmpeg/7.0/bin/ffmpeg"
|
||||||
|
elif self.path == "5.0":
|
||||||
|
return "/usr/lib/ffmpeg/5.0/bin/ffmpeg"
|
||||||
|
else:
|
||||||
|
return self.path
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CameraRoleEnum(str, Enum):
|
class CameraRoleEnum(str, Enum):
|
||||||
audio = "audio"
|
audio = "audio"
|
||||||
|
|||||||
@ -50,7 +50,7 @@ def get_ffmpeg_command(ffmpeg: FfmpegConfig) -> list[str]:
|
|||||||
or get_ffmpeg_arg_list(ffmpeg.input_args)
|
or get_ffmpeg_arg_list(ffmpeg.input_args)
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
["ffmpeg", "-vn", "-threads", "1"]
|
[ffmpeg.executable_path, "-vn", "-threads", "1"]
|
||||||
+ input_args
|
+ input_args
|
||||||
+ ["-i"]
|
+ ["-i"]
|
||||||
+ [ffmpeg_input.path]
|
+ [ffmpeg_input.path]
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import cv2
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from frigate.comms.config_updater import ConfigSubscriber
|
from frigate.comms.config_updater import ConfigSubscriber
|
||||||
from frigate.config import BirdseyeModeEnum, FrigateConfig
|
from frigate.config import BirdseyeModeEnum, FfmpegConfig, FrigateConfig
|
||||||
from frigate.const import BASE_DIR, BIRDSEYE_PIPE
|
from frigate.const import BASE_DIR, BIRDSEYE_PIPE
|
||||||
from frigate.util.image import (
|
from frigate.util.image import (
|
||||||
SharedMemoryFrameManager,
|
SharedMemoryFrameManager,
|
||||||
@ -112,7 +112,7 @@ class Canvas:
|
|||||||
class FFMpegConverter(threading.Thread):
|
class FFMpegConverter(threading.Thread):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
camera: str,
|
ffmpeg: FfmpegConfig,
|
||||||
input_queue: queue.Queue,
|
input_queue: queue.Queue,
|
||||||
stop_event: mp.Event,
|
stop_event: mp.Event,
|
||||||
in_width: int,
|
in_width: int,
|
||||||
@ -123,8 +123,8 @@ class FFMpegConverter(threading.Thread):
|
|||||||
birdseye_rtsp: bool = False,
|
birdseye_rtsp: bool = False,
|
||||||
):
|
):
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
self.name = f"{camera}_output_converter"
|
self.name = "birdseye_output_converter"
|
||||||
self.camera = camera
|
self.camera = "birdseye"
|
||||||
self.input_queue = input_queue
|
self.input_queue = input_queue
|
||||||
self.stop_event = stop_event
|
self.stop_event = stop_event
|
||||||
self.bd_pipe = None
|
self.bd_pipe = None
|
||||||
@ -133,7 +133,7 @@ class FFMpegConverter(threading.Thread):
|
|||||||
self.recreate_birdseye_pipe()
|
self.recreate_birdseye_pipe()
|
||||||
|
|
||||||
ffmpeg_cmd = [
|
ffmpeg_cmd = [
|
||||||
"ffmpeg",
|
ffmpeg.executable_path,
|
||||||
"-threads",
|
"-threads",
|
||||||
"1",
|
"1",
|
||||||
"-f",
|
"-f",
|
||||||
@ -725,7 +725,7 @@ class Birdseye:
|
|||||||
self.config = config
|
self.config = config
|
||||||
self.input = queue.Queue(maxsize=10)
|
self.input = queue.Queue(maxsize=10)
|
||||||
self.converter = FFMpegConverter(
|
self.converter = FFMpegConverter(
|
||||||
"birdseye",
|
config.ffmpeg,
|
||||||
self.input,
|
self.input,
|
||||||
stop_event,
|
stop_event,
|
||||||
config.birdseye.width,
|
config.birdseye.width,
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import queue
|
|||||||
import subprocess as sp
|
import subprocess as sp
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from frigate.config import CameraConfig
|
from frigate.config import CameraConfig, FfmpegConfig
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -15,6 +15,7 @@ class FFMpegConverter(threading.Thread):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
camera: str,
|
camera: str,
|
||||||
|
ffmpeg: FfmpegConfig,
|
||||||
input_queue: queue.Queue,
|
input_queue: queue.Queue,
|
||||||
stop_event: mp.Event,
|
stop_event: mp.Event,
|
||||||
in_width: int,
|
in_width: int,
|
||||||
@ -30,7 +31,7 @@ class FFMpegConverter(threading.Thread):
|
|||||||
self.stop_event = stop_event
|
self.stop_event = stop_event
|
||||||
|
|
||||||
ffmpeg_cmd = [
|
ffmpeg_cmd = [
|
||||||
"ffmpeg",
|
ffmpeg.executable_path,
|
||||||
"-threads",
|
"-threads",
|
||||||
"1",
|
"1",
|
||||||
"-f",
|
"-f",
|
||||||
@ -142,6 +143,7 @@ class JsmpegCamera:
|
|||||||
)
|
)
|
||||||
self.converter = FFMpegConverter(
|
self.converter = FFMpegConverter(
|
||||||
config.name,
|
config.name,
|
||||||
|
config.ffmpeg,
|
||||||
self.input,
|
self.input,
|
||||||
stop_event,
|
stop_event,
|
||||||
config.frame_shape[1],
|
config.frame_shape[1],
|
||||||
|
|||||||
@ -14,7 +14,7 @@ from typing import Optional
|
|||||||
|
|
||||||
from peewee import DoesNotExist
|
from peewee import DoesNotExist
|
||||||
|
|
||||||
from frigate.config import FrigateConfig
|
from frigate.config import FfmpegConfig, FrigateConfig
|
||||||
from frigate.const import (
|
from frigate.const import (
|
||||||
CACHE_DIR,
|
CACHE_DIR,
|
||||||
CLIPS_DIR,
|
CLIPS_DIR,
|
||||||
@ -116,7 +116,7 @@ class RecordingExporter(threading.Thread):
|
|||||||
minutes = int(diff / 60)
|
minutes = int(diff / 60)
|
||||||
seconds = int(diff % 60)
|
seconds = int(diff % 60)
|
||||||
ffmpeg_cmd = [
|
ffmpeg_cmd = [
|
||||||
"ffmpeg",
|
self.config.ffmpeg.executable_path,
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-loglevel",
|
"-loglevel",
|
||||||
"warning",
|
"warning",
|
||||||
@ -267,7 +267,7 @@ class RecordingExporter(threading.Thread):
|
|||||||
logger.debug(f"Finished exporting {video_path}")
|
logger.debug(f"Finished exporting {video_path}")
|
||||||
|
|
||||||
|
|
||||||
def migrate_exports(camera_names: list[str]):
|
def migrate_exports(ffmpeg: FfmpegConfig, camera_names: list[str]):
|
||||||
Path(os.path.join(CLIPS_DIR, "export")).mkdir(exist_ok=True)
|
Path(os.path.join(CLIPS_DIR, "export")).mkdir(exist_ok=True)
|
||||||
|
|
||||||
exports = []
|
exports = []
|
||||||
@ -286,7 +286,7 @@ def migrate_exports(camera_names: list[str]):
|
|||||||
) # use jpg because webp encoder can't get quality low enough
|
) # use jpg because webp encoder can't get quality low enough
|
||||||
|
|
||||||
ffmpeg_cmd = [
|
ffmpeg_cmd = [
|
||||||
"ffmpeg",
|
ffmpeg.executable_path,
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-loglevel",
|
"-loglevel",
|
||||||
"warning",
|
"warning",
|
||||||
|
|||||||
@ -387,7 +387,7 @@ class RecordingMaintainer(threading.Thread):
|
|||||||
|
|
||||||
# add faststart to kept segments to improve metadata reading
|
# add faststart to kept segments to improve metadata reading
|
||||||
p = await asyncio.create_subprocess_exec(
|
p = await asyncio.create_subprocess_exec(
|
||||||
"ffmpeg",
|
self.config.ffmpeg.executable_path,
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-y",
|
"-y",
|
||||||
"-i",
|
"-i",
|
||||||
|
|||||||
@ -765,12 +765,16 @@ def add_mask(mask: str, mask_img: np.ndarray):
|
|||||||
|
|
||||||
|
|
||||||
def get_image_from_recording(
|
def get_image_from_recording(
|
||||||
file_path: str, relative_frame_time: float, codec: str, height: Optional[int] = None
|
ffmpeg, # Ffmpeg Config
|
||||||
|
file_path: str,
|
||||||
|
relative_frame_time: float,
|
||||||
|
codec: str,
|
||||||
|
height: Optional[int] = None,
|
||||||
) -> Optional[any]:
|
) -> Optional[any]:
|
||||||
"""retrieve a frame from given time in recording file."""
|
"""retrieve a frame from given time in recording file."""
|
||||||
|
|
||||||
ffmpeg_cmd = [
|
ffmpeg_cmd = [
|
||||||
"ffmpeg",
|
ffmpeg.executable_path,
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-loglevel",
|
"-loglevel",
|
||||||
"warning",
|
"warning",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user