| /* |
| * Copyright (c) 2023 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. |
| */ |
| |
| #include "test/pc/e2e/analyzer/video/dvqa/frames_storage.h" |
| |
| #include <cstdint> |
| #include <utility> |
| |
| #include "absl/types/optional.h" |
| #include "api/units/timestamp.h" |
| #include "api/video/video_frame.h" |
| |
| namespace webrtc { |
| |
| void FramesStorage::Add(const VideoFrame& frame, Timestamp captured_time) { |
| heap_.push_back(HeapNode{.frame = frame, .captured_time = captured_time}); |
| frame_id_index_[frame.id()] = heap_.size() - 1; |
| Heapify(heap_.size() - 1); |
| RemoveTooOldFrames(); |
| } |
| |
| absl::optional<VideoFrame> FramesStorage::Get(uint16_t frame_id) { |
| auto it = frame_id_index_.find(frame_id); |
| if (it == frame_id_index_.end()) { |
| return absl::nullopt; |
| } |
| |
| return heap_[it->second].frame; |
| } |
| |
| void FramesStorage::Remove(uint16_t frame_id) { |
| RemoveInternal(frame_id); |
| RemoveTooOldFrames(); |
| } |
| |
| void FramesStorage::RemoveInternal(uint16_t frame_id) { |
| auto it = frame_id_index_.find(frame_id); |
| if (it == frame_id_index_.end()) { |
| return; |
| } |
| |
| size_t index = it->second; |
| frame_id_index_.erase(it); |
| |
| // If it's not the last element in the heap, swap the last element in the heap |
| // with element to remove. |
| if (index != heap_.size() - 1) { |
| heap_[index] = std::move(heap_[heap_.size() - 1]); |
| frame_id_index_[heap_[index].frame.id()] = index; |
| } |
| |
| // Remove the last element. |
| heap_.pop_back(); |
| |
| if (index < heap_.size()) { |
| Heapify(index); |
| } |
| } |
| |
| void FramesStorage::Heapify(size_t index) { |
| HeapifyUp(index); |
| HeapifyDown(index); |
| } |
| |
| void FramesStorage::HeapifyUp(size_t index) { |
| if (index == 0) { |
| return; |
| } |
| RTC_CHECK_LT(index, heap_.size()); |
| size_t parent = index / 2; |
| if (heap_[parent].captured_time <= heap_[index].captured_time) { |
| return; |
| } |
| HeapNode tmp = std::move(heap_[index]); |
| heap_[index] = std::move(heap_[parent]); |
| heap_[parent] = std::move(tmp); |
| |
| frame_id_index_[heap_[index].frame.id()] = index; |
| frame_id_index_[heap_[parent].frame.id()] = parent; |
| |
| HeapifyUp(parent); |
| } |
| |
| void FramesStorage::HeapifyDown(size_t index) { |
| RTC_CHECK_GE(index, 0); |
| RTC_CHECK_LT(index, heap_.size()); |
| |
| size_t left_child = 2 * index; |
| size_t right_child = 2 * index + 1; |
| |
| if (left_child >= heap_.size()) { |
| return; |
| } |
| size_t smallest_child = left_child; |
| if (right_child < heap_.size() && |
| heap_[right_child].captured_time < heap_[left_child].captured_time) { |
| smallest_child = right_child; |
| } |
| |
| if (heap_[index].captured_time <= heap_[smallest_child].captured_time) { |
| return; |
| } |
| |
| HeapNode tmp = std::move(heap_[index]); |
| heap_[index] = std::move(heap_[smallest_child]); |
| heap_[smallest_child] = std::move(tmp); |
| |
| frame_id_index_[heap_[index].frame.id()] = index; |
| frame_id_index_[heap_[smallest_child].frame.id()] = smallest_child; |
| |
| HeapifyDown(smallest_child); |
| } |
| |
| void FramesStorage::RemoveTooOldFrames() { |
| Timestamp now = clock_->CurrentTime(); |
| while (!heap_.empty() && |
| (heap_[0].captured_time + max_storage_duration_) < now) { |
| RemoveInternal(heap_[0].frame.id()); |
| } |
| } |
| |
| } // namespace webrtc |