Source code for xarray_video.codecs.h264
import os
import tempfile
import numpy
import io
from numcodecs.abc import Codec
from numcodecs.compat import ndarray_copy, ensure_contiguous_ndarray
import av
[docs]class H264(Codec):
"""Codec providing compression using h264 via pyav
Parameters
----------
fps : int (optional)
Frames per second in compressed chunk (default 25)
crf : int (optional)
Constant Rate Factor (default None). The range of the CRF
scale is 0–51, where 0 is lossless, and 51 is worst quality
possible. If None will use the ffmepg defautt (23).
"""
codec_id = "h264"
[docs] def __init__(self, fps=25, crf=None):
self.fps = fps
self.crf = crf
[docs] def encode(self, buf):
# normalise input
nf, ny, nx, nb = buf.shape
# write chunk as video file
data = io.BytesIO()
writer = av.open(data, mode="w", format="mp4")
stream = writer.add_stream("h264", rate=self.fps)
writer.streams.video[0].thread_type = "AUTO"
stream.width = nx
stream.height = ny
stream.pix_fmt = "yuv420p"
stream.options = {} if self.crf is None else {"crf": str(self.crf)}
for frame_i in buf:
frame = av.VideoFrame.from_ndarray(frame_i, format="rgb24")
for packet in stream.encode(frame):
writer.mux(packet)
# Flush stream
for packet in stream.encode():
writer.mux(packet)
writer.close()
data.seek(0)
return data.read()
[docs] def decode(self, buf, out=None):
# normalise inputs
buf = ensure_contiguous_ndarray(buf)
stream = io.BytesIO(buf)
reader = av.open(stream)
reader.streams.video[0].thread_type = "AUTO"
codec = reader.streams[0].codec_context
frames = reader.streams[0].frames
width = codec.width
height = codec.height
if out is not None:
out = ensure_contiguous_ndarray(out)
data = numpy.zeros((frames, height, width, 3), dtype="uint8")
for i, frame in enumerate(reader.decode(video=0)):
data[i] = frame.to_ndarray(format="rgb24")
reader.close()
return ndarray_copy(data, out)