summaryrefslogtreecommitdiff
path: root/chromium/media/base/text_ranges.cc
blob: a88cc90c076c9ed53f389f713a1f0cd142eb7b8e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// 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/logging.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<RangeMap::iterator, bool> 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