mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-05 18:55:23 +03:00
Run ffmpeg sub process & video_properties as async
This commit is contained in:
parent
680198148b
commit
a325ed40dc
@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
@ -1049,7 +1050,7 @@ class FrigateConfig(FrigateBaseModel):
|
||||
if "detect" in input.roles:
|
||||
stream_info = {"width": 0, "height": 0}
|
||||
try:
|
||||
stream_info = get_video_properties(input.path)
|
||||
stream_info = asyncio.run(get_video_properties(input.path))
|
||||
except Exception:
|
||||
logger.warn(
|
||||
f"Error detecting stream resolution automatically for {input.path} Applying default values."
|
||||
|
||||
@ -8,7 +8,6 @@ import os
|
||||
import queue
|
||||
import random
|
||||
import string
|
||||
import subprocess as sp
|
||||
import threading
|
||||
from collections import defaultdict
|
||||
from multiprocessing.synchronize import Event as MpEvent
|
||||
@ -183,7 +182,7 @@ class RecordingMaintainer(threading.Thread):
|
||||
if cache_path in self.end_time_cache:
|
||||
end_time, duration = self.end_time_cache[cache_path]
|
||||
else:
|
||||
segment_info = get_video_properties(cache_path, get_duration=True)
|
||||
segment_info = await get_video_properties(cache_path, get_duration=True)
|
||||
|
||||
if segment_info["duration"]:
|
||||
duration = float(segment_info["duration"])
|
||||
@ -231,7 +230,7 @@ class RecordingMaintainer(threading.Thread):
|
||||
if overlaps:
|
||||
record_mode = self.config.cameras[camera].record.events.retain.mode
|
||||
# move from cache to recordings immediately
|
||||
return self.move_segment(
|
||||
return await self.move_segment(
|
||||
camera,
|
||||
start_time,
|
||||
end_time,
|
||||
@ -253,7 +252,7 @@ class RecordingMaintainer(threading.Thread):
|
||||
# else retain days includes this segment
|
||||
else:
|
||||
record_mode = self.config.cameras[camera].record.retain.mode
|
||||
return self.move_segment(
|
||||
return await self.move_segment(
|
||||
camera, start_time, end_time, duration, cache_path, record_mode
|
||||
)
|
||||
|
||||
@ -296,7 +295,7 @@ class RecordingMaintainer(threading.Thread):
|
||||
|
||||
return SegmentInfo(motion_count, active_count, round(average_dBFS))
|
||||
|
||||
def move_segment(
|
||||
async def move_segment(
|
||||
self,
|
||||
camera: str,
|
||||
start_time: datetime.datetime,
|
||||
@ -332,7 +331,7 @@ class RecordingMaintainer(threading.Thread):
|
||||
start_frame = datetime.datetime.now().timestamp()
|
||||
|
||||
# add faststart to kept segments to improve metadata reading
|
||||
ffmpeg_cmd = [
|
||||
p = await asyncio.create_subprocess_exec(
|
||||
"ffmpeg",
|
||||
"-hide_banner",
|
||||
"-y",
|
||||
@ -343,17 +342,13 @@ class RecordingMaintainer(threading.Thread):
|
||||
"-movflags",
|
||||
"+faststart",
|
||||
file_path,
|
||||
]
|
||||
|
||||
p = sp.run(
|
||||
ffmpeg_cmd,
|
||||
encoding="ascii",
|
||||
capture_output=True,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
)
|
||||
await p.wait()
|
||||
|
||||
if p.returncode != 0:
|
||||
logger.error(f"Unable to convert {cache_path} to {file_path}")
|
||||
logger.error(p.stderr)
|
||||
logger.error((await p.stderr.read()).decode("ascii"))
|
||||
return None
|
||||
else:
|
||||
logger.debug(
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
"""Utilities for services."""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
@ -337,8 +338,8 @@ def vainfo_hwaccel(device_name: Optional[str] = None) -> sp.CompletedProcess:
|
||||
return sp.run(ffprobe_cmd, capture_output=True)
|
||||
|
||||
|
||||
def get_video_properties(url, get_duration=False):
|
||||
def calculate_duration(video: Optional[any]) -> float:
|
||||
async def get_video_properties(url, get_duration=False):
|
||||
async def calculate_duration(video: Optional[any]) -> float:
|
||||
duration = None
|
||||
|
||||
if video is not None:
|
||||
@ -351,7 +352,7 @@ def get_video_properties(url, get_duration=False):
|
||||
|
||||
# if cv2 failed need to use ffprobe
|
||||
if duration is None:
|
||||
ffprobe_cmd = [
|
||||
p = await asyncio.create_subprocess_exec(
|
||||
"ffprobe",
|
||||
"-v",
|
||||
"error",
|
||||
@ -360,11 +361,18 @@ def get_video_properties(url, get_duration=False):
|
||||
"-of",
|
||||
"default=noprint_wrappers=1:nokey=1",
|
||||
f"{url}",
|
||||
]
|
||||
p = sp.run(ffprobe_cmd, capture_output=True)
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
)
|
||||
await p.wait()
|
||||
|
||||
if p.returncode == 0 and p.stdout.decode():
|
||||
duration = float(p.stdout.decode().strip())
|
||||
if p.returncode == 0:
|
||||
result = (await p.stdout.read()).decode()
|
||||
else:
|
||||
result = None
|
||||
|
||||
if result:
|
||||
duration = float(result.strip())
|
||||
else:
|
||||
duration = -1
|
||||
|
||||
@ -385,7 +393,7 @@ def get_video_properties(url, get_duration=False):
|
||||
result = {}
|
||||
|
||||
if get_duration:
|
||||
result["duration"] = calculate_duration(video)
|
||||
result["duration"] = await calculate_duration(video)
|
||||
|
||||
if video is not None:
|
||||
# Get the width of frames in the video stream
|
||||
|
||||
Loading…
Reference in New Issue
Block a user