Home | History | Annotate | Download | only in filters
      1 // Copyright (c) 2012 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/filters/chunk_demuxer.h"
      6 
      7 #include <algorithm>
      8 #include <deque>
      9 #include <limits>
     10 
     11 #include "base/bind.h"
     12 #include "base/callback_helpers.h"
     13 #include "base/location.h"
     14 #include "base/message_loop/message_loop_proxy.h"
     15 #include "media/base/audio_decoder_config.h"
     16 #include "media/base/bind_to_loop.h"
     17 #include "media/base/stream_parser_buffer.h"
     18 #include "media/base/video_decoder_config.h"
     19 #include "media/filters/stream_parser_factory.h"
     20 #include "media/webm/webm_webvtt_parser.h"
     21 
     22 using base::TimeDelta;
     23 
     24 namespace media {
     25 
     26 // Contains state belonging to a source id.
     27 class SourceState {
     28  public:
     29   // Callback signature used to create ChunkDemuxerStreams.
     30   typedef base::Callback<ChunkDemuxerStream*(
     31       DemuxerStream::Type)> CreateDemuxerStreamCB;
     32 
     33   // Callback signature used to notify ChunkDemuxer of timestamps
     34   // that may cause the duration to be updated.
     35   typedef base::Callback<void(
     36       TimeDelta, ChunkDemuxerStream*)> IncreaseDurationCB;
     37 
     38   SourceState(scoped_ptr<StreamParser> stream_parser, const LogCB& log_cb,
     39               const CreateDemuxerStreamCB& create_demuxer_stream_cb,
     40               const IncreaseDurationCB& increase_duration_cb);
     41 
     42   void Init(const StreamParser::InitCB& init_cb,
     43             bool allow_audio,
     44             bool allow_video,
     45             const StreamParser::NewTextBuffersCB& text_cb,
     46             const StreamParser::NeedKeyCB& need_key_cb,
     47             const AddTextTrackCB& add_text_track_cb);
     48 
     49   // Appends new data to the StreamParser.
     50   // Returns true if the data was successfully appended. Returns false if an
     51   // error occurred.
     52   bool Append(const uint8* data, size_t length);
     53 
     54   // Aborts the current append sequence and resets the parser.
     55   void Abort();
     56 
     57   // Sets |timestamp_offset_| if possible.
     58   // Returns if the offset was set. Returns false if the offset could not be
     59   // updated at this time.
     60   bool SetTimestampOffset(TimeDelta timestamp_offset);
     61 
     62   TimeDelta timestamp_offset() const { return timestamp_offset_; }
     63 
     64   void set_append_window_start(TimeDelta start) {
     65     append_window_start_ = start;
     66   }
     67   void set_append_window_end(TimeDelta end) { append_window_end_ = end; }
     68 
     69  private:
     70   // Called by the |stream_parser_| when a new initialization segment is
     71   // encountered.
     72   // Returns true on a successful call. Returns false if an error occured while
     73   // processing decoder configurations.
     74   bool OnNewConfigs(bool allow_audio, bool allow_video,
     75                     const AudioDecoderConfig& audio_config,
     76                     const VideoDecoderConfig& video_config);
     77 
     78   // Called by the |stream_parser_| at the beginning of a new media segment.
     79   void OnNewMediaSegment();
     80 
     81   // Called by the |stream_parser_| at the end of a media segment.
     82   void OnEndOfMediaSegment();
     83 
     84   // Called by the |stream_parser_| when new buffers have been parsed. It
     85   // applies |timestamp_offset_| to all buffers in |audio_buffers| and
     86   // |video_buffers| and then calls Append() on |audio_| and/or
     87   // |video_| with the modified buffers.
     88   // Returns true on a successful call. Returns false if an error occured while
     89   // processing the buffers.
     90   bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers,
     91                     const StreamParser::BufferQueue& video_buffers);
     92 
     93   // Called by the |stream_parser_| when new text buffers have been parsed. It
     94   // applies |timestamp_offset_| to all buffers in |buffers| and then calls
     95   // |new_buffers_cb| with the modified buffers.
     96   // Returns true on a successful call. Returns false if an error occured while
     97   // processing the buffers.
     98   bool OnTextBuffers(const StreamParser::NewTextBuffersCB& new_buffers_cb,
     99                      TextTrack* text_track,
    100                      const StreamParser::BufferQueue& buffers);
    101 
    102   // Helper function that adds |timestamp_offset_| to each buffer in |buffers|.
    103   void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers);
    104 
    105   // Filters out buffers that are outside of the append window
    106   // [|append_window_start_|, |append_window_end_|).
    107   // |needs_keyframe| is a pointer to the |xxx_need_keyframe_| flag
    108   // associated with the |buffers|. Its state is read an updated as
    109   // this method filters |buffers|.
    110   // Buffers that are inside the append window are appended to the end
    111   // of |filtered_buffers|.
    112   void FilterWithAppendWindow(const StreamParser::BufferQueue& buffers,
    113                               bool* needs_keyframe,
    114                               StreamParser::BufferQueue* filtered_buffers);
    115 
    116   CreateDemuxerStreamCB create_demuxer_stream_cb_;
    117   IncreaseDurationCB increase_duration_cb_;
    118 
    119   // The offset to apply to media segment timestamps.
    120   TimeDelta timestamp_offset_;
    121 
    122   TimeDelta append_window_start_;
    123   TimeDelta append_window_end_;
    124 
    125   // Set to true if the next buffers appended within the append window
    126   // represent the start of a new media segment. This flag being set
    127   // triggers a call to |new_segment_cb_| when the new buffers are
    128   // appended. The flag is set on actual media segment boundaries and
    129   // when the "append window" filtering causes discontinuities in the
    130   // appended data.
    131   bool new_media_segment_;
    132 
    133   // Keeps track of whether |timestamp_offset_| can be modified.
    134   bool can_update_offset_;
    135 
    136   // The object used to parse appended data.
    137   scoped_ptr<StreamParser> stream_parser_;
    138 
    139   ChunkDemuxerStream* audio_;
    140   bool audio_needs_keyframe_;
    141 
    142   ChunkDemuxerStream* video_;
    143   bool video_needs_keyframe_;
    144 
    145   LogCB log_cb_;
    146 
    147   DISALLOW_COPY_AND_ASSIGN(SourceState);
    148 };
    149 
    150 class ChunkDemuxerStream : public DemuxerStream {
    151  public:
    152   typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue;
    153 
    154   explicit ChunkDemuxerStream(Type type);
    155   virtual ~ChunkDemuxerStream();
    156 
    157   // ChunkDemuxerStream control methods.
    158   void StartReturningData();
    159   void AbortReads();
    160   void CompletePendingReadIfPossible();
    161   void Shutdown();
    162 
    163   // SourceBufferStream manipulation methods.
    164   void Seek(TimeDelta time);
    165   bool IsSeekWaitingForData() const;
    166 
    167   // Add buffers to this stream.  Buffers are stored in SourceBufferStreams,
    168   // which handle ordering and overlap resolution.
    169   // Returns true if buffers were successfully added.
    170   bool Append(const StreamParser::BufferQueue& buffers);
    171 
    172   // Removes buffers between |start| and |end| according to the steps
    173   // in the "Coded Frame Removal Algorithm" in the Media Source
    174   // Extensions Spec.
    175   // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-coded-frame-removal
    176   //
    177   // |duration| is the current duration of the presentation. It is
    178   // required by the computation outlined in the spec.
    179   void Remove(TimeDelta start, TimeDelta end, TimeDelta duration);
    180 
    181   // Signal to the stream that duration has changed to |duration|.
    182   void OnSetDuration(TimeDelta duration);
    183 
    184   // Returns the range of buffered data in this stream, capped at |duration|.
    185   Ranges<TimeDelta> GetBufferedRanges(TimeDelta duration) const;
    186 
    187   // Signal to the stream that buffers handed in through subsequent calls to
    188   // Append() belong to a media segment that starts at |start_timestamp|.
    189   void OnNewMediaSegment(TimeDelta start_timestamp);
    190 
    191   // Called when midstream config updates occur.
    192   // Returns true if the new config is accepted.
    193   // Returns false if the new config should trigger an error.
    194   bool UpdateAudioConfig(const AudioDecoderConfig& config, const LogCB& log_cb);
    195   bool UpdateVideoConfig(const VideoDecoderConfig& config, const LogCB& log_cb);
    196 
    197   void MarkEndOfStream();
    198   void UnmarkEndOfStream();
    199 
    200   // DemuxerStream methods.
    201   virtual void Read(const ReadCB& read_cb) OVERRIDE;
    202   virtual Type type() OVERRIDE;
    203   virtual void EnableBitstreamConverter() OVERRIDE;
    204   virtual AudioDecoderConfig audio_decoder_config() OVERRIDE;
    205   virtual VideoDecoderConfig video_decoder_config() OVERRIDE;
    206 
    207   void set_memory_limit_for_testing(int memory_limit) {
    208     stream_->set_memory_limit_for_testing(memory_limit);
    209   }
    210 
    211  private:
    212   enum State {
    213     UNINITIALIZED,
    214     RETURNING_DATA_FOR_READS,
    215     RETURNING_ABORT_FOR_READS,
    216     SHUTDOWN,
    217   };
    218 
    219   // Assigns |state_| to |state|
    220   void ChangeState_Locked(State state);
    221 
    222   void CompletePendingReadIfPossible_Locked();
    223 
    224   // Gets the value to pass to the next Read() callback. Returns true if
    225   // |status| and |buffer| should be passed to the callback. False indicates
    226   // that |status| and |buffer| were not set and more data is needed.
    227   bool GetNextBuffer_Locked(DemuxerStream::Status* status,
    228                             scoped_refptr<StreamParserBuffer>* buffer);
    229 
    230   // Specifies the type of the stream (must be AUDIO or VIDEO for now).
    231   Type type_;
    232 
    233   scoped_ptr<SourceBufferStream> stream_;
    234 
    235   mutable base::Lock lock_;
    236   State state_;
    237   ReadCB read_cb_;
    238 
    239   DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream);
    240 };
    241 
    242 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser,
    243                          const LogCB& log_cb,
    244                          const CreateDemuxerStreamCB& create_demuxer_stream_cb,
    245                          const IncreaseDurationCB& increase_duration_cb)
    246     : create_demuxer_stream_cb_(create_demuxer_stream_cb),
    247       increase_duration_cb_(increase_duration_cb),
    248       append_window_end_(kInfiniteDuration()),
    249       new_media_segment_(false),
    250       can_update_offset_(true),
    251       stream_parser_(stream_parser.release()),
    252       audio_(NULL),
    253       audio_needs_keyframe_(true),
    254       video_(NULL),
    255       video_needs_keyframe_(true),
    256       log_cb_(log_cb) {
    257   DCHECK(!create_demuxer_stream_cb_.is_null());
    258   DCHECK(!increase_duration_cb_.is_null());
    259 }
    260 
    261 void SourceState::Init(const StreamParser::InitCB& init_cb,
    262                        bool allow_audio,
    263                        bool allow_video,
    264                        const StreamParser::NewTextBuffersCB& text_cb,
    265                        const StreamParser::NeedKeyCB& need_key_cb,
    266                        const AddTextTrackCB& add_text_track_cb) {
    267   StreamParser::NewBuffersCB audio_cb;
    268 
    269   stream_parser_->Init(init_cb,
    270                        base::Bind(&SourceState::OnNewConfigs,
    271                                   base::Unretained(this),
    272                                   allow_audio,
    273                                   allow_video),
    274                        base::Bind(&SourceState::OnNewBuffers,
    275                                   base::Unretained(this)),
    276                        base::Bind(&SourceState::OnTextBuffers,
    277                                   base::Unretained(this), text_cb),
    278                        need_key_cb,
    279                        add_text_track_cb,
    280                        base::Bind(&SourceState::OnNewMediaSegment,
    281                                   base::Unretained(this)),
    282                        base::Bind(&SourceState::OnEndOfMediaSegment,
    283                                   base::Unretained(this)),
    284                        log_cb_);
    285 }
    286 
    287 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) {
    288   if (!can_update_offset_)
    289     return false;
    290 
    291   timestamp_offset_ = timestamp_offset;
    292   return true;
    293 }
    294 
    295 bool SourceState::Append(const uint8* data, size_t length) {
    296   return stream_parser_->Parse(data, length);
    297 }
    298 
    299 void SourceState::Abort() {
    300   stream_parser_->Flush();
    301   audio_needs_keyframe_ = true;
    302   video_needs_keyframe_ = true;
    303   can_update_offset_ = true;
    304 }
    305 
    306 void SourceState::AdjustBufferTimestamps(
    307     const StreamParser::BufferQueue& buffers) {
    308   if (timestamp_offset_ == TimeDelta())
    309     return;
    310 
    311   for (StreamParser::BufferQueue::const_iterator itr = buffers.begin();
    312        itr != buffers.end(); ++itr) {
    313     (*itr)->SetDecodeTimestamp(
    314         (*itr)->GetDecodeTimestamp() + timestamp_offset_);
    315     (*itr)->set_timestamp((*itr)->timestamp() + timestamp_offset_);
    316   }
    317 }
    318 
    319 bool SourceState::OnNewConfigs(bool allow_audio, bool allow_video,
    320                                const AudioDecoderConfig& audio_config,
    321                                const VideoDecoderConfig& video_config) {
    322   DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video
    323            << ", " << audio_config.IsValidConfig()
    324            << ", " << video_config.IsValidConfig() << ")";
    325 
    326   if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) {
    327     DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!";
    328     return false;
    329   }
    330 
    331   // Signal an error if we get configuration info for stream types that weren't
    332   // specified in AddId() or more configs after a stream is initialized.
    333   if (allow_audio != audio_config.IsValidConfig()) {
    334     MEDIA_LOG(log_cb_)
    335         << "Initialization segment"
    336         << (audio_config.IsValidConfig() ? " has" : " does not have")
    337         << " an audio track, but the mimetype"
    338         << (allow_audio ? " specifies" : " does not specify")
    339         << " an audio codec.";
    340     return false;
    341   }
    342 
    343   if (allow_video != video_config.IsValidConfig()) {
    344     MEDIA_LOG(log_cb_)
    345         << "Initialization segment"
    346         << (video_config.IsValidConfig() ? " has" : " does not have")
    347         << " a video track, but the mimetype"
    348         << (allow_video ? " specifies" : " does not specify")
    349         << " a video codec.";
    350     return false;
    351   }
    352 
    353   bool success = true;
    354   if (audio_config.IsValidConfig()) {
    355     if (!audio_) {
    356       audio_ = create_demuxer_stream_cb_.Run(DemuxerStream::AUDIO);
    357 
    358       if (!audio_) {
    359         DVLOG(1) << "Failed to create an audio stream.";
    360         return false;
    361       }
    362     }
    363 
    364     success &= audio_->UpdateAudioConfig(audio_config, log_cb_);
    365   }
    366 
    367   if (video_config.IsValidConfig()) {
    368     if (!video_) {
    369       video_ = create_demuxer_stream_cb_.Run(DemuxerStream::VIDEO);
    370 
    371       if (!video_) {
    372         DVLOG(1) << "Failed to create a video stream.";
    373         return false;
    374       }
    375     }
    376 
    377     success &= video_->UpdateVideoConfig(video_config, log_cb_);
    378   }
    379 
    380   DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed");
    381   return success;
    382 }
    383 
    384 void SourceState::OnNewMediaSegment() {
    385   DVLOG(2) << "OnNewMediaSegment()";
    386   can_update_offset_ = false;
    387   new_media_segment_ = true;
    388 }
    389 
    390 void SourceState::OnEndOfMediaSegment() {
    391   DVLOG(2) << "OnEndOfMediaSegment()";
    392   can_update_offset_ = true;
    393   new_media_segment_ = false;
    394 }
    395 
    396 bool SourceState::OnNewBuffers(const StreamParser::BufferQueue& audio_buffers,
    397                                const StreamParser::BufferQueue& video_buffers) {
    398   DCHECK(!audio_buffers.empty() || !video_buffers.empty());
    399   AdjustBufferTimestamps(audio_buffers);
    400   AdjustBufferTimestamps(video_buffers);
    401 
    402   StreamParser::BufferQueue filtered_audio;
    403   StreamParser::BufferQueue filtered_video;
    404 
    405   FilterWithAppendWindow(audio_buffers, &audio_needs_keyframe_,
    406                          &filtered_audio);
    407 
    408   FilterWithAppendWindow(video_buffers, &video_needs_keyframe_,
    409                          &filtered_video);
    410 
    411   if (filtered_audio.empty() && filtered_video.empty())
    412     return true;
    413 
    414   if (new_media_segment_) {
    415     // Find the earliest timestamp in the filtered buffers and use that for the
    416     // segment start timestamp.
    417     TimeDelta segment_timestamp = kNoTimestamp();
    418 
    419     if (!filtered_audio.empty())
    420       segment_timestamp = filtered_audio.front()->GetDecodeTimestamp();
    421 
    422     if (!filtered_video.empty() &&
    423         (segment_timestamp == kNoTimestamp() ||
    424          filtered_video.front()->GetDecodeTimestamp() < segment_timestamp)) {
    425       segment_timestamp = filtered_video.front()->GetDecodeTimestamp();
    426     }
    427 
    428     new_media_segment_ = false;
    429 
    430     if (audio_)
    431       audio_->OnNewMediaSegment(segment_timestamp);
    432 
    433     if (video_)
    434       video_->OnNewMediaSegment(segment_timestamp);
    435   }
    436 
    437   if (!filtered_audio.empty()) {
    438     if (!audio_ || !audio_->Append(filtered_audio))
    439       return false;
    440     increase_duration_cb_.Run(filtered_audio.back()->timestamp(), audio_);
    441   }
    442 
    443   if (!filtered_video.empty()) {
    444     if (!video_ || !video_->Append(filtered_video))
    445       return false;
    446     increase_duration_cb_.Run(filtered_video.back()->timestamp(), video_);
    447   }
    448 
    449   return true;
    450 }
    451 
    452 bool SourceState::OnTextBuffers(
    453     const StreamParser::NewTextBuffersCB& new_buffers_cb,
    454     TextTrack* text_track,
    455     const StreamParser::BufferQueue& buffers) {
    456   if (new_buffers_cb.is_null())
    457     return false;
    458 
    459   AdjustBufferTimestamps(buffers);
    460 
    461   return new_buffers_cb.Run(text_track, buffers);
    462 }
    463 
    464 void SourceState::FilterWithAppendWindow(
    465     const StreamParser::BufferQueue& buffers, bool* needs_keyframe,
    466     StreamParser::BufferQueue* filtered_buffers) {
    467   DCHECK(needs_keyframe);
    468   DCHECK(filtered_buffers);
    469 
    470   // This loop implements steps 1.9, 1.10, & 1.11 of the "Coded frame
    471   // processing loop" in the Media Source Extensions spec.
    472   // These steps filter out buffers that are not within the "append
    473   // window" and handles resyncing on the next random access point
    474   // (i.e., next keyframe) if a buffer gets dropped.
    475   for (StreamParser::BufferQueue::const_iterator itr = buffers.begin();
    476        itr != buffers.end(); ++itr) {
    477     // Filter out buffers that are outside the append window. Anytime
    478     // a buffer gets dropped we need to set |*needs_keyframe| to true
    479     // because we can only resume decoding at keyframes.
    480     TimeDelta presentation_timestamp = (*itr)->timestamp();
    481 
    482     // TODO(acolwell): Change |frame_end_timestamp| value to
    483     // |presentation_timestamp + (*itr)->duration()|, like the spec
    484     // requires, once frame durations are actually present in all buffers.
    485     TimeDelta frame_end_timestamp = presentation_timestamp;
    486     if (presentation_timestamp < append_window_start_ ||
    487         frame_end_timestamp > append_window_end_) {
    488       DVLOG(1) << "Dropping buffer outside append window."
    489                << " presentation_timestamp "
    490                << presentation_timestamp.InSecondsF();
    491       *needs_keyframe = true;
    492 
    493       // This triggers a discontinuity so we need to treat the next frames
    494       // appended within the append window as if they were the beginning of a
    495       // new segment.
    496       new_media_segment_ = true;
    497       continue;
    498     }
    499 
    500     // If |*needs_keyframe| is true then filter out buffers until we
    501     // encounter the next keyframe.
    502     if (*needs_keyframe) {
    503       if (!(*itr)->IsKeyframe()) {
    504         DVLOG(1) << "Dropping non-keyframe. presentation_timestamp "
    505                  << presentation_timestamp.InSecondsF();
    506         continue;
    507       }
    508 
    509       *needs_keyframe = false;
    510     }
    511 
    512     filtered_buffers->push_back(*itr);
    513   }
    514 }
    515 
    516 ChunkDemuxerStream::ChunkDemuxerStream(Type type)
    517     : type_(type),
    518       state_(UNINITIALIZED) {
    519 }
    520 
    521 void ChunkDemuxerStream::StartReturningData() {
    522   DVLOG(1) << "ChunkDemuxerStream::StartReturningData()";
    523   base::AutoLock auto_lock(lock_);
    524   DCHECK(read_cb_.is_null());
    525   ChangeState_Locked(RETURNING_DATA_FOR_READS);
    526 }
    527 
    528 void ChunkDemuxerStream::AbortReads() {
    529   DVLOG(1) << "ChunkDemuxerStream::AbortReads()";
    530   base::AutoLock auto_lock(lock_);
    531   ChangeState_Locked(RETURNING_ABORT_FOR_READS);
    532   if (!read_cb_.is_null())
    533     base::ResetAndReturn(&read_cb_).Run(kAborted, NULL);
    534 }
    535 
    536 void ChunkDemuxerStream::CompletePendingReadIfPossible() {
    537   base::AutoLock auto_lock(lock_);
    538   if (read_cb_.is_null())
    539     return;
    540 
    541   CompletePendingReadIfPossible_Locked();
    542 }
    543 
    544 void ChunkDemuxerStream::Shutdown() {
    545   DVLOG(1) << "ChunkDemuxerStream::Shutdown()";
    546   base::AutoLock auto_lock(lock_);
    547   ChangeState_Locked(SHUTDOWN);
    548 
    549   // Pass an end of stream buffer to the pending callback to signal that no more
    550   // data will be sent.
    551   if (!read_cb_.is_null()) {
    552     base::ResetAndReturn(&read_cb_).Run(DemuxerStream::kOk,
    553                                         StreamParserBuffer::CreateEOSBuffer());
    554   }
    555 }
    556 
    557 bool ChunkDemuxerStream::IsSeekWaitingForData() const {
    558   base::AutoLock auto_lock(lock_);
    559   return stream_->IsSeekPending();
    560 }
    561 
    562 void ChunkDemuxerStream::Seek(TimeDelta time) {
    563   DVLOG(1) << "ChunkDemuxerStream::Seek(" << time.InSecondsF() << ")";
    564   base::AutoLock auto_lock(lock_);
    565   DCHECK(read_cb_.is_null());
    566   DCHECK(state_ == UNINITIALIZED || state_ == RETURNING_ABORT_FOR_READS);
    567 
    568   stream_->Seek(time);
    569 }
    570 
    571 bool ChunkDemuxerStream::Append(const StreamParser::BufferQueue& buffers) {
    572   if (buffers.empty())
    573     return false;
    574 
    575   base::AutoLock auto_lock(lock_);
    576   DCHECK_NE(state_, SHUTDOWN);
    577   if (!stream_->Append(buffers)) {
    578     DVLOG(1) << "ChunkDemuxerStream::Append() : stream append failed";
    579     return false;
    580   }
    581 
    582   if (!read_cb_.is_null())
    583     CompletePendingReadIfPossible_Locked();
    584 
    585   return true;
    586 }
    587 
    588 void ChunkDemuxerStream::Remove(TimeDelta start, TimeDelta end,
    589                                 TimeDelta duration) {
    590   base::AutoLock auto_lock(lock_);
    591   stream_->Remove(start, end, duration);
    592 }
    593 
    594 void ChunkDemuxerStream::OnSetDuration(TimeDelta duration) {
    595   base::AutoLock auto_lock(lock_);
    596   stream_->OnSetDuration(duration);
    597 }
    598 
    599 Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedRanges(
    600     TimeDelta duration) const {
    601   base::AutoLock auto_lock(lock_);
    602   Ranges<TimeDelta> range = stream_->GetBufferedTime();
    603 
    604   if (range.size() == 0u)
    605     return range;
    606 
    607   // Clamp the end of the stream's buffered ranges to fit within the duration.
    608   // This can be done by intersecting the stream's range with the valid time
    609   // range.
    610   Ranges<TimeDelta> valid_time_range;
    611   valid_time_range.Add(range.start(0), duration);
    612   return range.IntersectionWith(valid_time_range);
    613 }
    614 
    615 void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) {
    616   DVLOG(2) << "ChunkDemuxerStream::OnNewMediaSegment("
    617            << start_timestamp.InSecondsF() << ")";
    618   base::AutoLock auto_lock(lock_);
    619   stream_->OnNewMediaSegment(start_timestamp);
    620 }
    621 
    622 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config,
    623                                            const LogCB& log_cb) {
    624   DCHECK(config.IsValidConfig());
    625   DCHECK_EQ(type_, AUDIO);
    626   base::AutoLock auto_lock(lock_);
    627   if (!stream_) {
    628     DCHECK_EQ(state_, UNINITIALIZED);
    629     stream_.reset(new SourceBufferStream(config, log_cb));
    630     return true;
    631   }
    632 
    633   return stream_->UpdateAudioConfig(config);
    634 }
    635 
    636 bool ChunkDemuxerStream::UpdateVideoConfig(const VideoDecoderConfig& config,
    637                                            const LogCB& log_cb) {
    638   DCHECK(config.IsValidConfig());
    639   DCHECK_EQ(type_, VIDEO);
    640   base::AutoLock auto_lock(lock_);
    641 
    642   if (!stream_) {
    643     DCHECK_EQ(state_, UNINITIALIZED);
    644     stream_.reset(new SourceBufferStream(config, log_cb));
    645     return true;
    646   }
    647 
    648   return stream_->UpdateVideoConfig(config);
    649 }
    650 
    651 void ChunkDemuxerStream::MarkEndOfStream() {
    652   base::AutoLock auto_lock(lock_);
    653   stream_->MarkEndOfStream();
    654 }
    655 
    656 void ChunkDemuxerStream::UnmarkEndOfStream() {
    657   base::AutoLock auto_lock(lock_);
    658   stream_->UnmarkEndOfStream();
    659 }
    660 
    661 // DemuxerStream methods.
    662 void ChunkDemuxerStream::Read(const ReadCB& read_cb) {
    663   base::AutoLock auto_lock(lock_);
    664   DCHECK_NE(state_, UNINITIALIZED);
    665   DCHECK(read_cb_.is_null());
    666 
    667   read_cb_ = BindToCurrentLoop(read_cb);
    668   CompletePendingReadIfPossible_Locked();
    669 }
    670 
    671 DemuxerStream::Type ChunkDemuxerStream::type() { return type_; }
    672 
    673 void ChunkDemuxerStream::EnableBitstreamConverter() {}
    674 
    675 AudioDecoderConfig ChunkDemuxerStream::audio_decoder_config() {
    676   CHECK_EQ(type_, AUDIO);
    677   base::AutoLock auto_lock(lock_);
    678   return stream_->GetCurrentAudioDecoderConfig();
    679 }
    680 
    681 VideoDecoderConfig ChunkDemuxerStream::video_decoder_config() {
    682   CHECK_EQ(type_, VIDEO);
    683   base::AutoLock auto_lock(lock_);
    684   return stream_->GetCurrentVideoDecoderConfig();
    685 }
    686 
    687 void ChunkDemuxerStream::ChangeState_Locked(State state) {
    688   lock_.AssertAcquired();
    689   DVLOG(1) << "ChunkDemuxerStream::ChangeState_Locked() : "
    690            << "type " << type_
    691            << " - " << state_ << " -> " << state;
    692   state_ = state;
    693 }
    694 
    695 ChunkDemuxerStream::~ChunkDemuxerStream() {}
    696 
    697 void ChunkDemuxerStream::CompletePendingReadIfPossible_Locked() {
    698   lock_.AssertAcquired();
    699   DCHECK(!read_cb_.is_null());
    700 
    701   DemuxerStream::Status status;
    702   scoped_refptr<StreamParserBuffer> buffer;
    703 
    704   switch (state_) {
    705     case UNINITIALIZED:
    706       NOTREACHED();
    707       return;
    708     case RETURNING_DATA_FOR_READS:
    709       switch (stream_->GetNextBuffer(&buffer)) {
    710         case SourceBufferStream::kSuccess:
    711           status = DemuxerStream::kOk;
    712           break;
    713         case SourceBufferStream::kNeedBuffer:
    714           // Return early without calling |read_cb_| since we don't have
    715           // any data to return yet.
    716           return;
    717         case SourceBufferStream::kEndOfStream:
    718           status = DemuxerStream::kOk;
    719           buffer = StreamParserBuffer::CreateEOSBuffer();
    720           break;
    721         case SourceBufferStream::kConfigChange:
    722           DVLOG(2) << "Config change reported to ChunkDemuxerStream.";
    723           status = kConfigChanged;
    724           buffer = NULL;
    725           break;
    726       }
    727       break;
    728     case RETURNING_ABORT_FOR_READS:
    729       // Null buffers should be returned in this state since we are waiting
    730       // for a seek. Any buffers in the SourceBuffer should NOT be returned
    731       // because they are associated with the seek.
    732       status = DemuxerStream::kAborted;
    733       buffer = NULL;
    734       break;
    735     case SHUTDOWN:
    736       status = DemuxerStream::kOk;
    737       buffer = StreamParserBuffer::CreateEOSBuffer();
    738       break;
    739   }
    740 
    741   base::ResetAndReturn(&read_cb_).Run(status, buffer);
    742 }
    743 
    744 ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb,
    745                            const NeedKeyCB& need_key_cb,
    746                            const AddTextTrackCB& add_text_track_cb,
    747                            const LogCB& log_cb)
    748     : state_(WAITING_FOR_INIT),
    749       cancel_next_seek_(false),
    750       host_(NULL),
    751       open_cb_(open_cb),
    752       need_key_cb_(need_key_cb),
    753       add_text_track_cb_(add_text_track_cb),
    754       log_cb_(log_cb),
    755       duration_(kNoTimestamp()),
    756       user_specified_duration_(-1) {
    757   DCHECK(!open_cb_.is_null());
    758   DCHECK(!need_key_cb_.is_null());
    759 }
    760 
    761 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) {
    762   DVLOG(1) << "Init()";
    763 
    764   base::AutoLock auto_lock(lock_);
    765 
    766   init_cb_ = BindToCurrentLoop(cb);
    767   if (state_ == SHUTDOWN) {
    768     base::ResetAndReturn(&init_cb_).Run(DEMUXER_ERROR_COULD_NOT_OPEN);
    769     return;
    770   }
    771   DCHECK_EQ(state_, WAITING_FOR_INIT);
    772   host_ = host;
    773 
    774   ChangeState_Locked(INITIALIZING);
    775 
    776   base::ResetAndReturn(&open_cb_).Run();
    777 }
    778 
    779 void ChunkDemuxer::Stop(const base::Closure& callback) {
    780   DVLOG(1) << "Stop()";
    781   Shutdown();
    782   callback.Run();
    783 }
    784 
    785 void ChunkDemuxer::Seek(TimeDelta time, const PipelineStatusCB& cb) {
    786   DVLOG(1) << "Seek(" << time.InSecondsF() << ")";
    787   DCHECK(time >= TimeDelta());
    788 
    789   base::AutoLock auto_lock(lock_);
    790   DCHECK(seek_cb_.is_null());
    791 
    792   seek_cb_ = BindToCurrentLoop(cb);
    793   if (state_ != INITIALIZED && state_ != ENDED) {
    794     base::ResetAndReturn(&seek_cb_).Run(PIPELINE_ERROR_INVALID_STATE);
    795     return;
    796   }
    797 
    798   if (cancel_next_seek_) {
    799     cancel_next_seek_ = false;
    800     base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
    801     return;
    802   }
    803 
    804   SeekAllSources(time);
    805   StartReturningData();
    806 
    807   if (IsSeekWaitingForData_Locked()) {
    808     DVLOG(1) << "Seek() : waiting for more data to arrive.";
    809     return;
    810   }
    811 
    812   base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
    813 }
    814 
    815 void ChunkDemuxer::OnAudioRendererDisabled() {
    816   base::AutoLock auto_lock(lock_);
    817   audio_->Shutdown();
    818   disabled_audio_ = audio_.Pass();
    819 }
    820 
    821 // Demuxer implementation.
    822 DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) {
    823   base::AutoLock auto_lock(lock_);
    824   if (type == DemuxerStream::VIDEO)
    825     return video_.get();
    826 
    827   if (type == DemuxerStream::AUDIO)
    828     return audio_.get();
    829 
    830   return NULL;
    831 }
    832 
    833 TimeDelta ChunkDemuxer::GetStartTime() const {
    834   return TimeDelta();
    835 }
    836 
    837 void ChunkDemuxer::StartWaitingForSeek(TimeDelta seek_time) {
    838   DVLOG(1) << "StartWaitingForSeek()";
    839   base::AutoLock auto_lock(lock_);
    840   DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN ||
    841          state_ == PARSE_ERROR) << state_;
    842   DCHECK(seek_cb_.is_null());
    843 
    844   if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
    845     return;
    846 
    847   AbortPendingReads();
    848   SeekAllSources(seek_time);
    849 
    850   // Cancel state set in CancelPendingSeek() since we want to
    851   // accept the next Seek().
    852   cancel_next_seek_ = false;
    853 }
    854 
    855 void ChunkDemuxer::CancelPendingSeek(TimeDelta seek_time) {
    856   base::AutoLock auto_lock(lock_);
    857   DCHECK_NE(state_, INITIALIZING);
    858   DCHECK(seek_cb_.is_null() || IsSeekWaitingForData_Locked());
    859 
    860   if (cancel_next_seek_)
    861     return;
    862 
    863   AbortPendingReads();
    864   SeekAllSources(seek_time);
    865 
    866   if (seek_cb_.is_null()) {
    867     cancel_next_seek_ = true;
    868     return;
    869   }
    870 
    871   base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
    872 }
    873 
    874 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id,
    875                                          const std::string& type,
    876                                          std::vector<std::string>& codecs) {
    877   DCHECK_GT(codecs.size(), 0u);
    878   base::AutoLock auto_lock(lock_);
    879 
    880   if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id))
    881     return kReachedIdLimit;
    882 
    883   bool has_audio = false;
    884   bool has_video = false;
    885   scoped_ptr<media::StreamParser> stream_parser(
    886       StreamParserFactory::Create(type, codecs, log_cb_,
    887                                   &has_audio, &has_video));
    888 
    889   if (!stream_parser)
    890     return ChunkDemuxer::kNotSupported;
    891 
    892   if ((has_audio && !source_id_audio_.empty()) ||
    893       (has_video && !source_id_video_.empty()))
    894     return kReachedIdLimit;
    895 
    896   if (has_audio)
    897     source_id_audio_ = id;
    898 
    899   if (has_video)
    900     source_id_video_ = id;
    901 
    902   scoped_ptr<SourceState> source_state(
    903       new SourceState(stream_parser.Pass(), log_cb_,
    904                       base::Bind(&ChunkDemuxer::CreateDemuxerStream,
    905                                  base::Unretained(this)),
    906                       base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary,
    907                                  base::Unretained(this))));
    908 
    909   source_state->Init(
    910       base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)),
    911       has_audio,
    912       has_video,
    913       base::Bind(&ChunkDemuxer::OnTextBuffers, base::Unretained(this)),
    914       need_key_cb_,
    915       add_text_track_cb_);
    916 
    917   source_state_map_[id] = source_state.release();
    918   return kOk;
    919 }
    920 
    921 void ChunkDemuxer::RemoveId(const std::string& id) {
    922   base::AutoLock auto_lock(lock_);
    923   CHECK(IsValidId(id));
    924 
    925   delete source_state_map_[id];
    926   source_state_map_.erase(id);
    927 
    928   if (source_id_audio_ == id) {
    929     if (audio_)
    930       audio_->Shutdown();
    931     source_id_audio_.clear();
    932   }
    933 
    934   if (source_id_video_ == id) {
    935     if (video_)
    936       video_->Shutdown();
    937     source_id_video_.clear();
    938   }
    939 }
    940 
    941 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const {
    942   base::AutoLock auto_lock(lock_);
    943   DCHECK(!id.empty());
    944   DCHECK(IsValidId(id));
    945   DCHECK(id == source_id_audio_ || id == source_id_video_);
    946 
    947   if (id == source_id_audio_ && id != source_id_video_) {
    948     // Only include ranges that have been buffered in |audio_|
    949     return audio_ ? audio_->GetBufferedRanges(duration_) : Ranges<TimeDelta>();
    950   }
    951 
    952   if (id != source_id_audio_ && id == source_id_video_) {
    953     // Only include ranges that have been buffered in |video_|
    954     return video_ ? video_->GetBufferedRanges(duration_) : Ranges<TimeDelta>();
    955   }
    956 
    957   return ComputeIntersection();
    958 }
    959 
    960 Ranges<TimeDelta> ChunkDemuxer::ComputeIntersection() const {
    961   lock_.AssertAcquired();
    962 
    963   if (!audio_ || !video_)
    964     return Ranges<TimeDelta>();
    965 
    966   // Include ranges that have been buffered in both |audio_| and |video_|.
    967   Ranges<TimeDelta> audio_ranges = audio_->GetBufferedRanges(duration_);
    968   Ranges<TimeDelta> video_ranges = video_->GetBufferedRanges(duration_);
    969   Ranges<TimeDelta> result = audio_ranges.IntersectionWith(video_ranges);
    970 
    971   if (state_ == ENDED && result.size() > 0) {
    972     // If appending has ended, extend the last intersection range to include the
    973     // max end time of the last audio/video range. This allows the buffered
    974     // information to match the actual time range that will get played out if
    975     // the streams have slightly different lengths.
    976     TimeDelta audio_start = audio_ranges.start(audio_ranges.size() - 1);
    977     TimeDelta audio_end = audio_ranges.end(audio_ranges.size() - 1);
    978     TimeDelta video_start = video_ranges.start(video_ranges.size() - 1);
    979     TimeDelta video_end = video_ranges.end(video_ranges.size() - 1);
    980 
    981     // Verify the last audio range overlaps with the last video range.
    982     // This is enforced by the logic that controls the transition to ENDED.
    983     DCHECK((audio_start <= video_start && video_start <= audio_end) ||
    984            (video_start <= audio_start && audio_start <= video_end));
    985     result.Add(result.end(result.size()-1), std::max(audio_end, video_end));
    986   }
    987 
    988   return result;
    989 }
    990 
    991 void ChunkDemuxer::AppendData(const std::string& id,
    992                               const uint8* data,
    993                               size_t length) {
    994   DVLOG(1) << "AppendData(" << id << ", " << length << ")";
    995 
    996   DCHECK(!id.empty());
    997 
    998   Ranges<TimeDelta> ranges;
    999 
   1000   {
   1001     base::AutoLock auto_lock(lock_);
   1002     DCHECK_NE(state_, ENDED);
   1003 
   1004     // Capture if any of the SourceBuffers are waiting for data before we start
   1005     // parsing.
   1006     bool old_waiting_for_data = IsSeekWaitingForData_Locked();
   1007 
   1008     if (length == 0u)
   1009       return;
   1010 
   1011     DCHECK(data);
   1012 
   1013     switch (state_) {
   1014       case INITIALIZING:
   1015         DCHECK(IsValidId(id));
   1016         if (!source_state_map_[id]->Append(data, length)) {
   1017           ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
   1018           return;
   1019         }
   1020         break;
   1021 
   1022       case INITIALIZED: {
   1023         DCHECK(IsValidId(id));
   1024         if (!source_state_map_[id]->Append(data, length)) {
   1025           ReportError_Locked(PIPELINE_ERROR_DECODE);
   1026           return;
   1027         }
   1028       } break;
   1029 
   1030       case PARSE_ERROR:
   1031         DVLOG(1) << "AppendData(): Ignoring data after a parse error.";
   1032         return;
   1033 
   1034       case WAITING_FOR_INIT:
   1035       case ENDED:
   1036       case SHUTDOWN:
   1037         DVLOG(1) << "AppendData(): called in unexpected state " << state_;
   1038         return;
   1039     }
   1040 
   1041     // Check to see if data was appended at the pending seek point. This
   1042     // indicates we have parsed enough data to complete the seek.
   1043     if (old_waiting_for_data && !IsSeekWaitingForData_Locked() &&
   1044         !seek_cb_.is_null()) {
   1045       base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
   1046     }
   1047 
   1048     ranges = GetBufferedRanges();
   1049   }
   1050 
   1051   for (size_t i = 0; i < ranges.size(); ++i)
   1052     host_->AddBufferedTimeRange(ranges.start(i), ranges.end(i));
   1053 }
   1054 
   1055 void ChunkDemuxer::Abort(const std::string& id) {
   1056   DVLOG(1) << "Abort(" << id << ")";
   1057   base::AutoLock auto_lock(lock_);
   1058   DCHECK(!id.empty());
   1059   CHECK(IsValidId(id));
   1060   source_state_map_[id]->Abort();
   1061 }
   1062 
   1063 void ChunkDemuxer::Remove(const std::string& id, base::TimeDelta start,
   1064                           base::TimeDelta end) {
   1065   DVLOG(1) << "Remove(" << id << ", " << start.InSecondsF()
   1066            << ", " << end.InSecondsF() << ")";
   1067   base::AutoLock auto_lock(lock_);
   1068 
   1069   if (id == source_id_audio_ && audio_)
   1070     audio_->Remove(start, end, duration_);
   1071 
   1072   if (id == source_id_video_ && video_)
   1073     video_->Remove(start, end, duration_);
   1074 }
   1075 
   1076 double ChunkDemuxer::GetDuration() {
   1077   base::AutoLock auto_lock(lock_);
   1078   return GetDuration_Locked();
   1079 }
   1080 
   1081 double ChunkDemuxer::GetDuration_Locked() {
   1082   lock_.AssertAcquired();
   1083   if (duration_ == kNoTimestamp())
   1084     return std::numeric_limits<double>::quiet_NaN();
   1085 
   1086   // Return positive infinity if the resource is unbounded.
   1087   // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-media-duration
   1088   if (duration_ == kInfiniteDuration())
   1089     return std::numeric_limits<double>::infinity();
   1090 
   1091   if (user_specified_duration_ >= 0)
   1092     return user_specified_duration_;
   1093 
   1094   return duration_.InSecondsF();
   1095 }
   1096 
   1097 void ChunkDemuxer::SetDuration(double duration) {
   1098   base::AutoLock auto_lock(lock_);
   1099   DVLOG(1) << "SetDuration(" << duration << ")";
   1100   DCHECK_GE(duration, 0);
   1101 
   1102   if (duration == GetDuration_Locked())
   1103     return;
   1104 
   1105   // Compute & bounds check the TimeDelta representation of duration.
   1106   // This can be different if the value of |duration| doesn't fit the range or
   1107   // precision of TimeDelta.
   1108   TimeDelta min_duration = TimeDelta::FromInternalValue(1);
   1109   TimeDelta max_duration = TimeDelta::FromInternalValue(kint64max - 1);
   1110   double min_duration_in_seconds = min_duration.InSecondsF();
   1111   double max_duration_in_seconds = max_duration.InSecondsF();
   1112 
   1113   TimeDelta duration_td;
   1114   if (duration == std::numeric_limits<double>::infinity()) {
   1115     duration_td = media::kInfiniteDuration();
   1116   } else if (duration < min_duration_in_seconds) {
   1117     duration_td = min_duration;
   1118   } else if (duration > max_duration_in_seconds) {
   1119     duration_td = max_duration;
   1120   } else {
   1121     duration_td = TimeDelta::FromMicroseconds(
   1122         duration * base::Time::kMicrosecondsPerSecond);
   1123   }
   1124 
   1125   DCHECK(duration_td > TimeDelta());
   1126 
   1127   user_specified_duration_ = duration;
   1128   duration_ = duration_td;
   1129   host_->SetDuration(duration_);
   1130 
   1131   if (audio_)
   1132     audio_->OnSetDuration(duration_);
   1133 
   1134   if (video_)
   1135     video_->OnSetDuration(duration_);
   1136 }
   1137 
   1138 bool ChunkDemuxer::SetTimestampOffset(const std::string& id, TimeDelta offset) {
   1139   base::AutoLock auto_lock(lock_);
   1140   DVLOG(1) << "SetTimestampOffset(" << id << ", " << offset.InSecondsF() << ")";
   1141   CHECK(IsValidId(id));
   1142 
   1143   return source_state_map_[id]->SetTimestampOffset(offset);
   1144 }
   1145 
   1146 void ChunkDemuxer::MarkEndOfStream(PipelineStatus status) {
   1147   DVLOG(1) << "MarkEndOfStream(" << status << ")";
   1148   base::AutoLock auto_lock(lock_);
   1149   DCHECK_NE(state_, WAITING_FOR_INIT);
   1150   DCHECK_NE(state_, ENDED);
   1151 
   1152   if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
   1153     return;
   1154 
   1155   if (state_ == INITIALIZING) {
   1156     ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
   1157     return;
   1158   }
   1159 
   1160   bool old_waiting_for_data = IsSeekWaitingForData_Locked();
   1161   if (audio_)
   1162     audio_->MarkEndOfStream();
   1163 
   1164   if (video_)
   1165     video_->MarkEndOfStream();
   1166 
   1167   CompletePendingReadsIfPossible();
   1168 
   1169   // Give a chance to resume the pending seek process.
   1170   if (status != PIPELINE_OK) {
   1171     ReportError_Locked(status);
   1172     return;
   1173   }
   1174 
   1175   ChangeState_Locked(ENDED);
   1176   DecreaseDurationIfNecessary();
   1177 
   1178   if (old_waiting_for_data && !IsSeekWaitingForData_Locked() &&
   1179       !seek_cb_.is_null()) {
   1180     base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
   1181   }
   1182 }
   1183 
   1184 void ChunkDemuxer::UnmarkEndOfStream() {
   1185   DVLOG(1) << "UnmarkEndOfStream()";
   1186   base::AutoLock auto_lock(lock_);
   1187   DCHECK_EQ(state_, ENDED);
   1188 
   1189   ChangeState_Locked(INITIALIZED);
   1190 
   1191   if (audio_)
   1192     audio_->UnmarkEndOfStream();
   1193 
   1194   if (video_)
   1195     video_->UnmarkEndOfStream();
   1196 }
   1197 
   1198 void ChunkDemuxer::SetAppendWindowStart(const std::string& id,
   1199                                         TimeDelta start) {
   1200   base::AutoLock auto_lock(lock_);
   1201   DVLOG(1) << "SetAppendWindowStart(" << id << ", "
   1202            << start.InSecondsF() << ")";
   1203   CHECK(IsValidId(id));
   1204   source_state_map_[id]->set_append_window_start(start);
   1205 }
   1206 
   1207 void ChunkDemuxer::SetAppendWindowEnd(const std::string& id, TimeDelta end) {
   1208   base::AutoLock auto_lock(lock_);
   1209   DVLOG(1) << "SetAppendWindowEnd(" << id << ", " << end.InSecondsF() << ")";
   1210   CHECK(IsValidId(id));
   1211   source_state_map_[id]->set_append_window_end(end);
   1212 }
   1213 
   1214 void ChunkDemuxer::Shutdown() {
   1215   DVLOG(1) << "Shutdown()";
   1216   base::AutoLock auto_lock(lock_);
   1217 
   1218   if (state_ == SHUTDOWN)
   1219     return;
   1220 
   1221   if (audio_)
   1222     audio_->Shutdown();
   1223 
   1224   if (video_)
   1225     video_->Shutdown();
   1226 
   1227   ChangeState_Locked(SHUTDOWN);
   1228 
   1229   if(!seek_cb_.is_null())
   1230     base::ResetAndReturn(&seek_cb_).Run(PIPELINE_ERROR_ABORT);
   1231 }
   1232 
   1233 void ChunkDemuxer::SetMemoryLimitsForTesting(int memory_limit) {
   1234   if (audio_)
   1235     audio_->set_memory_limit_for_testing(memory_limit);
   1236 
   1237   if (video_)
   1238     video_->set_memory_limit_for_testing(memory_limit);
   1239 }
   1240 
   1241 void ChunkDemuxer::ChangeState_Locked(State new_state) {
   1242   lock_.AssertAcquired();
   1243   DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : "
   1244            << state_ << " -> " << new_state;
   1245   state_ = new_state;
   1246 }
   1247 
   1248 ChunkDemuxer::~ChunkDemuxer() {
   1249   DCHECK_NE(state_, INITIALIZED);
   1250   for (SourceStateMap::iterator it = source_state_map_.begin();
   1251        it != source_state_map_.end(); ++it) {
   1252     delete it->second;
   1253   }
   1254   source_state_map_.clear();
   1255 }
   1256 
   1257 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) {
   1258   DVLOG(1) << "ReportError_Locked(" << error << ")";
   1259   lock_.AssertAcquired();
   1260   DCHECK_NE(error, PIPELINE_OK);
   1261 
   1262   ChangeState_Locked(PARSE_ERROR);
   1263 
   1264   PipelineStatusCB cb;
   1265 
   1266   if (!init_cb_.is_null()) {
   1267     std::swap(cb, init_cb_);
   1268   } else {
   1269     if (!seek_cb_.is_null())
   1270       std::swap(cb, seek_cb_);
   1271 
   1272     if (audio_)
   1273       audio_->Shutdown();
   1274 
   1275     if (video_)
   1276       video_->Shutdown();
   1277   }
   1278 
   1279   if (!cb.is_null()) {
   1280     cb.Run(error);
   1281     return;
   1282   }
   1283 
   1284   base::AutoUnlock auto_unlock(lock_);
   1285   host_->OnDemuxerError(error);
   1286 }
   1287 
   1288 bool ChunkDemuxer::IsSeekWaitingForData_Locked() const {
   1289   lock_.AssertAcquired();
   1290   bool waiting_for_data = false;
   1291 
   1292   if (audio_)
   1293     waiting_for_data = audio_->IsSeekWaitingForData();
   1294 
   1295   if (!waiting_for_data && video_)
   1296     waiting_for_data = video_->IsSeekWaitingForData();
   1297 
   1298   return waiting_for_data;
   1299 }
   1300 
   1301 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) {
   1302   DVLOG(1) << "OnSourceInitDone(" << success << ", "
   1303            << duration.InSecondsF() << ")";
   1304   lock_.AssertAcquired();
   1305   DCHECK_EQ(state_, INITIALIZING);
   1306   if (!success || (!audio_ && !video_)) {
   1307     ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
   1308     return;
   1309   }
   1310 
   1311   if (duration != TimeDelta() && duration_ == kNoTimestamp())
   1312     UpdateDuration(duration);
   1313 
   1314   // Wait until all streams have initialized.
   1315   if ((!source_id_audio_.empty() && !audio_) ||
   1316       (!source_id_video_.empty() && !video_))
   1317     return;
   1318 
   1319   SeekAllSources(GetStartTime());
   1320   StartReturningData();
   1321 
   1322   if (duration_ == kNoTimestamp())
   1323     duration_ = kInfiniteDuration();
   1324 
   1325   // The demuxer is now initialized after the |start_timestamp_| was set.
   1326   ChangeState_Locked(INITIALIZED);
   1327   base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
   1328 }
   1329 
   1330 ChunkDemuxerStream*
   1331 ChunkDemuxer::CreateDemuxerStream(DemuxerStream::Type type) {
   1332   switch (type) {
   1333     case DemuxerStream::AUDIO:
   1334       if (audio_)
   1335         return NULL;
   1336       audio_.reset(new ChunkDemuxerStream(DemuxerStream::AUDIO));
   1337       return audio_.get();
   1338       break;
   1339     case DemuxerStream::VIDEO:
   1340       if (video_)
   1341         return NULL;
   1342       video_.reset(new ChunkDemuxerStream(DemuxerStream::VIDEO));
   1343       return video_.get();
   1344       break;
   1345     case DemuxerStream::UNKNOWN:
   1346     case DemuxerStream::NUM_TYPES:
   1347       NOTREACHED();
   1348       return NULL;
   1349   }
   1350   NOTREACHED();
   1351   return NULL;
   1352 }
   1353 
   1354 bool ChunkDemuxer::OnTextBuffers(
   1355   TextTrack* text_track,
   1356   const StreamParser::BufferQueue& buffers) {
   1357   lock_.AssertAcquired();
   1358   DCHECK_NE(state_, SHUTDOWN);
   1359 
   1360   // TODO(matthewjheaney): IncreaseDurationIfNecessary
   1361 
   1362   for (StreamParser::BufferQueue::const_iterator itr = buffers.begin();
   1363        itr != buffers.end(); ++itr) {
   1364     const StreamParserBuffer* const buffer = itr->get();
   1365     const TimeDelta start = buffer->timestamp();
   1366     const TimeDelta end = start + buffer->duration();
   1367 
   1368     std::string id, settings, content;
   1369 
   1370     WebMWebVTTParser::Parse(buffer->data(),
   1371                             buffer->data_size(),
   1372                             &id, &settings, &content);
   1373 
   1374     text_track->addWebVTTCue(start, end, id, content, settings);
   1375   }
   1376 
   1377   return true;
   1378 }
   1379 
   1380 bool ChunkDemuxer::IsValidId(const std::string& source_id) const {
   1381   lock_.AssertAcquired();
   1382   return source_state_map_.count(source_id) > 0u;
   1383 }
   1384 
   1385 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) {
   1386   DCHECK(duration_ != new_duration);
   1387   user_specified_duration_ = -1;
   1388   duration_ = new_duration;
   1389   host_->SetDuration(new_duration);
   1390 }
   1391 
   1392 void ChunkDemuxer::IncreaseDurationIfNecessary(
   1393     TimeDelta last_appended_buffer_timestamp,
   1394     ChunkDemuxerStream* stream) {
   1395   DCHECK(last_appended_buffer_timestamp != kNoTimestamp());
   1396   if (last_appended_buffer_timestamp <= duration_)
   1397     return;
   1398 
   1399   Ranges<TimeDelta> ranges = stream->GetBufferedRanges(kInfiniteDuration());
   1400   DCHECK_GT(ranges.size(), 0u);
   1401 
   1402   TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1);
   1403   if (last_timestamp_buffered > duration_)
   1404     UpdateDuration(last_timestamp_buffered);
   1405 }
   1406 
   1407 void ChunkDemuxer::DecreaseDurationIfNecessary() {
   1408   Ranges<TimeDelta> ranges = GetBufferedRanges();
   1409   if (ranges.size() == 0u)
   1410     return;
   1411 
   1412   TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1);
   1413   if (last_timestamp_buffered < duration_)
   1414     UpdateDuration(last_timestamp_buffered);
   1415 }
   1416 
   1417 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const {
   1418   if (audio_ && !video_)
   1419     return audio_->GetBufferedRanges(duration_);
   1420   else if (!audio_ && video_)
   1421     return video_->GetBufferedRanges(duration_);
   1422   return ComputeIntersection();
   1423 }
   1424 
   1425 void ChunkDemuxer::StartReturningData() {
   1426   if (audio_)
   1427     audio_->StartReturningData();
   1428 
   1429   if (video_)
   1430     video_->StartReturningData();
   1431 }
   1432 
   1433 void ChunkDemuxer::AbortPendingReads() {
   1434   if (audio_)
   1435     audio_->AbortReads();
   1436 
   1437   if (video_)
   1438     video_->AbortReads();
   1439 }
   1440 
   1441 void ChunkDemuxer::SeekAllSources(TimeDelta seek_time) {
   1442   if (audio_)
   1443     audio_->Seek(seek_time);
   1444 
   1445   if (video_)
   1446     video_->Seek(seek_time);
   1447 }
   1448 
   1449 void ChunkDemuxer::CompletePendingReadsIfPossible() {
   1450   if (audio_)
   1451     audio_->CompletePendingReadIfPossible();
   1452 
   1453   if (video_)
   1454     video_->CompletePendingReadIfPossible();
   1455 }
   1456 
   1457 }  // namespace media
   1458