mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Additional stream typing improvements (#129695)
This commit is contained in:
parent
e18ffc53f2
commit
5cf13d9273
@ -9,7 +9,7 @@ from dataclasses import dataclass, field
|
|||||||
import datetime
|
import datetime
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
import logging
|
import logging
|
||||||
from typing import TYPE_CHECKING, Any
|
from typing import TYPE_CHECKING, Any, cast
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@ -27,7 +27,8 @@ from .const import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from av import CodecContext, Packet
|
from av import Packet
|
||||||
|
from av.video.codeccontext import VideoCodecContext
|
||||||
|
|
||||||
from homeassistant.components.camera import DynamicStreamSettings
|
from homeassistant.components.camera import DynamicStreamSettings
|
||||||
|
|
||||||
@ -448,7 +449,7 @@ class KeyFrameConverter:
|
|||||||
self._image: bytes | None = None
|
self._image: bytes | None = None
|
||||||
self._turbojpeg = TurboJPEGSingleton.instance()
|
self._turbojpeg = TurboJPEGSingleton.instance()
|
||||||
self._lock = asyncio.Lock()
|
self._lock = asyncio.Lock()
|
||||||
self._codec_context: CodecContext | None = None
|
self._codec_context: VideoCodecContext | None = None
|
||||||
self._stream_settings = stream_settings
|
self._stream_settings = stream_settings
|
||||||
self._dynamic_stream_settings = dynamic_stream_settings
|
self._dynamic_stream_settings = dynamic_stream_settings
|
||||||
|
|
||||||
@ -460,7 +461,7 @@ class KeyFrameConverter:
|
|||||||
self._packet = packet
|
self._packet = packet
|
||||||
self._hass.loop.call_soon_threadsafe(self._event.set)
|
self._hass.loop.call_soon_threadsafe(self._event.set)
|
||||||
|
|
||||||
def create_codec_context(self, codec_context: CodecContext) -> None:
|
def create_codec_context(self, codec_context: VideoCodecContext) -> None:
|
||||||
"""Create a codec context to be used for decoding the keyframes.
|
"""Create a codec context to be used for decoding the keyframes.
|
||||||
|
|
||||||
This is run by the worker thread and will only be called once per worker.
|
This is run by the worker thread and will only be called once per worker.
|
||||||
@ -474,7 +475,9 @@ class KeyFrameConverter:
|
|||||||
# pylint: disable-next=import-outside-toplevel
|
# pylint: disable-next=import-outside-toplevel
|
||||||
from av import CodecContext
|
from av import CodecContext
|
||||||
|
|
||||||
self._codec_context = CodecContext.create(codec_context.name, "r")
|
self._codec_context = cast(
|
||||||
|
"VideoCodecContext", CodecContext.create(codec_context.name, "r")
|
||||||
|
)
|
||||||
self._codec_context.extradata = codec_context.extradata
|
self._codec_context.extradata = codec_context.extradata
|
||||||
self._codec_context.skip_frame = "NONKEY"
|
self._codec_context.skip_frame = "NONKEY"
|
||||||
self._codec_context.thread_type = "NONE"
|
self._codec_context.thread_type = "NONE"
|
||||||
|
@ -122,7 +122,7 @@ class RecorderOutput(StreamOutput):
|
|||||||
if not output_v:
|
if not output_v:
|
||||||
output_v = output.add_stream(template=source_v)
|
output_v = output.add_stream(template=source_v)
|
||||||
context = output_v.codec_context
|
context = output_v.codec_context
|
||||||
context.flags |= "GLOBAL_HEADER"
|
context.global_header = True
|
||||||
if source_a and not output_a:
|
if source_a and not output_a:
|
||||||
output_a = output.add_stream(template=source_a)
|
output_a = output.add_stream(template=source_a)
|
||||||
|
|
||||||
|
@ -127,6 +127,16 @@ class StreamState:
|
|||||||
class StreamMuxer:
|
class StreamMuxer:
|
||||||
"""StreamMuxer re-packages video/audio packets for output."""
|
"""StreamMuxer re-packages video/audio packets for output."""
|
||||||
|
|
||||||
|
_segment_start_dts: int
|
||||||
|
_memory_file: BytesIO
|
||||||
|
_av_output: av.container.OutputContainer
|
||||||
|
_output_video_stream: av.video.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
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@ -138,19 +148,10 @@ class StreamMuxer:
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize StreamMuxer."""
|
"""Initialize StreamMuxer."""
|
||||||
self._hass = hass
|
self._hass = hass
|
||||||
self._segment_start_dts: int = cast(int, None)
|
self._input_video_stream = video_stream
|
||||||
self._memory_file: BytesIO = cast(BytesIO, None)
|
self._input_audio_stream = audio_stream
|
||||||
self._av_output: av.container.OutputContainer = None
|
|
||||||
self._input_video_stream: av.video.VideoStream = video_stream
|
|
||||||
self._input_audio_stream: av.audio.AudioStream | None = audio_stream
|
|
||||||
self._audio_bsf = audio_bsf
|
self._audio_bsf = audio_bsf
|
||||||
self._audio_bsf_context: av.BitStreamFilterContext = None
|
self._audio_bsf_context: av.BitStreamFilterContext | None = None
|
||||||
self._output_video_stream: av.video.VideoStream = None
|
|
||||||
self._output_audio_stream: av.audio.AudioStream | None = None
|
|
||||||
self._segment: Segment | None = None
|
|
||||||
# the following 3 member variables are used for Part formation
|
|
||||||
self._memory_file_pos: int = cast(int, None)
|
|
||||||
self._part_start_dts: int = cast(int, None)
|
|
||||||
self._part_has_keyframe = False
|
self._part_has_keyframe = False
|
||||||
self._stream_settings = stream_settings
|
self._stream_settings = stream_settings
|
||||||
self._stream_state = stream_state
|
self._stream_state = stream_state
|
||||||
@ -256,7 +257,7 @@ class StreamMuxer:
|
|||||||
input_astream=self._input_audio_stream,
|
input_astream=self._input_audio_stream,
|
||||||
)
|
)
|
||||||
if self._output_video_stream.name == "hevc":
|
if self._output_video_stream.name == "hevc":
|
||||||
self._output_video_stream.codec_tag = "hvc1"
|
self._output_video_stream.codec_context.codec_tag = "hvc1"
|
||||||
|
|
||||||
def mux_packet(self, packet: av.Packet) -> None:
|
def mux_packet(self, packet: av.Packet) -> None:
|
||||||
"""Mux a packet to the appropriate output stream."""
|
"""Mux a packet to the appropriate output stream."""
|
||||||
@ -562,7 +563,7 @@ def stream_worker(
|
|||||||
|
|
||||||
dts_validator = TimestampValidator(
|
dts_validator = TimestampValidator(
|
||||||
int(1 / video_stream.time_base),
|
int(1 / video_stream.time_base),
|
||||||
1 / audio_stream.time_base if audio_stream else 1,
|
int(1 / audio_stream.time_base) if audio_stream else 1,
|
||||||
)
|
)
|
||||||
container_packets = PeekIterator(
|
container_packets = PeekIterator(
|
||||||
filter(dts_validator.is_valid, container.demux((video_stream, audio_stream)))
|
filter(dts_validator.is_valid, container.demux((video_stream, audio_stream)))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user