Switch back to av 13.1.0 (#129699)

This commit is contained in:
Marc Mueller
2024-11-04 14:48:28 +01:00
committed by GitHub
parent ff621d5bf3
commit 41a81cbf15
8 changed files with 47 additions and 49 deletions

View File

@ -7,5 +7,5 @@
"documentation": "https://www.home-assistant.io/integrations/generic",
"integration_type": "device",
"iot_class": "local_push",
"requirements": ["ha-av==10.1.1", "Pillow==10.4.0"]
"requirements": ["av==13.1.0", "Pillow==10.4.0"]
}

View File

@ -27,8 +27,7 @@ from .const import (
)
if TYPE_CHECKING:
from av import Packet
from av.video.codeccontext import VideoCodecContext
from av import Packet, VideoCodecContext
from homeassistant.components.camera import DynamicStreamSettings
@ -509,9 +508,8 @@ class KeyFrameConverter:
frames = self._codec_context.decode(None)
break
except EOFError:
_LOGGER.debug("Codec context needs flushing, attempting to reopen")
self._codec_context.close()
self._codec_context.open()
_LOGGER.debug("Codec context needs flushing")
self._codec_context.flush_buffers()
else:
_LOGGER.debug("Unable to decode keyframe")
return

View File

@ -7,5 +7,5 @@
"integration_type": "system",
"iot_class": "local_push",
"quality_scale": "internal",
"requirements": ["PyTurboJPEG==1.7.5", "ha-av==10.1.1", "numpy==1.26.4"]
"requirements": ["PyTurboJPEG==1.7.5", "av==13.1.0", "numpy==1.26.4"]
}

View File

@ -107,7 +107,7 @@ class RecorderOutput(StreamOutput):
# Create output on first segment
if not output:
container_options: dict[str, str] = {
"video_track_timescale": str(int(1 / source_v.time_base)),
"video_track_timescale": str(int(1 / source_v.time_base)), # type: ignore[operator]
"movflags": "frag_keyframe+empty_moov",
"min_frag_duration": str(self.stream_settings.min_segment_duration),
}
@ -132,21 +132,23 @@ class RecorderOutput(StreamOutput):
last_stream_id = segment.stream_id
pts_adjuster["video"] = int(
(running_duration - source.start_time)
/ (av.time_base * source_v.time_base)
/ (av.time_base * source_v.time_base) # type: ignore[operator]
)
if source_a:
pts_adjuster["audio"] = int(
(running_duration - source.start_time)
/ (av.time_base * source_a.time_base)
/ (av.time_base * source_a.time_base) # type: ignore[operator]
)
# Remux video
for packet in source.demux():
if packet.dts is None:
if packet.pts is None:
continue
packet.pts += pts_adjuster[packet.stream.type]
packet.dts += pts_adjuster[packet.stream.type]
packet.stream = output_v if packet.stream.type == "video" else output_a
packet.pts += pts_adjuster[packet.stream.type] # type: ignore[operator]
packet.dts += pts_adjuster[packet.stream.type] # type: ignore[operator]
stream = output_v if packet.stream.type == "video" else output_a
assert stream
packet.stream = stream
output.mux(packet)
running_duration += source.duration - source.start_time

View File

