1 // Copyright 2013 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.
5 #include "media/blink/websourcebuffer_impl.h"
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/callback_helpers.h"
13 #include "media/filters/chunk_demuxer.h"
14 #include "third_party/WebKit/public/platform/WebSourceBufferClient.h"
18 static base::TimeDelta
DoubleToTimeDelta(double time
) {
19 DCHECK(!std::isnan(time
));
20 DCHECK_NE(time
, -std::numeric_limits
<double>::infinity());
22 if (time
== std::numeric_limits
<double>::infinity())
23 return kInfiniteDuration();
25 // Don't use base::TimeDelta::Max() here, as we want the largest finite time
27 base::TimeDelta max_time
= base::TimeDelta::FromInternalValue(kint64max
- 1);
28 double max_time_in_seconds
= max_time
.InSecondsF();
30 if (time
>= max_time_in_seconds
)
33 return base::TimeDelta::FromMicroseconds(
34 time
* base::Time::kMicrosecondsPerSecond
);
37 WebSourceBufferImpl::WebSourceBufferImpl(
38 const std::string
& id
, ChunkDemuxer
* demuxer
)
42 append_window_end_(kInfiniteDuration()) {
46 WebSourceBufferImpl::~WebSourceBufferImpl() {
47 DCHECK(!demuxer_
) << "Object destroyed w/o removedFromMediaSource() call";
51 void WebSourceBufferImpl::setClient(blink::WebSourceBufferClient
* client
) {
57 bool WebSourceBufferImpl::setMode(WebSourceBuffer::AppendMode mode
) {
58 if (demuxer_
->IsParsingMediaSegment(id_
))
62 case WebSourceBuffer::AppendModeSegments
:
63 demuxer_
->SetSequenceMode(id_
, false);
65 case WebSourceBuffer::AppendModeSequence
:
66 demuxer_
->SetSequenceMode(id_
, true);
74 blink::WebTimeRanges
WebSourceBufferImpl::buffered() {
75 Ranges
<base::TimeDelta
> ranges
= demuxer_
->GetBufferedRanges(id_
);
76 blink::WebTimeRanges
result(ranges
.size());
77 for (size_t i
= 0; i
< ranges
.size(); i
++) {
78 result
[i
].start
= ranges
.start(i
).InSecondsF();
79 result
[i
].end
= ranges
.end(i
).InSecondsF();
84 void WebSourceBufferImpl::append(
85 const unsigned char* data
,
87 double* timestamp_offset
) {
88 base::TimeDelta old_offset
= timestamp_offset_
;
89 demuxer_
->AppendData(id_
, data
, length
,
90 append_window_start_
, append_window_end_
,
92 base::Bind(&WebSourceBufferImpl::InitSegmentReceived
,
93 base::Unretained(this)));
95 // Coded frame processing may update the timestamp offset. If the caller
96 // provides a non-NULL |timestamp_offset| and frame processing changes the
97 // timestamp offset, report the new offset to the caller. Do not update the
98 // caller's offset otherwise, to preserve any pre-existing value that may have
99 // more than microsecond precision.
100 if (timestamp_offset
&& old_offset
!= timestamp_offset_
)
101 *timestamp_offset
= timestamp_offset_
.InSecondsF();
104 void WebSourceBufferImpl::abort() {
106 append_window_start_
, append_window_end_
,
109 // TODO(wolenetz): abort should be able to modify the caller timestamp offset
110 // (just like WebSourceBufferImpl::append).
111 // See http://crbug.com/370229 for further details.
114 void WebSourceBufferImpl::remove(double start
, double end
) {
117 demuxer_
->Remove(id_
, DoubleToTimeDelta(start
), DoubleToTimeDelta(end
));
120 bool WebSourceBufferImpl::setTimestampOffset(double offset
) {
121 if (demuxer_
->IsParsingMediaSegment(id_
))
124 timestamp_offset_
= DoubleToTimeDelta(offset
);
126 // http://www.w3.org/TR/media-source/#widl-SourceBuffer-timestampOffset
127 // Step 6: If the mode attribute equals "sequence", then set the group start
128 // timestamp to new timestamp offset.
129 demuxer_
->SetGroupStartTimestampIfInSequenceMode(id_
, timestamp_offset_
);
133 void WebSourceBufferImpl::setAppendWindowStart(double start
) {
135 append_window_start_
= DoubleToTimeDelta(start
);
138 void WebSourceBufferImpl::setAppendWindowEnd(double end
) {
140 append_window_end_
= DoubleToTimeDelta(end
);
143 void WebSourceBufferImpl::removedFromMediaSource() {
144 demuxer_
->RemoveId(id_
);
149 void WebSourceBufferImpl::InitSegmentReceived() {
150 DVLOG(1) << __FUNCTION__
;
151 client_
->initializationSegmentReceived();