Fix iOS playback of H.265 clips (#10105)

* Fix iOS playback of H.265 clips

* CI
This commit is contained in:
Andrew Reiter 2024-02-27 22:41:36 -05:00 committed by GitHub
parent 9893741990
commit 5edaaceaf2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 60 additions and 26 deletions

View File

@ -614,6 +614,7 @@ class FfmpegOutputArgsConfig(FrigateBaseModel):
default=RECORD_FFMPEG_OUTPUT_ARGS_DEFAULT,
title="Record role FFmpeg output arguments.",
)
_force_record_hvc1: bool = PrivateAttr(default=False)
class FfmpegConfig(FrigateBaseModel):
@ -878,7 +879,10 @@ class CameraConfig(FrigateBaseModel):
if "record" in ffmpeg_input.roles and self.record.enabled:
record_args = get_ffmpeg_arg_list(
parse_preset_output_record(self.ffmpeg.output_args.record)
parse_preset_output_record(
self.ffmpeg.output_args.record,
self.ffmpeg.output_args._force_record_hvc1,
)
or self.ffmpeg.output_args.record
)
@ -1161,31 +1165,42 @@ class FrigateConfig(FrigateBaseModel):
if camera_config.ffmpeg.hwaccel_args == "auto":
camera_config.ffmpeg.hwaccel_args = config.ffmpeg.hwaccel_args
if (
camera_config.detect.height is None
or camera_config.detect.width is None
):
for input in camera_config.ffmpeg.inputs:
if "detect" in input.roles:
stream_info = {"width": 0, "height": 0}
try:
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."
)
stream_info = {"width": 0, "height": 0}
for input in camera_config.ffmpeg.inputs:
need_record_fourcc = "record" in input.roles
need_detect_dimensions = "detect" in input.roles and (
camera_config.detect.height is None
or camera_config.detect.width is None
)
camera_config.detect.width = (
stream_info["width"]
if stream_info.get("width")
else DEFAULT_DETECT_DIMENSIONS["width"]
)
camera_config.detect.height = (
stream_info["height"]
if stream_info.get("height")
else DEFAULT_DETECT_DIMENSIONS["height"]
if need_detect_dimensions or need_record_fourcc:
stream_info = {"width": 0, "height": 0, "fourcc": None}
try:
stream_info = asyncio.run(get_video_properties(input.path))
except Exception:
logger.warn(
f"Error detecting stream parameters automatically for {input.path} Applying default values."
)
stream_info = {"width": 0, "height": 0, "fourcc": None}
if need_detect_dimensions:
camera_config.detect.width = (
stream_info["width"]
if stream_info.get("width")
else DEFAULT_DETECT_DIMENSIONS["width"]
)
camera_config.detect.height = (
stream_info["height"]
if stream_info.get("height")
else DEFAULT_DETECT_DIMENSIONS["height"]
)
if need_record_fourcc:
# Apple only supports HEVC if it is hvc1 (vs. hev1)
camera_config.ffmpeg.output_args._force_record_hvc1 = (
stream_info["fourcc"] == "hevc"
if stream_info.get("hevc")
else False
)
# Default min_initialized configuration
min_initialized = camera_config.detect.fps / 2

View File

@ -461,9 +461,18 @@ PRESETS_RECORD_OUTPUT = {
}
def parse_preset_output_record(arg: Any) -> list[str]:
def parse_preset_output_record(arg: Any, force_record_hvc1: bool) -> list[str]:
"""Return the correct preset if in preset format otherwise return None."""
if not isinstance(arg, str):
return None
return PRESETS_RECORD_OUTPUT.get(arg, None)
preset = PRESETS_RECORD_OUTPUT.get(arg, None)
if not preset:
return None
if force_record_hvc1:
# Apple only supports HEVC if it is hvc1 (vs. hev1)
preset += ["-tag:v", "hvc1"]
return preset

View File

@ -505,10 +505,20 @@ async def get_video_properties(url, get_duration=False) -> dict[str, any]:
# Get the height of frames in the video stream
height = video.get(cv2.CAP_PROP_FRAME_HEIGHT)
# Get the stream encoding
fourcc_int = int(video.get(cv2.CAP_PROP_FOURCC))
fourcc = (
chr((fourcc_int >> 0) & 255)
+ chr((fourcc_int >> 8) & 255)
+ chr((fourcc_int >> 16) & 255)
+ chr((fourcc_int >> 24) & 255)
)
# Release the video stream
video.release()
result["width"] = round(width)
result["height"] = round(height)
result["fourcc"] = fourcc
return result