Module livekit.rtc.encoded_video
Classes
class EncodedRateControl (target_bitrate_bps: int, framerate_fps: float)-
Expand source code
@dataclass(frozen=True) class EncodedRateControl: """The latest bitrate and frame-rate targets requested by WebRTC.""" target_bitrate_bps: int framerate_fps: floatThe latest bitrate and frame-rate targets requested by WebRTC.
Instance variables
var framerate_fps : floatvar target_bitrate_bps : int
class EncodedVideoFrame (data: bytes,
width: int,
height: int,
codec: proto_video.VideoCodec.ValueType,
frame_type: proto_video.EncodedFrameType.ValueType,
timestamp_us: int,
metadata: proto_video.FrameMetadata | None = None)-
Expand source code
@dataclass(frozen=True) class EncodedVideoFrame: """One complete encoded access unit, without a container or RTP headers. ``data`` must contain a single frame in ``codec`` (Annex B for H.264/H.265). ``timestamp_us`` is its capture time in microseconds, increasing along the stream. The codec must match the publication and remain fixed for its lifetime. """ data: bytes width: int height: int codec: proto_video.VideoCodec.ValueType frame_type: proto_video.EncodedFrameType.ValueType timestamp_us: int metadata: proto_video.FrameMetadata | None = None def __post_init__(self) -> None: if not isinstance(self.data, bytes): raise TypeError("encoded frame data must be bytes") if not self.data: raise ValueError("encoded frame data must not be empty") if self.width <= 0 or self.height <= 0: raise ValueError("encoded frame dimensions must be positive")One complete encoded access unit, without a container or RTP headers.
datamust contain a single frame incodec(Annex B for H.264/H.265).timestamp_usis its capture time in microseconds, increasing along the stream. The codec must match the publication and remain fixed for its lifetime.Instance variables
var codec : intvar data : bytesvar frame_type : intvar height : intvar metadata : video_frame_pb2.FrameMetadata | Nonevar timestamp_us : intvar width : int
class EncodedVideoSource (width: int, height: int)-
Expand source code
class EncodedVideoSource: """Publish pre-encoded video without decoding or re-encoding it. Create a ``LocalVideoTrack`` with this source and publish it with a matching ``video_codec``, ``video_encoder=ENCODER_BACKEND_PRE_ENCODED`` and ``simulcast=False``. Feed complete access units at the intended playback rate; this source does not pace or buffer a file for playback. Poll ``take_feedback`` and forward keyframe and rate-control requests to the upstream encoder. A demuxer alone cannot produce a new keyframe or adapt the encoded bitrate. Call ``capture_frame`` from a single producer. """ def __init__(self, width: int, height: int) -> None: """Create a source with the initial encoded frame dimensions.""" if width <= 0 or height <= 0: raise ValueError("encoded source dimensions must be positive") req = proto_ffi.FfiRequest() req.new_video_source.type = proto_video.VideoSourceType.VIDEO_SOURCE_ENCODED req.new_video_source.resolution.width = width req.new_video_source.resolution.height = height resp = FfiClient.instance.request(req) self._ffi_handle = FfiHandle(resp.new_video_source.source.handle.id) def capture_frame(self, frame: EncodedVideoFrame) -> bool: """Submit a frame; return whether the native source accepted it. The native implementation copies the payload before this call returns. Acceptance does not guarantee delivery to subscribers. """ req = proto_ffi.FfiRequest() capture = req.capture_encoded_video_frame capture.source_handle = self._ffi_handle.handle capture.buffer.data_ptr = get_address(frame.data) capture.buffer.data_len = len(frame.data) capture.codec = frame.codec capture.frame_type = frame.frame_type capture.width = frame.width capture.height = frame.height capture.timestamp_us = frame.timestamp_us if frame.metadata is not None: capture.metadata.CopyFrom(frame.metadata) response: proto_ffi.FfiResponse = FfiClient.instance.request(req) return response.capture_encoded_video_frame.accepted def take_feedback(self) -> EncodedVideoSourceFeedback: """Consume pending feedback, including requests from late subscribers.""" req = proto_ffi.FfiRequest() req.take_encoded_video_source_feedback.source_handle = self._ffi_handle.handle feedback = FfiClient.instance.request(req).take_encoded_video_source_feedback rate_control = None if feedback.HasField("rate_control"): rate_control = EncodedRateControl( target_bitrate_bps=feedback.rate_control.target_bitrate_bps, framerate_fps=feedback.rate_control.framerate_fps, ) return EncodedVideoSourceFeedback(feedback.keyframe_requested, rate_control) async def aclose(self) -> None: """Release the native source handle.""" self._ffi_handle.dispose()Publish pre-encoded video without decoding or re-encoding it.
Create a
LocalVideoTrackwith this source and publish it with a matchingvideo_codec,video_encoder=ENCODER_BACKEND_PRE_ENCODEDandsimulcast=False. Feed complete access units at the intended playback rate; this source does not pace or buffer a file for playback.Poll
take_feedbackand forward keyframe and rate-control requests to the upstream encoder. A demuxer alone cannot produce a new keyframe or adapt the encoded bitrate. Callcapture_framefrom a single producer.Create a source with the initial encoded frame dimensions.
Methods
async def aclose(self) ‑> None-
Expand source code
async def aclose(self) -> None: """Release the native source handle.""" self._ffi_handle.dispose()Release the native source handle.
def capture_frame(self,
frame: EncodedVideoFrame) ‑> bool-
Expand source code
def capture_frame(self, frame: EncodedVideoFrame) -> bool: """Submit a frame; return whether the native source accepted it. The native implementation copies the payload before this call returns. Acceptance does not guarantee delivery to subscribers. """ req = proto_ffi.FfiRequest() capture = req.capture_encoded_video_frame capture.source_handle = self._ffi_handle.handle capture.buffer.data_ptr = get_address(frame.data) capture.buffer.data_len = len(frame.data) capture.codec = frame.codec capture.frame_type = frame.frame_type capture.width = frame.width capture.height = frame.height capture.timestamp_us = frame.timestamp_us if frame.metadata is not None: capture.metadata.CopyFrom(frame.metadata) response: proto_ffi.FfiResponse = FfiClient.instance.request(req) return response.capture_encoded_video_frame.acceptedSubmit a frame; return whether the native source accepted it.
The native implementation copies the payload before this call returns. Acceptance does not guarantee delivery to subscribers.
def take_feedback(self) ‑> EncodedVideoSourceFeedback-
Expand source code
def take_feedback(self) -> EncodedVideoSourceFeedback: """Consume pending feedback, including requests from late subscribers.""" req = proto_ffi.FfiRequest() req.take_encoded_video_source_feedback.source_handle = self._ffi_handle.handle feedback = FfiClient.instance.request(req).take_encoded_video_source_feedback rate_control = None if feedback.HasField("rate_control"): rate_control = EncodedRateControl( target_bitrate_bps=feedback.rate_control.target_bitrate_bps, framerate_fps=feedback.rate_control.framerate_fps, ) return EncodedVideoSourceFeedback(feedback.keyframe_requested, rate_control)Consume pending feedback, including requests from late subscribers.
class EncodedVideoSourceFeedback (keyframe_requested: bool,
rate_control: EncodedRateControl | None)-
Expand source code
@dataclass(frozen=True) class EncodedVideoSourceFeedback: """Encoder feedback consumed since the previous call to ``take_feedback``.""" keyframe_requested: bool rate_control: EncodedRateControl | NoneEncoder feedback consumed since the previous call to
take_feedback.Instance variables
var keyframe_requested : boolvar rate_control : EncodedRateControl | None