Home | History | Annotate | Download | only in blink
      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                        &timestamp_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                   &timestamp_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