@ -16,7 +16,6 @@ import av
import av.audio
import av.container
import av.stream
import av.video
from homeassistant.core import HomeAssistant
from homeassistant.util import dt as dt_util
@ -53,8 +52,8 @@ class StreamWorkerError(Exception):
def redact_av_error_string(err: av.FFmpegError) -> str:
"""Return an error string with credentials redacted from the url."""
parts = [str(err.type), err.strerror]
if err.filename is not None:
parts = [str(err.type), err.strerror] # type: ignore[attr-defined]
if err.filename:
parts.append(redact_credentials(err.filename))
return ", ".join(parts)
@ -130,19 +129,19 @@ class StreamMuxer:
_segment_start_dts: int
_memory_file: BytesIO
_av_output: av.container.OutputContainer
_output_video_stream: av.video.VideoStream
_output_video_stream: av.VideoStream
_output_audio_stream: av.audio.AudioStream | None
_segment: Segment | None
# the following 2 member variables are used for Part formation
_memory_file_pos: int
_part_start_dts: int
_part_start_dts: float
def __init__(
self,
hass: HomeAssistant,
video_stream: av.video.VideoStream,
video_stream: av.VideoStream,
audio_stream: av.audio.AudioStream | None,
audio_bsf: av.BitStreamFilter | None,
audio_bsf: str | None,
stream_state: StreamState,
stream_settings: StreamSettings,
) -> None:
@ -161,11 +160,11 @@ class StreamMuxer:
self,
memory_file: BytesIO,
sequence: int,
input_vstream: av.video.VideoStream,
input_vstream: av.VideoStream,
input_astream: av.audio.AudioStream | None,
) -> tuple[
av.container.OutputContainer,
av.video.VideoStream,
av.VideoStream,
av.audio.AudioStream | None,
]:
"""Make a new av OutputContainer and add output streams."""
@ -182,7 +181,7 @@ class StreamMuxer:
# in test_durations
"avoid_negative_ts": "make_non_negative",
"fragment_index": str(sequence + 1),
"video_track_timescale": str(int(1 / input_vstream.time_base)),
"video_track_timescale": str(int(1 / input_vstream.time_base)), # type: ignore[operator]
# Only do extra fragmenting if we are using ll_hls
# Let ffmpeg do the work using frag_duration
# Fragment durations may exceed the 15% allowed variance but it seems ok
@ -233,12 +232,11 @@ class StreamMuxer:
output_astream = None
if input_astream:
if self._audio_bsf:
self._audio_bsf_context = self._audio_bsf.create()
self._audio_bsf_context.set_input_stream(input_astream)
output_astream = container.add_stream(
template=self._audio_bsf_context or input_astream
)
return container, output_vstream, output_astream
self._audio_bsf_context = av.BitStreamFilterContext(
self._audio_bsf, input_astream
)
output_astream = container.add_stream(template=input_astream)
return container, output_vstream, output_astream # type: ignore[return-value]
def reset(self, video_dts: int) -> None:
"""Initialize a new stream segment."""
@ -279,11 +277,11 @@ class StreamMuxer:
self._part_has_keyframe |= packet.is_keyframe
elif packet.stream == self._input_audio_stream:
assert self._output_audio_stream
if self._audio_bsf_context:
self._audio_bsf_context.send(packet)
while packet := self._audio_bsf_context.recv():
packet.stream = self._output_audio_stream
self._av_output.mux(packet)
for audio_packet in self._audio_bsf_context.filter(packet):
audio_packet.stream = self._output_audio_stream
self._av_output.mux(audio_packet)
return
packet.stream = self._output_audio_stream
self._av_output.mux(packet)
@ -465,7 +463,7 @@ class TimestampValidator:
"""Validate the packet timestamp based on ordering within the stream."""
# Discard packets missing DTS. Terminate if too many are missing.
if packet.dts is None:
if self._missing_dts >= MAX_MISSING_DTS:
if self._missing_dts >= MAX_MISSING_DTS: # type: ignore[unreachable]
raise StreamWorkerError(
f"No dts in {MAX_MISSING_DTS+1} consecutive packets"
)
@ -492,7 +490,7 @@ def is_keyframe(packet: av.Packet) -> Any:
def get_audio_bitstream_filter(
packets: Iterator[av.Packet], audio_stream: Any
) -> av.BitStreamFilterContext | None:
) -> str | None:
"""Return the aac_adtstoasc bitstream filter if ADTS AAC is detected."""
if not audio_stream:
return None
@ -509,7 +507,7 @@ def get_audio_bitstream_filter(
_LOGGER.debug(
"ADTS AAC detected. Adding aac_adtstoaac bitstream filter"
)
return av.BitStreamFilter("aac_adtstoasc")
return "aac_adtstoasc"
break
return None
@ -547,7 +545,7 @@ def stream_worker(
audio_stream = None
# Some audio streams do not have a profile and throw errors when remuxing
if audio_stream and audio_stream.profile is None:
audio_stream = None
audio_stream = None # type: ignore[unreachable]
# Disable ll-hls for hls inputs
if container.format.name == "hls":
for field in fields(StreamSettings):
@ -562,8 +560,8 @@ def stream_worker(
stream_state.diagnostics.set_value("audio_codec", audio_stream.name)
dts_validator = TimestampValidator(
int(1 / video_stream.time_base),
int(1 / audio_stream.time_base) if audio_stream else 1,
int(1 / video_stream.time_base), # type: ignore[operator]
int(1 / audio_stream.time_base) if audio_stream else 1, # type: ignore[operator]
)
container_packets = PeekIterator(
filter(dts_validator.is_valid, container.demux((video_stream, audio_stream)))

View File

@ -13,6 +13,7 @@ async-interrupt==1.2.0
async-upnp-client==0.41.0
atomicwrites-homeassistant==1.4.1
attrs==24.2.0
av==13.1.0
awesomeversion==24.6.0
bcrypt==4.2.0
bleak-retry-connector==3.6.0
@ -27,7 +28,6 @@ cryptography==43.0.1
dbus-fast==2.24.3
fnv-hash-fast==1.0.2
go2rtc-client==0.0.1b3
ha-av==10.1.1
ha-ffmpeg==3.2.1
habluetooth==3.6.0
hass-nabucasa==0.83.0

View File

@ -526,6 +526,10 @@ autarco==3.1.0
# homeassistant.components.husqvarna_automower_ble
automower-ble==0.2.0
# homeassistant.components.generic
# homeassistant.components.stream
av==13.1.0
# homeassistant.components.avea
# avea==1.5.1
@ -1064,10 +1068,6 @@ guppy3==3.1.4.post1
# homeassistant.components.iaqualink
h2==4.1.0
# homeassistant.components.generic
# homeassistant.components.stream
ha-av==10.1.1
# homeassistant.components.ffmpeg
ha-ffmpeg==3.2.1

View File

@ -481,6 +481,10 @@ autarco==3.1.0
# homeassistant.components.husqvarna_automower_ble
automower-ble==0.2.0
# homeassistant.components.generic
# homeassistant.components.stream
av==13.1.0
# homeassistant.components.axis
axis==63
@ -902,10 +906,6 @@ guppy3==3.1.4.post1
# homeassistant.components.iaqualink
h2==4.1.0
# homeassistant.components.generic
# homeassistant.components.stream
ha-av==10.1.1
# homeassistant.components.ffmpeg
ha-ffmpeg==3.2.1