summaryrefslogtreecommitdiff
path: root/chromium/media/filters/source_buffer_range.h
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/media/filters/source_buffer_range.h')
-rw-r--r--chromium/media/filters/source_buffer_range.h314
1 files changed, 266 insertions, 48 deletions
diff --git a/chromium/media/filters/source_buffer_range.h b/chromium/media/filters/source_buffer_range.h
index b8ff274fa44..ef4426406ff 100644
--- a/chromium/media/filters/source_buffer_range.h
+++ b/chromium/media/filters/source_buffer_range.h
@@ -5,6 +5,10 @@
#ifndef MEDIA_FILTERS_SOURCE_BUFFER_RANGE_H_
#define MEDIA_FILTERS_SOURCE_BUFFER_RANGE_H_
+#include <stddef.h>
+#include <map>
+#include <memory>
+
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
@@ -37,40 +41,29 @@ class MEDIA_EXPORT SourceBufferRange {
ALLOW_GAPS
};
- // Sequential buffers with the same decode timestamp make sense under certain
- // conditions, typically when the first buffer is a keyframe. Due to some
- // atypical media append behaviors where a new keyframe might have the same
- // decode timestamp as a previous non-keyframe, the playback of the sequence
- // might involve some throwaway decode work. This method supports detecting
- // this situation so that callers can log warnings (it returns true in this
- // case only).
- // For all other cases, including more typical same-DTS sequences, this method
- // returns false. Examples of typical situations where DTS of two consecutive
- // frames can be equal:
- // - Video: VP8 Alt-Ref frames.
- // - Video: IPBPBP...: DTS for I frame and for P frame can be equal.
- // - Text track cues that start at same time.
- // Returns true if |prev_is_keyframe| and |current_is_keyframe| indicate a
- // same timestamp situation that is atypical. False is returned otherwise.
- static bool IsUncommonSameTimestampSequence(bool prev_is_keyframe,
- bool current_is_keyframe);
-
+ // 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.
SourceBufferRange(GapPolicy gap_policy,
+ const BufferQueue& new_buffers,
+ base::TimeDelta range_start_pts,
const InterbufferDistanceCB& interbuffer_distance_cb);
- virtual ~SourceBufferRange();
+ ~SourceBufferRange();
// Deletes all buffers in range.
- virtual void DeleteAll(BufferQueue* deleted_buffers) = 0;
+ void DeleteAll(BufferQueue* deleted_buffers);
// Seeks to the beginning of the range.
void SeekToStart();
- // Updates |out_buffer| with the next buffer in presentation order. Seek()
- // must be called before calls to GetNextBuffer(), and buffers are returned
- // in order from the last call to Seek(). Returns true if |out_buffer| is
- // filled with a valid buffer, false if there is not enough data to fulfill
- // the request.
+ // Updates |out_buffer| with the next buffer in presentation order by GOP and
+ // by decode order within each GOP (in general, in sequence to feed a
+ // decoder). Seek() must be called before calls to GetNextBuffer(), and
+ // buffers are returned in order from the last call to Seek(). Returns true if
+ // |out_buffer| is filled with a valid buffer, false if there is not enough
+ // data to fulfill the request.
bool GetNextBuffer(scoped_refptr<StreamParserBuffer>* out_buffer);
bool HasNextBuffer() const;
@@ -86,18 +79,178 @@ class MEDIA_EXPORT SourceBufferRange {
// Resets this range to an "unseeked" state.
void ResetNextBufferPosition();
- // TODO(wolenetz): Remove in favor of
- // GetEndTimestamp()/GetBufferedEndTimestamp() once they report in PTS, not
- // DTS. See https://crbug.com/718641.
- void GetRangeEndTimesForTesting(base::TimeDelta* highest_pts,
- base::TimeDelta* end_time) const;
+ // 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 transferred 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 SourceBufferRange& range,
+ bool transfer_current_position);
+ bool CanAppendRangeToEnd(const SourceBufferRange& 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 SourceBufferRange with the buffers from
+ // that keyframe onward. The buffers in the new SourceBufferRange are
+ // moved out of this range. The start time of the new SourceBufferRange
+ // 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<SourceBufferRange> 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;
size_t size_in_bytes() const { return size_in_bytes_; }
- protected:
- // Friend of protected is only for IsNextInPresentationSequence testing.
+ private:
+ // Friend of private is only for IsNextInPresentationSequence testing.
friend class SourceBufferStreamTest;
+ using KeyframeMap = std::map<base::TimeDelta, int>;
+
// Called during AppendBuffersToEnd to adjust estimated duration at the
// end of the last append to match the delta in timestamps between
// the last append and the upcoming append. This is a workaround for
@@ -108,30 +261,27 @@ class MEDIA_EXPORT SourceBufferRange {
// Frees the buffers in |buffers_| from [|start_point|,|ending_point|) and
// updates the |size_in_bytes_| accordingly. Note, this does not update
// |keyframe_map_|.
- // TODO(wolenetz): elevate keyframe_map_ to base class so this comment has
- // better context. See https://crbug.com/718641.
void FreeBufferRange(const BufferQueue::const_iterator& starting_point,
const BufferQueue::const_iterator& ending_point);
// Returns the distance in time estimating how far from the beginning or end
- // of this range a buffer can be to considered in the range.
+ // of this range a buffer can be to be considered in the range.
base::TimeDelta GetFudgeRoom() const;
// Returns the approximate duration of a buffer in this range.
base::TimeDelta GetApproximateDuration() const;
// Updates |highest_frame_| if |new_buffer| has a higher PTS than
- // |highest_frame_| or if the range was previously empty.
+ // |highest_frame_|, |new_buffer| has the same PTS as |highest_frame_| and
+ // duration at least as long as |highest_frame_|, or if the range was
+ // previously empty.
void UpdateEndTime(scoped_refptr<StreamParserBuffer> new_buffer);
// Returns true if |timestamp| is allowed in this range as the timestamp of
// the next buffer in presentation sequence at or after |highest_frame_|.
// |buffers_| must not be empty, and |highest_frame_| must not be nullptr.
// Uses |gap_policy_| to potentially allow gaps.
- // TODO(wolenetz): Switch to using this helper in CanAppendBuffersToEnd(),
- // etc, when switching to managing ranges by their presentation interval, and
- // not necessarily just their decode times. See https://crbug.com/718641. Once
- // being used and not just tested, the following also applies:
+ //
// Due to potential for out-of-order decode vs presentation time, this method
// should only be used to determine adjacency of keyframes with the end of
// |buffers_|.
@@ -141,10 +291,7 @@ class MEDIA_EXPORT SourceBufferRange {
// timestamp of the next buffer in decode sequence at or after the last buffer
// in |buffers_|'s decode timestamp. |buffers_| must not be empty. Uses
// |gap_policy_| to potentially allow gaps.
- // TODO(wolenetz): Switch to using this helper in CanAppendBuffersToEnd(),
- // etc, appropriately when switching to managing ranges by their presentation
- // interval between GOPs, and by their decode sequence within GOPs. See
- // https://crbug.com/718641. Once that's done, the following also would apply:
+ //
// Due to potential for out-of-order decode vs presentation time, this method
// should only be used to determine adjacency of non-keyframes with the end of
// |buffers_|, when determining if a non-keyframe with |decode_timestamp|
@@ -152,19 +299,71 @@ class MEDIA_EXPORT SourceBufferRange {
// |buffers_|.
bool IsNextInDecodeSequence(DecodeTimestamp decode_timestamp) const;
+ // 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 SourceBufferRange& 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;
+
// Keeps track of whether gaps are allowed.
const GapPolicy gap_policy_;
- // An ordered list of buffers in this range.
+ // The ordered list of buffers in this range.
BufferQueue buffers_;
// Index into |buffers_| for the next buffer to be returned by
- // GetNextBuffer(), set to -1 before Seek().
+ // GetNextBuffer(), set to -1 by ResetNextBufferPosition().
int next_buffer_index_;
// Caches the buffer, if any, with the highest PTS currently in |buffers_|.
// This is nullptr if this range is empty. This is useful in determining
- // range membership and adjacency in SourceBufferRangeByPts.
+ // range membership and adjacency.
scoped_refptr<StreamParserBuffer> highest_frame_;
// Called to get the largest interbuffer distance seen so far in the stream.
@@ -173,7 +372,26 @@ class MEDIA_EXPORT SourceBufferRange {
// Stores the amount of memory taken up by the data in |buffers_|.
size_t size_in_bytes_;
- private:
+ // 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(SourceBufferRange);
};