|
| 1 | +/* |
| 2 | + * Copyright 2026 LiveKit |
| 3 | + * |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | + * you may not use this file except in compliance with the License. |
| 6 | + * You may obtain a copy of the License at |
| 7 | + * |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | + * |
| 10 | + * Unless required by applicable law or agreed to in writing, software |
| 11 | + * distributed under the License is distributed on an “AS IS” BASIS, |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + * See the License for the specific language governing permissions and |
| 14 | + * limitations under the License. |
| 15 | + */ |
| 16 | + |
| 17 | +#pragma once |
| 18 | + |
| 19 | +#include <cstdint> |
| 20 | +#include <optional> |
| 21 | +#include <vector> |
| 22 | + |
| 23 | +#include "livekit/video_codec.h" |
| 24 | +#include "livekit/video_source.h" |
| 25 | +#include "livekit/visibility.h" |
| 26 | + |
| 27 | +namespace livekit { |
| 28 | + |
| 29 | +/// @brief Video source for publishing pre-encoded access units without re-encoding. |
| 30 | +/// |
| 31 | +/// Capture calls are synchronous and copy the payload before returning. This |
| 32 | +/// type is not safe for concurrent capture calls. Feedback polling can run on |
| 33 | +/// another application thread. |
| 34 | +class LIVEKIT_API EncodedVideoSource final : public VideoSource { |
| 35 | +public: |
| 36 | + /// @brief One complete pre-encoded video access unit. |
| 37 | + struct Frame { |
| 38 | + /// True if this access unit is independently decodable. |
| 39 | + bool is_keyframe = false; |
| 40 | + /// Encoded frame width in pixels. |
| 41 | + /// Set both width and height to zero to use the source resolution. |
| 42 | + std::uint32_t width = 0; |
| 43 | + /// Encoded frame height in pixels. |
| 44 | + /// Set both width and height to zero to use the source resolution. |
| 45 | + std::uint32_t height = 0; |
| 46 | + /// Capture timestamp in microseconds. Set to zero to use the current time. |
| 47 | + std::int64_t timestamp_us = 0; |
| 48 | + /// Complete encoded access-unit payload. |
| 49 | + std::vector<std::uint8_t> data; |
| 50 | + /// Optional packet-trailer metadata. |
| 51 | + std::optional<VideoFrameMetadata> metadata; |
| 52 | + }; |
| 53 | + |
| 54 | + /// @brief Latest encoder rate-control target requested by the publishing pipeline. |
| 55 | + struct RateControl { |
| 56 | + /// Requested target bitrate in bits per second. |
| 57 | + std::uint64_t target_bitrate_bps = 0; |
| 58 | + /// Requested frame rate in frames per second. |
| 59 | + double framerate_fps = 0.0; |
| 60 | + }; |
| 61 | + |
| 62 | + /// @brief Pending feedback from the pre-encoded passthrough encoder. |
| 63 | + struct Feedback { |
| 64 | + /// True when the upstream encoder must produce a key frame. |
| 65 | + bool keyframe_requested = false; |
| 66 | + /// Latest rate-control target, if the publishing pipeline requested one. |
| 67 | + std::optional<RateControl> rate_control; |
| 68 | + }; |
| 69 | + |
| 70 | + /// @brief Create a pre-encoded source for one codec and initial resolution. |
| 71 | + /// @param codec Codec carried by every frame submitted to this source. This |
| 72 | + /// must match TrackPublishOptions::video_codec. |
| 73 | + /// @param width Initial source width in pixels. Must be in [1, 65535]. |
| 74 | + /// @param height Initial source height in pixels. Must be in [1, 65535]. |
| 75 | + /// @throws std::invalid_argument if either dimension is outside [1, 65535]. |
| 76 | + /// @throws std::runtime_error if source creation fails. |
| 77 | + EncodedVideoSource(VideoCodec codec, int width, int height); |
| 78 | + |
| 79 | + /// @brief Codec carried by every frame submitted to this source. |
| 80 | + VideoCodec codec() const noexcept { return codec_; } |
| 81 | + |
| 82 | + /// @brief Submit one complete encoded access unit. |
| 83 | + /// @param frame Encoded frame. Its payload is copied during this call. |
| 84 | + /// @return True if the frame was accepted. |
| 85 | + /// @throws std::invalid_argument if the frame is empty, too large, has only |
| 86 | + /// one zero dimension, or has a dimension above 65535. |
| 87 | + /// @throws std::runtime_error if the FFI request fails. |
| 88 | + [[nodiscard]] bool captureFrame(const Frame& frame) const; |
| 89 | + |
| 90 | + /// @brief Consume pending keyframe and rate-control feedback. |
| 91 | + /// @return Feedback accumulated since the previous call. Rate-control |
| 92 | + /// updates use latest-value-wins semantics. |
| 93 | + /// @throws std::runtime_error if the FFI request fails. |
| 94 | + [[nodiscard]] Feedback takeFeedback() const; |
| 95 | + |
| 96 | +private: |
| 97 | + using VideoSource::captureFrame; |
| 98 | + |
| 99 | + VideoCodec codec_; |
| 100 | +}; |
| 101 | + |
| 102 | +} // namespace livekit |
0 commit comments