blob: 8f647d8c5fbe0c22ec55a9ea5b545f13b1717c5b [file] [log] [blame]
// 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)
namespace amlogic_decoder {
// 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;
}
} // namespace amlogic_decoder