core/homeassistant/components/stream/recorder.py

95 lines
2.5 KiB
Python
Raw Normal View History

"""Provide functionality to record stream."""
import threading
from typing import List
import av
from homeassistant.core import callback
from .core import PROVIDERS, Segment, StreamOutput
@callback
def async_setup_recorder(hass):
"""Only here so Provider Registry works."""
def recorder_save_worker(file_out: str, segments: List[Segment]):
"""Handle saving stream."""
2019-07-31 19:25:30 +00:00
output = av.open(file_out, "w", options={"movflags": "frag_keyframe"})
output_v = None
for segment in segments:
# Seek to beginning and open segment
segment.segment.seek(0)
2019-07-31 19:25:30 +00:00
source = av.open(segment.segment, "r", format="mpegts")
source_v = source.streams.video[0]
# Add output streams
if not output_v:
output_v = output.add_stream(template=source_v)
# Remux video
for packet in source.demux(source_v):
if packet is not None and packet.dts is not None:
packet.stream = output_v
output.mux(packet)
output.close()
2019-07-31 19:25:30 +00:00
@PROVIDERS.register("recorder")
class RecorderOutput(StreamOutput):
"""Represents HLS Output formats."""
def __init__(self, stream, timeout: int = 30) -> None:
"""Initialize recorder output."""
super().__init__(stream, timeout)
self.video_path = None
self._segments = []
@property
def name(self) -> str:
"""Return provider name."""
2019-07-31 19:25:30 +00:00
return "recorder"
@property
def format(self) -> str:
"""Return container format."""
2019-07-31 19:25:30 +00:00
return "mpegts"
@property
def audio_codec(self) -> str:
"""Return desired audio codec."""
2019-07-31 19:25:30 +00:00
return "aac"
@property
def video_codec(self) -> str:
"""Return desired video codec."""
2019-07-31 19:25:30 +00:00
return "h264"
def prepend(self, segments: List[Segment]) -> None:
"""Prepend segments to existing list."""
own_segments = self.segments
segments = [s for s in segments if s.sequence not in own_segments]
self._segments = segments + self._segments
@callback
def _timeout(self, _now=None):
"""Handle recorder timeout."""
self._unsub = None
self.cleanup()
def cleanup(self):
"""Write recording and clean up."""
thread = threading.Thread(
2019-07-31 19:25:30 +00:00
name="recorder_save_worker",
target=recorder_save_worker,
2019-07-31 19:25:30 +00:00
args=(self.video_path, self._segments),
)
thread.start()
self._segments = []
self._stream.remove_provider(self)