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