1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "media/base/text_ranges.h" 6 7 #include "base/logging.h" 8 9 namespace media { 10 11 TextRanges::TextRanges() { 12 Reset(); 13 } 14 15 TextRanges::~TextRanges() { 16 } 17 18 void TextRanges::Reset() { 19 curr_range_itr_ = range_map_.end(); 20 } 21 22 bool TextRanges::AddCue(base::TimeDelta start_time) { 23 typedef RangeMap::iterator Itr; 24 25 if (curr_range_itr_ == range_map_.end()) { 26 // There is no active time range, so this is the first AddCue() 27 // attempt that follows a Reset(). 28 29 if (range_map_.empty()) { 30 NewRange(start_time); 31 return true; 32 } 33 34 if (start_time < range_map_.begin()->first) { 35 NewRange(start_time); 36 return true; 37 } 38 39 const Itr itr = --Itr(range_map_.upper_bound(start_time)); 40 DCHECK(start_time >= itr->first); 41 42 Range& range = itr->second; 43 44 if (start_time > range.last_time()) { 45 NewRange(start_time); 46 return true; 47 } 48 49 range.ResetCount(start_time); 50 curr_range_itr_ = itr; 51 return false; 52 } 53 54 DCHECK(start_time >= curr_range_itr_->first); 55 56 Range& curr_range = curr_range_itr_->second; 57 58 if (start_time <= curr_range.last_time()) 59 return curr_range.AddCue(start_time); 60 61 const Itr next_range_itr = ++Itr(curr_range_itr_); 62 63 if (next_range_itr != range_map_.end()) { 64 DCHECK(next_range_itr->first > curr_range.last_time()); 65 DCHECK(start_time <= next_range_itr->first); 66 67 if (start_time == next_range_itr->first) { 68 // We have walked off the current range, and onto the next one. 69 // There is now no ambiguity about where the current time range 70 // ends, and so we coalesce the current and next ranges. 71 72 Merge(curr_range, next_range_itr); 73 return false; 74 } 75 } 76 77 // Either |curr_range| is the last range in the map, or there is a 78 // next range beyond |curr_range|, but its start time is ahead of 79 // this cue's start time. In either case, this cue becomes the new 80 // last_time for |curr_range|. Eventually we will see a cue whose 81 // time matches the start time of the next range, in which case we 82 // coalesce the current and next ranges. 83 84 curr_range.SetLastTime(start_time); 85 return true; 86 } 87 88 size_t TextRanges::RangeCountForTesting() const { 89 return range_map_.size(); 90 } 91 92 void TextRanges::NewRange(base::TimeDelta start_time) { 93 Range range; 94 range.SetLastTime(start_time); 95 96 std::pair<RangeMap::iterator, bool> result = 97 range_map_.insert(std::make_pair(start_time, range)); 98 DCHECK(result.second); 99 100 curr_range_itr_ = result.first; 101 } 102 103 void TextRanges::Merge( 104 Range& curr_range, 105 const RangeMap::iterator& next_range_itr) { 106 curr_range = next_range_itr->second; 107 curr_range.ResetCount(next_range_itr->first); 108 range_map_.erase(next_range_itr); 109 } 110 111 void TextRanges::Range::ResetCount(base::TimeDelta start_time) { 112 count_ = (start_time < last_time_) ? 0 : 1; 113 } 114 115 void TextRanges::Range::SetLastTime(base::TimeDelta last_time) { 116 last_time_ = last_time; 117 count_ = 1; 118 max_count_ = 1; 119 } 120 121 bool TextRanges::Range::AddCue(base::TimeDelta start_time) { 122 if (start_time < last_time_) { 123 DCHECK_EQ(count_, 0); 124 return false; 125 } 126 127 DCHECK(start_time == last_time_); 128 129 ++count_; 130 if (count_ <= max_count_) 131 return false; 132 133 ++max_count_; 134 return true; 135 } 136 137 base::TimeDelta TextRanges::Range::last_time() const { 138 return last_time_; 139 } 140 141 } // namespace media 142