Run ffmpeg sub process & video_properties as async

This commit is contained in:
Nick Mowen 2023-07-24 08:23:36 -06:00
parent 680198148b
commit a325ed40dc
3 changed files with 26 additions and 22 deletions

View File

@ -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."

View File

@ -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(

View File

@ -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