// Copyright 2019 The MediaPipe Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "mediapipe/util/tracking/streaming_buffer.h" #include "absl/strings/str_cat.h" namespace mediapipe { StreamingBuffer::StreamingBuffer( const std::vector& data_configuration, int overlap) : overlap_(overlap) { CHECK_GE(overlap, 0); for (auto& item : data_configuration) { CHECK(data_config_.find(item.first) == data_config_.end()) << "Tag " << item.first << " already exists"; data_config_[item.first] = item.second; // Init deque. data_[item.first].clear(); } } bool StreamingBuffer::HasTag(const std::string& tag) const { return data_config_.find(tag) != data_config_.end(); } bool StreamingBuffer::HasTags(const std::vector& tags) const { for (const auto& tag : tags) { if (!HasTag(tag)) { return false; } } return true; } int StreamingBuffer::BufferSize(const std::string& tag) const { CHECK(HasTag(tag)); return data_.find(tag)->second.size(); } int StreamingBuffer::MaxBufferSize() const { int max_buffer = 0; for (const auto& elem : data_) { max_buffer = std::max(max_buffer, BufferSize(elem.first)); } return max_buffer; } bool StreamingBuffer::HaveEqualSize( const std::vector& tags) const { if (tags.size() < 2) { return true; } int first_size = BufferSize(tags[0]); for (int k = 1; k < tags.size(); ++k) { if (BufferSize(tags[1]) != first_size) { return false; } } return true; } std::vector StreamingBuffer::AllTags() const { std::vector all_tags; for (auto& item : data_config_) { all_tags.push_back(item.first); } return all_tags; } bool StreamingBuffer::TruncateBuffer(bool flush) { // Only truncate if sufficient elements have been buffered. const int elems_to_clear = std::max(0, MaxBufferSize() - (flush ? 0 : overlap_)); if (elems_to_clear == 0) { return true; } bool is_consistent = true; for (auto& item : data_) { auto& buffer = item.second; const int buffer_elems_to_clear = std::min(elems_to_clear, buffer.size()); if (buffer_elems_to_clear < elems_to_clear) { LOG(WARNING) << "For tag " << item.first << " got " << elems_to_clear - buffer_elems_to_clear << "fewer elements than buffer can hold."; is_consistent = false; } buffer.erase(buffer.begin(), buffer.begin() + buffer_elems_to_clear); } first_frame_index_ += elems_to_clear; const int remaining_elems = flush ? 0 : overlap_; for (const auto& item : data_) { const auto& buffer = item.second; if (buffer.size() != remaining_elems) { LOG(WARNING) << "After trunctation, for tag " << item.first << "got " << buffer.size() << " elements, " << "expected " << remaining_elems; is_consistent = false; } } return is_consistent; } void StreamingBuffer::DiscardDatum(const std::string& tag, int num_frames) { CHECK(HasTag(tag)); auto& queue = data_[tag]; if (queue.empty()) { return; } queue.erase(queue.begin(), queue.begin() + std::min(queue.size(), num_frames)); } void StreamingBuffer::DiscardDatumFromEnd(const std::string& tag, int num_frames) { CHECK(HasTag(tag)); auto& queue = data_[tag]; if (queue.empty()) { return; } queue.erase(queue.end() - std::min(queue.size(), num_frames), queue.end()); } void StreamingBuffer::DiscardData(const std::vector& tags, int num_frames) { for (const std::string& tag : tags) { DiscardDatum(tag, num_frames); } } } // namespace mediapipe