Home | History | Annotate | Download | only in media
      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 "content/renderer/media/websourcebuffer_impl.h"
      6 
      7 #include <limits>
      8 
      9 #include "base/float_util.h"
     10 #include "media/filters/chunk_demuxer.h"
     11 
     12 namespace content {
     13 
     14 static base::TimeDelta DoubleToTimeDelta(double time) {
     15   DCHECK(!base::IsNaN(time));
     16   DCHECK_NE(time, -std::numeric_limits<double>::infinity());
     17 
     18   if (time == std::numeric_limits<double>::infinity())
     19     return media::kInfiniteDuration();
     20 
     21   // Don't use base::TimeDelta::Max() here, as we want the largest finite time
     22   // delta.
     23   base::TimeDelta max_time = base::TimeDelta::FromInternalValue(kint64max - 1);
     24   double max_time_in_seconds = max_time.InSecondsF();
     25 
     26   if (time >= max_time_in_seconds)
     27     return max_time;
     28 
     29   return base::TimeDelta::FromMicroseconds(
     30       time * base::Time::kMicrosecondsPerSecond);
     31 }
     32 
     33 WebSourceBufferImpl::WebSourceBufferImpl(
     34     const std::string& id, media::ChunkDemuxer* demuxer)
     35     : id_(id),
     36       demuxer_(demuxer),
     37       append_window_end_(media::kInfiniteDuration()) {
     38   DCHECK(demuxer_);
     39 }
     40 
     41 WebSourceBufferImpl::~WebSourceBufferImpl() {
     42   DCHECK(!demuxer_) << "Object destroyed w/o removedFromMediaSource() call";
     43 }
     44 
     45 bool WebSourceBufferImpl::setMode(WebSourceBuffer::AppendMode mode) {
     46   if (demuxer_->IsParsingMediaSegment(id_))
     47     return false;
     48 
     49   switch (mode) {
     50     case WebSourceBuffer::AppendModeSegments:
     51       demuxer_->SetSequenceMode(id_, false);
     52       return true;
     53     case WebSourceBuffer::AppendModeSequence:
     54       demuxer_->SetSequenceMode(id_, true);
     55       return true;
     56   }
     57 
     58   NOTREACHED();
     59   return false;
     60 }
     61 
     62 blink::WebTimeRanges WebSourceBufferImpl::buffered() {
     63   media::Ranges<base::TimeDelta> ranges = demuxer_->GetBufferedRanges(id_);
     64   blink::WebTimeRanges result(ranges.size());
     65   for (size_t i = 0; i < ranges.size(); i++) {
     66     result[i].start = ranges.start(i).InSecondsF();
     67     result[i].end = ranges.end(i).InSecondsF();
     68   }
     69   return result;
     70 }
     71 
     72 void WebSourceBufferImpl::append(
     73     const unsigned char* data,
     74     unsigned length,
     75     double* timestamp_offset) {
     76   base::TimeDelta old_offset = timestamp_offset_;
     77   demuxer_->AppendData(id_, data, length,
     78                        append_window_start_, append_window_end_,
     79                        &timestamp_offset_);
     80 
     81   // Coded frame processing may update the timestamp offset. If the caller
     82   // provides a non-NULL |timestamp_offset| and frame processing changes the
     83   // timestamp offset, report the new offset to the caller. Do not update the
     84   // caller's offset otherwise, to preserve any pre-existing value that may have
     85   // more than microsecond precision.
     86   if (timestamp_offset && old_offset != timestamp_offset_)
     87     *timestamp_offset = timestamp_offset_.InSecondsF();
     88 }
     89 
     90 void WebSourceBufferImpl::abort() {
     91   demuxer_->Abort(id_,
     92                   append_window_start_, append_window_end_,
     93                   &timestamp_offset_);
     94 
     95   // TODO(wolenetz): abort should be able to modify the caller timestamp offset
     96   // (just like WebSourceBufferImpl::append).
     97   // See http://crbug.com/370229 for further details.
     98 }
     99 
    100 void WebSourceBufferImpl::remove(double start, double end) {
    101   DCHECK_GE(start, 0);
    102   DCHECK_GE(end, 0);
    103   demuxer_->Remove(id_, DoubleToTimeDelta(start), DoubleToTimeDelta(end));
    104 }
    105 
    106 bool WebSourceBufferImpl::setTimestampOffset(double offset) {
    107   if (demuxer_->IsParsingMediaSegment(id_))
    108     return false;
    109 
    110   timestamp_offset_ = DoubleToTimeDelta(offset);
    111 
    112   // http://www.w3.org/TR/media-source/#widl-SourceBuffer-timestampOffset
    113   // Step 6: If the mode attribute equals "sequence", then set the group start
    114   // timestamp to new timestamp offset.
    115   demuxer_->SetGroupStartTimestampIfInSequenceMode(id_, timestamp_offset_);
    116   return true;
    117 }
    118 
    119 void WebSourceBufferImpl::setAppendWindowStart(double start) {
    120   DCHECK_GE(start, 0);
    121   append_window_start_ = DoubleToTimeDelta(start);
    122 }
    123 
    124 void WebSourceBufferImpl::setAppendWindowEnd(double end) {
    125   DCHECK_GE(end, 0);
    126   append_window_end_ = DoubleToTimeDelta(end);
    127 }
    128 
    129 void WebSourceBufferImpl::removedFromMediaSource() {
    130   demuxer_->RemoveId(id_);
    131   demuxer_ = NULL;
    132 }
    133 
    134 }  // namespace content
    135