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