| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "pts_manager.h" |
| |
| #include <inttypes.h> |
| #include <zircon/assert.h> |
| |
| #include "lib/media/extend_bits/extend_bits.h" |
| #include "macros.h" |
| |
| #ifndef AMLOGIC_PTS_DLOG_ENABLE |
| #define AMLOGIC_PTS_DLOG_ENABLE 0 |
| #endif |
| |
| #define PTS_DLOG(fmt, ...) \ |
| do { \ |
| if (AMLOGIC_PTS_DLOG_ENABLE) { \ |
| LOG(INFO, fmt, ##__VA_ARGS__); \ |
| } \ |
| } while (0) |
| |
| // h264 has HW stream offset counter with 0xfffffff max - 28 bit - 256 MiB cycle period |
| // vp9 has a 32 bit stream offset counter. |
| void PtsManager::SetLookupBitWidth(uint32_t lookup_bit_width) { |
| PTS_DLOG("SetLookupBitWidth() lookup_bit_width: %u", lookup_bit_width); |
| std::lock_guard<std::mutex> lock(lock_); |
| ZX_DEBUG_ASSERT(lookup_bit_width_ == 64 && lookup_bit_width != 64); |
| lookup_bit_width_ = lookup_bit_width; |
| } |
| |
| void PtsManager::InsertPts(uint64_t offset, bool has_pts, uint64_t pts) { |
| PTS_DLOG("InsertPts() offset: 0x%" PRIx64 " has_pts: %d pts: %" PRIx64, offset, has_pts, pts); |
| std::lock_guard<std::mutex> lock(lock_); |
| |
| ZX_DEBUG_ASSERT(has_pts || !pts); |
| |
| // caller should not insert duplicates |
| ZX_DEBUG_ASSERT(offset_to_result_.find(offset) == offset_to_result_.end()); |
| // caller should set offsets in order |
| ZX_DEBUG_ASSERT(offset_to_result_.empty() || offset > offset_to_result_.rbegin()->first); |
| |
| offset_to_result_.emplace(std::make_pair(offset, LookupResult(false, has_pts, pts))); |
| |
| // Erase the oldest PTSes. See the definition of kMaxEntriesToKeep for how we know this will be |
| // enough entries. |
| while (offset_to_result_.size() > kMaxEntriesToKeep) { |
| offset_to_result_.erase(offset_to_result_.begin()); |
| } |
| } |
| |
| void PtsManager::SetEndOfStreamOffset(uint64_t end_of_stream_offset) { |
| PTS_DLOG("SetEndOfStreamOffset() end_of_stream_offset: %" PRIx64, end_of_stream_offset); |
| std::lock_guard<std::mutex> lock(lock_); |
| |
| // caller should not insert duplicates |
| ZX_DEBUG_ASSERT(offset_to_result_.find(end_of_stream_offset) == offset_to_result_.end()); |
| // caller should set offsets in order |
| ZX_DEBUG_ASSERT(offset_to_result_.empty() || |
| end_of_stream_offset > (*offset_to_result_.rbegin()).first); |
| |
| // caller should only set end of stream offset once |
| ZX_DEBUG_ASSERT(offset_to_result_.empty() || |
| !(*offset_to_result_.rbegin()).second.is_end_of_stream()); |
| |
| offset_to_result_.emplace(std::make_pair(end_of_stream_offset, LookupResult(true, false, 0))); |
| } |
| |
| const PtsManager::LookupResult PtsManager::Lookup(uint64_t offset) { |
| std::lock_guard<std::mutex> lock(lock_); |
| ZX_DEBUG_ASSERT(lookup_bit_width_ == 64 || |
| offset < (static_cast<uint64_t>(1) << lookup_bit_width_)); |
| |
| // last_inserted_offset is known-good in the sense that it's known to be a valid full-width |
| // uint64_t input stream offset. We prefer to anchor on this value rather than incrementally |
| // anchoring on the last bit-extended offset passed in as a query, since we know with higher |
| // certainty that this value is correct (and both those options are fairly near the bit-extended |
| // form of the logical offset coming into this method). |
| uint64_t last_inserted_offset = GetLastInsertedOffset(); |
| |
| // Basically we're determining whether offset is logically above or logically below |
| // last_inserted_offset. |
| offset = ExtendBits(last_inserted_offset, offset, lookup_bit_width_); |
| |
| auto it = offset_to_result_.upper_bound(offset); |
| // Check if this offset is < any element in the list. |
| if (it == offset_to_result_.begin()) { |
| PTS_DLOG("it == offset_to_result_.begin() -- offset: 0x%" PRIx64, offset); |
| return PtsManager::LookupResult(false, false, 0); |
| } |
| // Decrement to find the pts corresponding to the last offset <= |offset|. |
| --it; |
| |
| if (AMLOGIC_PTS_DLOG_ENABLE) { |
| const PtsManager::LookupResult& result = it->second; |
| if (result.is_end_of_stream()) { |
| PTS_DLOG("Lookup() offset: 0x%" PRIx64 " EOS", offset); |
| } else { |
| PTS_DLOG("Lookup() offset: 0x%" PRIx64 " has_pts: %d pts: 0x%" PRIx64 |
| " offset - found: 0x%" PRIx64 " entries beyond found: %u", |
| offset, result.has_pts(), result.pts(), offset - it->first, |
| CountEntriesBeyondLocked(it->first)); |
| } |
| } |
| |
| return it->second; |
| } |
| |
| uint32_t PtsManager::CountEntriesBeyond(uint64_t threshold_offset) const { |
| std::lock_guard<std::mutex> lock(lock_); |
| return CountEntriesBeyondLocked(threshold_offset); |
| } |
| |
| uint32_t PtsManager::CountEntriesBeyondLocked(uint64_t threshold_offset) const { |
| // Shorter bit width not implemented for this method yet. |
| ZX_DEBUG_ASSERT(lookup_bit_width_ == 64); |
| auto it = offset_to_result_.upper_bound(threshold_offset); |
| uint32_t count = 0; |
| while (it != offset_to_result_.end()) { |
| ++it; |
| ++count; |
| } |
| return count; |
| } |
| |
| // The last inserted offset is offset_to_result_.rbegin()->first, unless empty() in which case |
| // logically 0. |
| uint64_t PtsManager::GetLastInsertedOffset() { |
| if (offset_to_result_.empty()) { |
| return 0; |
| } |
| return offset_to_result_.rbegin()->first; |
| } |