| /* | |
| * Copyright (c) 2026 The WebRTC project authors. All Rights Reserved. | |
| * | |
| * Use of this source code is governed by a BSD-style license | |
| * that can be found in the LICENSE file in the root of the source | |
| * tree. An additional intellectual property rights grant can be found | |
| * in the file PATENTS. All contributing project authors may | |
| * be found in the AUTHORS file in the root of the source tree. | |
| */ | |
| #ifndef MODULES_VIDEO_CODING_SVC_REFERENCE_BUFFER_MANAGER_H_ | |
| #define MODULES_VIDEO_CODING_SVC_REFERENCE_BUFFER_MANAGER_H_ | |
| #include <cstdint> | |
| #include <optional> | |
| #include <span> | |
| #include <string> | |
| #include <vector> | |
| #include "api/units/timestamp.h" | |
| #include "api/video_codecs/video_encoder_factory_interface.h" | |
| #include "api/video_codecs/video_encoder_interface.h" | |
| namespace webrtc { | |
| // Keeps track of which encoder reference buffers are free, reserved for an | |
| // ongoing encode or populated with a frame, while enforcing the rules of the | |
| // encoder's buffer space type. | |
| // | |
| // Buffers are reserved before encoding and populated via `SetBufferMetadata()` | |
| // once the encode succeeds. Reserved but unpopulated buffers are never returned | |
| // by queries nor invalidated by keyframes. "Last" means most recently | |
| // populated. | |
| class ReferenceBufferManager { | |
| public: | |
| using PredictionConstraints = | |
| VideoEncoderFactoryInterface::Capabilities::PredictionConstraints; | |
| // Handle to an encoder reference buffer. | |
| struct Buffer { | |
| // Encoder buffer index. | |
| int id = 0; | |
| // Owning instance for `kMultiInstance`, otherwise the reserving layer. | |
| int spatial_id = 0; | |
| friend bool operator==(const Buffer&, const Buffer&) = default; | |
| template <typename Sink> | |
| friend void AbslStringify(Sink& sink, const Buffer& buffer) { | |
| sink.Append("{id=" + std::to_string(buffer.id) + | |
| ", spatial_id=" + std::to_string(buffer.spatial_id) + "}"); | |
| } | |
| }; | |
| // Describes the frame stored in a buffer. | |
| struct Metadata { | |
| VideoEncoderInterface::FrameType type = | |
| VideoEncoderInterface::FrameType::kDeltaFrame; | |
| int spatial_id = 0; | |
| std::optional<int> temporal_id; | |
| Timestamp timestamp = Timestamp::Zero(); | |
| std::optional<int> frame_id; | |
| bool acknowledged = false; | |
| }; | |
| explicit ReferenceBufferManager(const PredictionConstraints& constraints); | |
| // Number of buffers that `ReserveBuffer(spatial_id)` could still reserve. | |
| int NumFreeBuffers(int spatial_id) const; | |
| // Reserves the lowest indexed free buffer, or nullopt if none is free. | |
| std::optional<Buffer> ReserveBuffer(int spatial_id); | |
| // Populates a reserved buffer. A keyframe first releases all populated | |
| // buffers that it invalidates according to the buffer space type. | |
| void SetBufferMetadata(Buffer buffer, const Metadata& metadata); | |
| // Nullopt unless `buffer` is populated. | |
| std::optional<Metadata> GetMetadata(Buffer buffer) const; | |
| // Last buffer with the given temporal id. | |
| std::optional<Buffer> Get(int spatial_id, int temporal_id) const; | |
| // Last buffer of the base temporal layer (`temporal_id == 0`). | |
| std::optional<Buffer> GetLastTl0(int spatial_id) const; | |
| // Last buffer of each temporal layer below `temporal_id`, in increasing | |
| // temporal id order. Layers without a buffer are skipped. | |
| std::vector<Buffer> GetAllLowerTemporalLayers(int spatial_id, | |
| int temporal_id) const; | |
| // Returns `buffers` ordered most recently populated first, which is the | |
| // reference order expected by `VideoEncoderInterface`. Unpopulated buffers | |
| // are skipped. | |
| std::vector<Buffer> SortByRecency(std::span<const Buffer> buffers) const; | |
| // Marks all buffers holding `frame_id` as acknowledged. Unknown ids, e.g. | |
| // for buffers already released, are ignored. | |
| void MarkFrameAsAcknowledged(int spatial_id, int frame_id); | |
| // Last buffer holding an acknowledged frame. | |
| std::optional<Buffer> GetLastAcknowledgedFrame(int spatial_id) const; | |
| // Frees a reserved or populated buffer. No-op if already free. | |
| void ReleaseBuffer(Buffer buffer); | |
| // Frees populated buffers with temporal id above `temporal_id`. | |
| void ReleaseAllHigherTemporalLayers(int spatial_id, int temporal_id); | |
| // Frees populated buffers with a timestamp before `cutoff`. | |
| void ReleaseAllPriorTemporalUnits(int spatial_id, Timestamp cutoff); | |
| // Frees all reserved and populated buffers of `spatial_id`. | |
| void ReleaseAllBuffers(int spatial_id); | |
| private: | |
| // Internal state of a single encoder reference buffer, whereas `Buffer` is a | |
| // lightweight public handle. The slot for `buffer` is at index `buffer.id` in | |
| // `Pool(buffer.spatial_id)`. | |
| struct Slot { | |
| bool reserved = false; | |
| int spatial_id = 0; | |
| std::optional<Metadata> metadata; | |
| int64_t sequence_number = 0; | |
| }; | |
| std::span<Slot> Pool(int spatial_id); | |
| std::span<const Slot> Pool(int spatial_id) const; | |
| Slot& GetSlot(Buffer buffer); | |
| // Last populated buffer of `spatial_id` matching `predicate`. | |
| template <typename Predicate> | |
| std::optional<Buffer> FindLast(int spatial_id, Predicate predicate) const; | |
| // Frees populated buffers of `spatial_id` matching `predicate`. | |
| template <typename Predicate> | |
| void ReleaseIf(int spatial_id, Predicate predicate); | |
| const PredictionConstraints::BufferSpaceType buffer_space_type_; | |
| const int num_spatial_layers_; | |
| // One pool per spatial layer for `kMultiInstance`, otherwise a single one. | |
| std::vector<std::vector<Slot>> pools_; | |
| int64_t next_sequence_number_ = 0; | |
| }; | |
| } // namespace webrtc | |
| #endif // MODULES_VIDEO_CODING_SVC_REFERENCE_BUFFER_MANAGER_H_ |