summaryrefslogtreecommitdiff
path: root/chromium/media/filters/source_buffer_range_by_pts.h
blob: 353f744f9d0d4f7bf30658a1618796b923a8b928 (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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
// Copyright 2017 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.

#ifndef MEDIA_FILTERS_SOURCE_BUFFER_RANGE_BY_PTS_H_
#define MEDIA_FILTERS_SOURCE_BUFFER_RANGE_BY_PTS_H_

#include <stddef.h>
#include <map>
#include <memory>

#include "media/filters/source_buffer_range.h"

namespace media {

class MEDIA_EXPORT SourceBufferRangeByPts : public SourceBufferRange {
 public:
  // Creates a range with |new_buffers|. |new_buffers| cannot be empty and the
  // front of |new_buffers| must be a keyframe.
  // |range_start_pts| refers to the starting timestamp for the coded
  // frame group to which these buffers belong.
  SourceBufferRangeByPts(GapPolicy gap_policy,
                         const BufferQueue& new_buffers,
                         base::TimeDelta range_start_pts,
                         const InterbufferDistanceCB& interbuffer_distance_cb);

  ~SourceBufferRangeByPts() override;

  void DeleteAll(BufferQueue* deleted_buffers) override;

  // Appends the buffers from |range| into this range.
  // The first buffer in |range| must come directly after the last buffer
  // in this range.
  // If |transfer_current_position| is true, |range|'s |next_buffer_index_|
  // is transfered to this SourceBufferRange.
  // Note: Use these only to merge existing ranges. |range|'s first buffer
  // timestamp must be adjacent to this range. No group start timestamp
  // adjacency is involved in these methods.
  // During append, |highest_frame_| is updated, if necessary.
  void AppendRangeToEnd(const SourceBufferRangeByPts& range,
                        bool transfer_current_position);
  bool CanAppendRangeToEnd(const SourceBufferRangeByPts& range) const;

  // Appends |buffers| to the end of the range and updates |keyframe_map_| as
  // it encounters new keyframes.
  // If |new_buffers_group_start_pts| is kNoTimestamp, then the
  // first buffer in |buffers| must come directly after the last buffer in this
  // range (within the fudge room) - specifically, if the first buffer in
  // |buffers| is not a keyframe, then it must be next in DTS order w.r.t. last
  // buffer in |buffers|. Otherwise, it's a keyframe that must be next in PTS
  // order w.r.t. |highest_frame_| or be immediately adjacent to the last buffer
  // in this range if that buffer has estimated duration (only allowed in WebM
  // streams).
  // If |new_buffers_group_start_pts| is set otherwise, then that time must come
  // directly after |highest_frame_| (within the fudge room), or directly after
  // the last buffered frame if it has estimated duration (only allowed in WebM
  // streams), and the first buffer in |buffers| must be a keyframe.
  // The latter scenario is required when a muxed coded frame group has such a
  // large jagged start across tracks that its first buffer is not within the
  // fudge room, yet its group start was.
  // The conditions around estimated duration are handled by
  // AllowableAppendAfterEstimatedDuration, and are intended to solve the edge
  // case in the SourceBufferStreamTest
  // MergeAllowedIfRangeEndTimeWithEstimatedDurationMatchesNextRangeStart.
  // During append, |highest_frame_| is updated, if necessary.
  void AppendBuffersToEnd(const BufferQueue& buffers,
                          base::TimeDelta new_buffers_group_start_timestamp);
  bool AllowableAppendAfterEstimatedDuration(
      const BufferQueue& buffers,
      base::TimeDelta new_buffers_group_start_pts) const;
  bool CanAppendBuffersToEnd(const BufferQueue& buffers,
                             base::TimeDelta new_buffers_group_start_pts) const;

  // Updates |next_buffer_index_| to point to the keyframe with presentation
  // timestamp at or before |timestamp|. Assumes |timestamp| is valid and in
  // this range.
  void Seek(base::TimeDelta timestamp);

  // Returns true if the range has enough data to seek to the specified
  // |timestamp|, false otherwise.
  bool CanSeekTo(base::TimeDelta timestamp) const;

  // Return the config ID for the buffer at |timestamp|. Precondition: callers
  // must first verify CanSeekTo(timestamp) == true.
  int GetConfigIdAtTime(base::TimeDelta timestamp) const;

  // Return true if all buffers in range of [start, end] have the same config
  // ID. Precondition: callers must first verify that
  // CanSeekTo(start) ==  CanSeekTo(end) == true.
  bool SameConfigThruRange(base::TimeDelta start, base::TimeDelta end) const;

  // Finds the next keyframe from |buffers_| starting at or after |timestamp|
  // and creates and returns a new SourceBufferRangeByPts with the buffers from
  // that keyframe onward. The buffers in the new SourceBufferRangeByPts are
  // moved out of this range. The start time of the new SourceBufferRangeByPts
  // is set to the later of |timestamp| and this range's GetStartTimestamp().
  // Note that this may result in temporary overlap of the new range and this
  // range until the caller truncates any nonkeyframes out of this range with
  // time > |timestamp|.  If there is no keyframe at or after |timestamp|,
  // SplitRange() returns null and this range is unmodified. This range can
  // become empty if |timestamp| <= the PTS of the first buffer in this range.
  // |highest_frame_| is updated, if necessary.
  std::unique_ptr<SourceBufferRangeByPts> SplitRange(base::TimeDelta timestamp);

  // Deletes the buffers from this range starting at |timestamp|, exclusive if
  // |is_exclusive| is true, inclusive otherwise.
  // Resets |next_buffer_index_| if the buffer at |next_buffer_index_| was
  // deleted, and deletes the |keyframe_map_| entries for the buffers that
  // were removed.
  // |highest_frame_| is updated, if necessary.
  // |deleted_buffers| contains the buffers that were deleted from this range,
  // starting at the buffer that had been at |next_buffer_index_|.
  // Returns true if everything in the range was deleted. Otherwise
  // returns false.
  bool TruncateAt(base::TimeDelta timestamp,
                  BufferQueue* deleted_buffers,
                  bool is_exclusive);

  // Deletes a GOP from the front or back of the range and moves these
  // buffers into |deleted_buffers|. Returns the number of bytes deleted from
  // the range (i.e. the size in bytes of |deleted_buffers|).
  // |highest_frame_| is updated, if necessary.
  // This range must NOT be empty when these methods are called.
  // The GOP being deleted must NOT contain the next buffer position.
  size_t DeleteGOPFromFront(BufferQueue* deleted_buffers);
  size_t DeleteGOPFromBack(BufferQueue* deleted_buffers);

  // Gets the range of GOP to secure at least |bytes_to_free| from
  // [|start_timestamp|, |end_timestamp|).
  // Returns the size of the buffers to secure if the buffers of
  // [|start_timestamp|, |end_removal_timestamp|) is removed.
  // Will not update |end_removal_timestamp| if the returned size is 0.
  size_t GetRemovalGOP(base::TimeDelta start_timestamp,
                       base::TimeDelta end_timestamp,
                       size_t bytes_to_free,
                       base::TimeDelta* end_removal_timestamp) const;

  // Returns true iff the buffered end time of the first GOP in this range is
  // at or before |media_time|.
  bool FirstGOPEarlierThanMediaTime(base::TimeDelta media_time) const;

  // Indicates whether the GOP at the beginning or end of the range contains the
  // next buffer position.
  bool FirstGOPContainsNextBufferPosition() const;
  bool LastGOPContainsNextBufferPosition() const;

  // Returns the timestamp of the next buffer that will be returned from
  // GetNextBuffer(), or kNoTimestamp if the timestamp is unknown.
  base::TimeDelta GetNextTimestamp() const;

  // Returns the start timestamp of the range.
  base::TimeDelta GetStartTimestamp() const;

  // Returns the highest presentation timestamp of frames in the last GOP in the
  // range.
  base::TimeDelta GetEndTimestamp() const;

  // Returns the timestamp for the end of the buffered region in this range.
  // This is an approximation if the duration for the buffer with highest PTS in
  // the last GOP in the range is unset.
  base::TimeDelta GetBufferedEndTimestamp() const;

  // Returns whether a buffer with a starting timestamp of |timestamp| would
  // belong in this range. This includes a buffer that would be appended to
  // the end of the range.
  bool BelongsToRange(base::TimeDelta timestamp) const;

  // Returns the highest time from among GetStartTimestamp() and frame timestamp
  // (in order in |buffers_| beginning at the first keyframe at or before
  // |timestamp|) for buffers in this range up to and including |timestamp|.
  // Note that |timestamp| must belong to this range.
  base::TimeDelta FindHighestBufferedTimestampAtOrBefore(
      base::TimeDelta timestamp) const;

  // Gets the timestamp for the keyframe that is at or after |timestamp|. If
  // there isn't such a keyframe in the range then kNoTimestamp is returned.
  // If |timestamp| is in the "gap" between the value returned by
  // GetStartTimestamp() and the timestamp on the first buffer in |buffers_|,
  // then |timestamp| is returned.
  base::TimeDelta NextKeyframeTimestamp(base::TimeDelta timestamp) const;

  // Gets the timestamp for the closest keyframe that is <= |timestamp|. If
  // there isn't a keyframe before |timestamp| or |timestamp| is outside
  // this range, then kNoTimestamp is returned.
  base::TimeDelta KeyframeBeforeTimestamp(base::TimeDelta timestamp) const;

  // Adds all buffers which overlap [start, end) to the end of |buffers|.  If
  // no buffers exist in the range returns false, true otherwise.
  // This method is used for finding audio splice overlap buffers, so all
  // buffers are expected to be keyframes here (so DTS doesn't matter at all).
  bool GetBuffersInRange(base::TimeDelta start,
                         base::TimeDelta end,
                         BufferQueue* buffers) const;

 private:
  typedef std::map<base::TimeDelta, int> KeyframeMap;

  // Helper method for Appending |range| to the end of this range.  If |range|'s
  // first buffer time is before the time of the last buffer in this range,
  // returns kNoTimestamp.  Otherwise, returns the closest time within
  // [|range|'s start time, |range|'s first buffer time] that is at or after the
  // this range's GetEndTimestamp(). This allows |range| to potentially be
  // determined to be adjacent within fudge room for appending to the end of
  // this range, especially if |range| has a start time that is before its first
  // buffer's time.
  base::TimeDelta NextRangeStartTimeForAppendRangeToEnd(
      const SourceBufferRangeByPts& range) const;

  // Returns an index (or iterator) into |buffers_| pointing to the first buffer
  // at or after |timestamp|.  If |skip_given_timestamp| is true, this returns
  // the first buffer with timestamp strictly greater than |timestamp|. If
  // |buffers_| has no such buffer, returns |buffers_.size()| (or
  // |buffers_.end()|).
  size_t GetBufferIndexAt(base::TimeDelta timestamp,
                          bool skip_given_timestamp) const;
  BufferQueue::const_iterator GetBufferItrAt(base::TimeDelta timestamp,
                                             bool skip_given_timestamp) const;

  // Returns an iterator in |keyframe_map_| pointing to the next keyframe after
  // |timestamp|. If |skip_given_timestamp| is true, this returns the first
  // keyframe with a timestamp strictly greater than |timestamp|.
  KeyframeMap::const_iterator GetFirstKeyframeAt(
      base::TimeDelta timestamp,
      bool skip_given_timestamp) const;

  // Returns an iterator in |keyframe_map_| pointing to the first keyframe
  // before or at |timestamp|.
  KeyframeMap::const_iterator GetFirstKeyframeAtOrBefore(
      base::TimeDelta timestamp) const;

  // Helper method to delete buffers in |buffers_| starting at
  // |starting_point|, an index in |buffers_|.
  // Returns true if everything in the range was removed. Returns
  // false if the range still contains buffers.
  bool TruncateAt(const size_t starting_point, BufferQueue* deleted_buffers);

  // Updates |highest_frame_| to be the frame with highest PTS in the last GOP
  // in this range.  If there are no buffers in this range, resets
  // |highest_frame_|.
  // Normally, incremental additions to this range should just use
  // UpdateEndTime(). When removing buffers from this range (which could be out
  // of order presentation vs decode order), inspecting the last buffer in
  // decode order of this range can be insufficient to determine the correct
  // presentation end time of this range. Hence this helper method.
  void UpdateEndTimeUsingLastGOP();

  // Helper for debugging state.
  std::string ToStringForDebugging() const;

  // If the first buffer in this range is the beginning of a coded frame group,
  // |range_start_pts_| is the presentation time when the coded frame group
  // begins. This is especially important in muxed media where the first coded
  // frames for each track do not necessarily begin at the same time.
  // |range_start_pts_| may be <= the timestamp of the first buffer in
  // |buffers_|. |range_start_pts_| is kNoTimestamp if this range does not start
  // at the beginning of a coded frame group, which can happen by range removal
  // or split when we don't have a way of knowing, across potentially multiple
  // muxed streams, the coded frame group start timestamp for the new range.
  base::TimeDelta range_start_pts_;

  // Index base of all positions in |keyframe_map_|. In other words, the
  // real position of entry |k| of |keyframe_map_| in the range is:
  //   keyframe_map_[k] - keyframe_map_index_base_
  int keyframe_map_index_base_;

  // Maps keyframe presentation timestamps to GOP start index of |buffers_|
  // (with index adjusted by |keyframe_map_index_base_|);
  KeyframeMap keyframe_map_;

  DISALLOW_COPY_AND_ASSIGN(SourceBufferRangeByPts);
};

}  // namespace media

#endif  // MEDIA_FILTERS_SOURCE_BUFFER_RANGE_BY_PTS_H_