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. 4 5 #include "media/blink/websourcebuffer_impl.h" 6 7 #include <limits> 8 9 #include "base/bind.h" 10 #include "base/callback.h" 11 #include "base/callback_helpers.h" 12 #include "base/float_util.h" 13 #include "media/filters/chunk_demuxer.h" 14 #include "third_party/WebKit/public/platform/WebSourceBufferClient.h" 15 16 namespace media { 17 18 static base::TimeDelta DoubleToTimeDelta(double time) { 19 DCHECK(!base::IsNaN(time)); 20 DCHECK_NE(time, -std::numeric_limits<double>::infinity()); 21 22 if (time == std::numeric_limits<double>::infinity()) 23 return kInfiniteDuration(); 24 25 // Don't use base::TimeDelta::Max() here, as we want the largest finite time 26 // delta. 27 base::TimeDelta max_time = base::TimeDelta::FromInternalValue(kint64max - 1); 28 double max_time_in_seconds = max_time.InSecondsF(); 29 30 if (time >= max_time_in_seconds) 31 return max_time; 32 33 return base::TimeDelta::FromMicroseconds( 34 time * base::Time::kMicrosecondsPerSecond); 35 } 36 37 WebSourceBufferImpl::WebSourceBufferImpl( 38 const std::string& id, ChunkDemuxer* demuxer) 39 : id_(id), 40 demuxer_(demuxer), 41 client_(NULL), 42 append_window_end_(kInfiniteDuration()) { 43 DCHECK(demuxer_); 44 } 45 46 WebSourceBufferImpl::~WebSourceBufferImpl() { 47 DCHECK(!demuxer_) << "Object destroyed w/o removedFromMediaSource() call"; 48 DCHECK(!client_); 49 } 50 51 void WebSourceBufferImpl::setClient(blink::WebSourceBufferClient* client) { 52 DCHECK(client); 53 DCHECK(!client_); 54 client_ = client; 55 } 56 57 bool WebSourceBufferImpl::setMode(WebSourceBuffer::AppendMode mode) { 58 if (demuxer_->IsParsingMediaSegment(id_)) 59 return false; 60 61 switch (mode) { 62 case WebSourceBuffer::AppendModeSegments: 63 demuxer_->SetSequenceMode(id_, false); 64 return true; 65 case WebSourceBuffer::AppendModeSequence: 66 demuxer_->SetSequenceMode(id_, true); 67 return true; 68 } 69 70 NOTREACHED(); 71 return false; 72 } 73 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(); 80 } 81 return result; 82 } 83 84 void WebSourceBufferImpl::append( 85 const unsigned char* data, 86 unsigned length, 87 double* timestamp_offset) { 88 base::TimeDelta old_offset = timestamp_offset_; 89 demuxer_->AppendData(id_, data, length, 90 append_window_start_, append_window_end_, 91 ×tamp_offset_, 92 base::Bind(&WebSourceBufferImpl::InitSegmentReceived, 93 base::Unretained(this))); 94 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(); 102 } 103 104 void WebSourceBufferImpl::abort() { 105 demuxer_->Abort(id_, 106 append_window_start_, append_window_end_, 107 ×tamp_offset_); 108 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. 112 } 113 114 void WebSourceBufferImpl::remove(double start, double end) { 115 DCHECK_GE(start, 0); 116 DCHECK_GE(end, 0); 117 demuxer_->Remove(id_, DoubleToTimeDelta(start), DoubleToTimeDelta(end)); 118 } 119 120 bool WebSourceBufferImpl::setTimestampOffset(double offset) { 121 if (demuxer_->IsParsingMediaSegment(id_)) 122 return false; 123 124 timestamp_offset_ = DoubleToTimeDelta(offset); 125 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_); 130 return true; 131 } 132 133 void WebSourceBufferImpl::setAppendWindowStart(double start) { 134 DCHECK_GE(start, 0); 135 append_window_start_ = DoubleToTimeDelta(start); 136 } 137 138 void WebSourceBufferImpl::setAppendWindowEnd(double end) { 139 DCHECK_GE(end, 0); 140 append_window_end_ = DoubleToTimeDelta(end); 141 } 142 143 void WebSourceBufferImpl::removedFromMediaSource() { 144 demuxer_->RemoveId(id_); 145 demuxer_ = NULL; 146 client_ = NULL; 147 } 148 149 void WebSourceBufferImpl::InitSegmentReceived() { 150 DVLOG(1) << __FUNCTION__; 151 client_->initializationSegmentReceived(); 152 } 153 154 } // namespace media 155