// Copyright 2014 The Chromium 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 "media/base/text_ranges.h" #include "base/check_op.h" namespace media { TextRanges::TextRanges() { Reset(); } TextRanges::~TextRanges() = default; void TextRanges::Reset() { curr_range_itr_ = range_map_.end(); } bool TextRanges::AddCue(base::TimeDelta start_time) { typedef RangeMap::iterator Itr; if (curr_range_itr_ == range_map_.end()) { // There is no active time range, so this is the first AddCue() // attempt that follows a Reset(). if (range_map_.empty()) { NewRange(start_time); return true; } if (start_time < range_map_.begin()->first) { NewRange(start_time); return true; } const Itr itr = --Itr(range_map_.upper_bound(start_time)); DCHECK(start_time >= itr->first); Range& range = itr->second; if (start_time > range.last_time()) { NewRange(start_time); return true; } range.ResetCount(start_time); curr_range_itr_ = itr; return false; } DCHECK(start_time >= curr_range_itr_->first); Range& curr_range = curr_range_itr_->second; if (start_time <= curr_range.last_time()) return curr_range.AddCue(start_time); const Itr next_range_itr = ++Itr(curr_range_itr_); if (next_range_itr != range_map_.end()) { DCHECK(next_range_itr->first > curr_range.last_time()); DCHECK(start_time <= next_range_itr->first); if (start_time == next_range_itr->first) { // We have walked off the current range, and onto the next one. // There is now no ambiguity about where the current time range // ends, and so we coalesce the current and next ranges. Merge(curr_range, next_range_itr); return false; } } // Either |curr_range| is the last range in the map, or there is a // next range beyond |curr_range|, but its start time is ahead of // this cue's start time. In either case, this cue becomes the new // last_time for |curr_range|. Eventually we will see a cue whose // time matches the start time of the next range, in which case we // coalesce the current and next ranges. curr_range.SetLastTime(start_time); return true; } size_t TextRanges::RangeCountForTesting() const { return range_map_.size(); } void TextRanges::NewRange(base::TimeDelta start_time) { Range range; range.SetLastTime(start_time); std::pair result = range_map_.insert(std::make_pair(start_time, range)); DCHECK(result.second); curr_range_itr_ = result.first; } void TextRanges::Merge( Range& curr_range, const RangeMap::iterator& next_range_itr) { curr_range = next_range_itr->second; curr_range.ResetCount(next_range_itr->first); range_map_.erase(next_range_itr); } void TextRanges::Range::ResetCount(base::TimeDelta start_time) { count_ = (start_time < last_time_) ? 0 : 1; } void TextRanges::Range::SetLastTime(base::TimeDelta last_time) { last_time_ = last_time; count_ = 1; max_count_ = 1; } bool TextRanges::Range::AddCue(base::TimeDelta start_time) { if (start_time < last_time_) { DCHECK_EQ(count_, 0); return false; } DCHECK(start_time == last_time_); ++count_; if (count_ <= max_count_) return false; ++max_count_; return true; } base::TimeDelta TextRanges::Range::last_time() const { return last_time_; } } // namespace media