Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / media / filters / chunk_demuxer.cc
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 <limits>
9 #include <list>
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_current_loop.h"
18 #include "media/base/stream_parser_buffer.h"
19 #include "media/base/video_decoder_config.h"
20 #include "media/filters/frame_processor.h"
21 #include "media/filters/legacy_frame_processor.h"
22 #include "media/filters/stream_parser_factory.h"
23
24 using base::TimeDelta;
25
26 namespace media {
27
28 static TimeDelta EndTimestamp(const StreamParser::BufferQueue& queue) {
29   return queue.back()->timestamp() + queue.back()->duration();
30 }
31
32 // List of time ranges for each SourceBuffer.
33 typedef std::list<Ranges<TimeDelta> > RangesList;
34 static Ranges<TimeDelta> ComputeIntersection(const RangesList& activeRanges,
35                                              bool ended) {
36   // Implementation of HTMLMediaElement.buffered algorithm in MSE spec.
37   // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#dom-htmlmediaelement.buffered
38
39   // Step 1: If activeSourceBuffers.length equals 0 then return an empty
40   //  TimeRanges object and abort these steps.
41   if (activeRanges.empty())
42     return Ranges<TimeDelta>();
43
44   // Step 2: Let active ranges be the ranges returned by buffered for each
45   //  SourceBuffer object in activeSourceBuffers.
46   // Step 3: Let highest end time be the largest range end time in the active
47   //  ranges.
48   TimeDelta highest_end_time;
49   for (RangesList::const_iterator itr = activeRanges.begin();
50        itr != activeRanges.end(); ++itr) {
51     if (!itr->size())
52       continue;
53
54     highest_end_time = std::max(highest_end_time, itr->end(itr->size() - 1));
55   }
56
57   // Step 4: Let intersection ranges equal a TimeRange object containing a
58   //  single range from 0 to highest end time.
59   Ranges<TimeDelta> intersection_ranges;
60   intersection_ranges.Add(TimeDelta(), highest_end_time);
61
62   // Step 5: For each SourceBuffer object in activeSourceBuffers run the
63   //  following steps:
64   for (RangesList::const_iterator itr = activeRanges.begin();
65        itr != activeRanges.end(); ++itr) {
66     // Step 5.1: Let source ranges equal the ranges returned by the buffered
67     //  attribute on the current SourceBuffer.
68     Ranges<TimeDelta> source_ranges = *itr;
69
70     // Step 5.2: If readyState is "ended", then set the end time on the last
71     //  range in source ranges to highest end time.
72     if (ended && source_ranges.size() > 0u) {
73       source_ranges.Add(source_ranges.start(source_ranges.size() - 1),
74                         highest_end_time);
75     }
76
77     // Step 5.3: Let new intersection ranges equal the intersection between
78     // the intersection ranges and the source ranges.
79     // Step 5.4: Replace the ranges in intersection ranges with the new
80     // intersection ranges.
81     intersection_ranges = intersection_ranges.IntersectionWith(source_ranges);
82   }
83
84   return intersection_ranges;
85 }
86
87 // Contains state belonging to a source id.
88 class SourceState {
89  public:
90   // Callback signature used to create ChunkDemuxerStreams.
91   typedef base::Callback<ChunkDemuxerStream*(
92       DemuxerStream::Type)> CreateDemuxerStreamCB;
93
94   typedef base::Callback<void(
95       ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB;
96
97   SourceState(
98       scoped_ptr<StreamParser> stream_parser,
99       scoped_ptr<FrameProcessorBase> frame_processor, const LogCB& log_cb,
100       const CreateDemuxerStreamCB& create_demuxer_stream_cb);
101
102   ~SourceState();
103
104   void Init(const StreamParser::InitCB& init_cb,
105             bool allow_audio,
106             bool allow_video,
107             const StreamParser::NeedKeyCB& need_key_cb,
108             const NewTextTrackCB& new_text_track_cb);
109
110   // Appends new data to the StreamParser.
111   // Returns true if the data was successfully appended. Returns false if an
112   // error occurred. |*timestamp_offset| is used and possibly updated by the
113   // append. |append_window_start| and |append_window_end| correspond to the MSE
114   // spec's similarly named source buffer attributes that are used in coded
115   // frame processing.
116   bool Append(const uint8* data, size_t length,
117               TimeDelta append_window_start,
118               TimeDelta append_window_end,
119               TimeDelta* timestamp_offset);
120
121   // Aborts the current append sequence and resets the parser.
122   void Abort(TimeDelta append_window_start,
123              TimeDelta append_window_end,
124              TimeDelta* timestamp_offset);
125
126   // Calls Remove(|start|, |end|, |duration|) on all
127   // ChunkDemuxerStreams managed by this object.
128   void Remove(TimeDelta start, TimeDelta end, TimeDelta duration);
129
130   // Returns true if currently parsing a media segment, or false otherwise.
131   bool parsing_media_segment() const { return parsing_media_segment_; }
132
133   // Sets |frame_processor_|'s sequence mode to |sequence_mode|.
134   void SetSequenceMode(bool sequence_mode);
135
136   // Signals the coded frame processor to update its group start timestamp to be
137   // |timestamp_offset| if it is in sequence append mode.
138   void SetGroupStartTimestampIfInSequenceMode(base::TimeDelta timestamp_offset);
139
140   // Returns the range of buffered data in this source, capped at |duration|.
141   // |ended| - Set to true if end of stream has been signaled and the special
142   // end of stream range logic needs to be executed.
143   Ranges<TimeDelta> GetBufferedRanges(TimeDelta duration, bool ended) const;
144
145   // Returns the highest buffered duration across all streams managed
146   // by this object.
147   // Returns TimeDelta() if none of the streams contain buffered data.
148   TimeDelta GetMaxBufferedDuration() const;
149
150   // Helper methods that call methods with similar names on all the
151   // ChunkDemuxerStreams managed by this object.
152   void StartReturningData();
153   void AbortReads();
154   void Seek(TimeDelta seek_time);
155   void CompletePendingReadIfPossible();
156   void OnSetDuration(TimeDelta duration);
157   void MarkEndOfStream();
158   void UnmarkEndOfStream();
159   void Shutdown();
160   // Sets the memory limit on each stream. |memory_limit| is the
161   // maximum number of bytes each stream is allowed to hold in its buffer.
162   void SetMemoryLimitsForTesting(int memory_limit);
163   bool IsSeekWaitingForData() const;
164
165  private:
166   // Called by the |stream_parser_| when a new initialization segment is
167   // encountered.
168   // Returns true on a successful call. Returns false if an error occurred while
169   // processing decoder configurations.
170   bool OnNewConfigs(bool allow_audio, bool allow_video,
171                     const AudioDecoderConfig& audio_config,
172                     const VideoDecoderConfig& video_config,
173                     const StreamParser::TextTrackConfigMap& text_configs);
174
175   // Called by the |stream_parser_| at the beginning of a new media segment.
176   void OnNewMediaSegment();
177
178   // Called by the |stream_parser_| at the end of a media segment.
179   void OnEndOfMediaSegment();
180
181   // Called by the |stream_parser_| when new buffers have been parsed.
182   // It processes the new buffers using |frame_processor_|, which includes
183   // appending the processed frames to associated demuxer streams for each
184   // frame's track.
185   // Returns true on a successful call. Returns false if an error occurred while
186   // processing the buffers.
187   bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers,
188                     const StreamParser::BufferQueue& video_buffers,
189                     const StreamParser::TextBufferQueueMap& text_map);
190
191   void OnSourceInitDone(bool success,
192                         const StreamParser::InitParameters& params);
193
194   CreateDemuxerStreamCB create_demuxer_stream_cb_;
195   NewTextTrackCB new_text_track_cb_;
196
197   // During Append(), if OnNewBuffers() coded frame processing updates the
198   // timestamp offset then |*timestamp_offset_during_append_| is also updated
199   // so Append()'s caller can know the new offset. This pointer is only non-NULL
200   // during the lifetime of an Append() call.
201   TimeDelta* timestamp_offset_during_append_;
202
203   // During Append(), coded frame processing triggered by OnNewBuffers()
204   // requires these two attributes. These are only valid during the lifetime of
205   // an Append() call.
206   TimeDelta append_window_start_during_append_;
207   TimeDelta append_window_end_during_append_;
208
209   // Set to true if the next buffers appended within the append window
210   // represent the start of a new media segment. This flag being set
211   // triggers a call to |new_segment_cb_| when the new buffers are
212   // appended. The flag is set on actual media segment boundaries and
213   // when the "append window" filtering causes discontinuities in the
214   // appended data.
215   // TODO(wolenetz/acolwell): Investigate if we need this, or if coded frame
216   // processing's discontinuity logic is enough. See http://crbug.com/351489.
217   bool new_media_segment_;
218
219   // Keeps track of whether a media segment is being parsed.
220   bool parsing_media_segment_;
221
222   // The object used to parse appended data.
223   scoped_ptr<StreamParser> stream_parser_;
224
225   ChunkDemuxerStream* audio_;  // Not owned by |this|.
226   ChunkDemuxerStream* video_;  // Not owned by |this|.
227
228   typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap;
229   TextStreamMap text_stream_map_;  // |this| owns the map's stream pointers.
230
231   scoped_ptr<FrameProcessorBase> frame_processor_;
232   LogCB log_cb_;
233   StreamParser::InitCB init_cb_;
234
235   // Indicates that timestampOffset should be updated automatically during
236   // OnNewBuffers() based on the earliest end timestamp of the buffers provided.
237   // TODO(wolenetz): Refactor this function while integrating April 29, 2014
238   // changes to MSE spec. See http://crbug.com/371499.
239   bool auto_update_timestamp_offset_;
240
241   DISALLOW_COPY_AND_ASSIGN(SourceState);
242 };
243
244 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser,
245                          scoped_ptr<FrameProcessorBase> frame_processor,
246                          const LogCB& log_cb,
247                          const CreateDemuxerStreamCB& create_demuxer_stream_cb)
248     : create_demuxer_stream_cb_(create_demuxer_stream_cb),
249       timestamp_offset_during_append_(NULL),
250       new_media_segment_(false),
251       parsing_media_segment_(false),
252       stream_parser_(stream_parser.release()),
253       audio_(NULL),
254       video_(NULL),
255       frame_processor_(frame_processor.release()),
256       log_cb_(log_cb),
257       auto_update_timestamp_offset_(false) {
258   DCHECK(!create_demuxer_stream_cb_.is_null());
259   DCHECK(frame_processor_);
260 }
261
262 SourceState::~SourceState() {
263   Shutdown();
264
265   STLDeleteValues(&text_stream_map_);
266 }
267
268 void SourceState::Init(const StreamParser::InitCB& init_cb,
269                        bool allow_audio,
270                        bool allow_video,
271                        const StreamParser::NeedKeyCB& need_key_cb,
272                        const NewTextTrackCB& new_text_track_cb) {
273   new_text_track_cb_ = new_text_track_cb;
274   init_cb_ = init_cb;
275
276   stream_parser_->Init(
277       base::Bind(&SourceState::OnSourceInitDone, base::Unretained(this)),
278       base::Bind(&SourceState::OnNewConfigs,
279                  base::Unretained(this),
280                  allow_audio,
281                  allow_video),
282       base::Bind(&SourceState::OnNewBuffers, base::Unretained(this)),
283       new_text_track_cb_.is_null(),
284       need_key_cb,
285       base::Bind(&SourceState::OnNewMediaSegment, base::Unretained(this)),
286       base::Bind(&SourceState::OnEndOfMediaSegment, base::Unretained(this)),
287       log_cb_);
288 }
289
290 void SourceState::SetSequenceMode(bool sequence_mode) {
291   DCHECK(!parsing_media_segment_);
292
293   frame_processor_->SetSequenceMode(sequence_mode);
294 }
295
296 void SourceState::SetGroupStartTimestampIfInSequenceMode(
297     base::TimeDelta timestamp_offset) {
298   DCHECK(!parsing_media_segment_);
299
300   frame_processor_->SetGroupStartTimestampIfInSequenceMode(timestamp_offset);
301 }
302
303 bool SourceState::Append(const uint8* data, size_t length,
304                          TimeDelta append_window_start,
305                          TimeDelta append_window_end,
306                          TimeDelta* timestamp_offset) {
307   DCHECK(timestamp_offset);
308   DCHECK(!timestamp_offset_during_append_);
309   append_window_start_during_append_ = append_window_start;
310   append_window_end_during_append_ = append_window_end;
311   timestamp_offset_during_append_ = timestamp_offset;
312
313   // TODO(wolenetz/acolwell): Curry and pass a NewBuffersCB here bound with
314   // append window and timestamp offset pointer. See http://crbug.com/351454.
315   bool err = stream_parser_->Parse(data, length);
316   timestamp_offset_during_append_ = NULL;
317   return err;
318 }
319
320 void SourceState::Abort(TimeDelta append_window_start,
321                         TimeDelta append_window_end,
322                         base::TimeDelta* timestamp_offset) {
323   DCHECK(timestamp_offset);
324   DCHECK(!timestamp_offset_during_append_);
325   timestamp_offset_during_append_ = timestamp_offset;
326   append_window_start_during_append_ = append_window_start;
327   append_window_end_during_append_ = append_window_end;
328
329   stream_parser_->Flush();
330   timestamp_offset_during_append_ = NULL;
331
332   frame_processor_->Reset();
333   parsing_media_segment_ = false;
334 }
335
336 void SourceState::Remove(TimeDelta start, TimeDelta end, TimeDelta duration) {
337   if (audio_)
338     audio_->Remove(start, end, duration);
339
340   if (video_)
341     video_->Remove(start, end, duration);
342
343   for (TextStreamMap::iterator itr = text_stream_map_.begin();
344        itr != text_stream_map_.end(); ++itr) {
345     itr->second->Remove(start, end, duration);
346   }
347 }
348
349 Ranges<TimeDelta> SourceState::GetBufferedRanges(TimeDelta duration,
350                                                  bool ended) const {
351   // TODO(acolwell): When we start allowing disabled tracks we'll need to update
352   // this code to only add ranges from active tracks.
353   RangesList ranges_list;
354   if (audio_)
355     ranges_list.push_back(audio_->GetBufferedRanges(duration));
356
357   if (video_)
358     ranges_list.push_back(video_->GetBufferedRanges(duration));
359
360   for (TextStreamMap::const_iterator itr = text_stream_map_.begin();
361        itr != text_stream_map_.end(); ++itr) {
362     ranges_list.push_back(itr->second->GetBufferedRanges(duration));
363   }
364
365   return ComputeIntersection(ranges_list, ended);
366 }
367
368 TimeDelta SourceState::GetMaxBufferedDuration() const {
369   TimeDelta max_duration;
370
371   if (audio_)
372     max_duration = std::max(max_duration, audio_->GetBufferedDuration());
373
374   if (video_)
375     max_duration = std::max(max_duration, video_->GetBufferedDuration());
376
377   for (TextStreamMap::const_iterator itr = text_stream_map_.begin();
378        itr != text_stream_map_.end(); ++itr) {
379     max_duration = std::max(max_duration, itr->second->GetBufferedDuration());
380   }
381
382   return max_duration;
383 }
384
385 void SourceState::StartReturningData() {
386   if (audio_)
387     audio_->StartReturningData();
388
389   if (video_)
390     video_->StartReturningData();
391
392   for (TextStreamMap::iterator itr = text_stream_map_.begin();
393        itr != text_stream_map_.end(); ++itr) {
394     itr->second->StartReturningData();
395   }
396 }
397
398 void SourceState::AbortReads() {
399   if (audio_)
400     audio_->AbortReads();
401
402   if (video_)
403     video_->AbortReads();
404
405   for (TextStreamMap::iterator itr = text_stream_map_.begin();
406        itr != text_stream_map_.end(); ++itr) {
407     itr->second->AbortReads();
408   }
409 }
410
411 void SourceState::Seek(TimeDelta seek_time) {
412   if (audio_)
413     audio_->Seek(seek_time);
414
415   if (video_)
416     video_->Seek(seek_time);
417
418   for (TextStreamMap::iterator itr = text_stream_map_.begin();
419        itr != text_stream_map_.end(); ++itr) {
420     itr->second->Seek(seek_time);
421   }
422 }
423
424 void SourceState::CompletePendingReadIfPossible() {
425   if (audio_)
426     audio_->CompletePendingReadIfPossible();
427
428   if (video_)
429     video_->CompletePendingReadIfPossible();
430
431   for (TextStreamMap::iterator itr = text_stream_map_.begin();
432        itr != text_stream_map_.end(); ++itr) {
433     itr->second->CompletePendingReadIfPossible();
434   }
435 }
436
437 void SourceState::OnSetDuration(TimeDelta duration) {
438   if (audio_)
439     audio_->OnSetDuration(duration);
440
441   if (video_)
442     video_->OnSetDuration(duration);
443
444   for (TextStreamMap::iterator itr = text_stream_map_.begin();
445        itr != text_stream_map_.end(); ++itr) {
446     itr->second->OnSetDuration(duration);
447   }
448 }
449
450 void SourceState::MarkEndOfStream() {
451   if (audio_)
452     audio_->MarkEndOfStream();
453
454   if (video_)
455     video_->MarkEndOfStream();
456
457   for (TextStreamMap::iterator itr = text_stream_map_.begin();
458        itr != text_stream_map_.end(); ++itr) {
459     itr->second->MarkEndOfStream();
460   }
461 }
462
463 void SourceState::UnmarkEndOfStream() {
464   if (audio_)
465     audio_->UnmarkEndOfStream();
466
467   if (video_)
468     video_->UnmarkEndOfStream();
469
470   for (TextStreamMap::iterator itr = text_stream_map_.begin();
471        itr != text_stream_map_.end(); ++itr) {
472     itr->second->UnmarkEndOfStream();
473   }
474 }
475
476 void SourceState::Shutdown() {
477   if (audio_)
478     audio_->Shutdown();
479
480   if (video_)
481     video_->Shutdown();
482
483   for (TextStreamMap::iterator itr = text_stream_map_.begin();
484        itr != text_stream_map_.end(); ++itr) {
485     itr->second->Shutdown();
486   }
487 }
488
489 void SourceState::SetMemoryLimitsForTesting(int memory_limit) {
490   if (audio_)
491     audio_->set_memory_limit_for_testing(memory_limit);
492
493   if (video_)
494     video_->set_memory_limit_for_testing(memory_limit);
495
496   for (TextStreamMap::iterator itr = text_stream_map_.begin();
497        itr != text_stream_map_.end(); ++itr) {
498     itr->second->set_memory_limit_for_testing(memory_limit);
499   }
500 }
501
502 bool SourceState::IsSeekWaitingForData() const {
503   if (audio_ && audio_->IsSeekWaitingForData())
504     return true;
505
506   if (video_ && video_->IsSeekWaitingForData())
507     return true;
508
509   // NOTE: We are intentionally not checking the text tracks
510   // because text tracks are discontinuous and may not have data
511   // for the seek position. This is ok and playback should not be
512   // stalled because we don't have cues. If cues, with timestamps after
513   // the seek time, eventually arrive they will be delivered properly
514   // in response to ChunkDemuxerStream::Read() calls.
515
516   return false;
517 }
518
519 bool SourceState::OnNewConfigs(
520     bool allow_audio, bool allow_video,
521     const AudioDecoderConfig& audio_config,
522     const VideoDecoderConfig& video_config,
523     const StreamParser::TextTrackConfigMap& text_configs) {
524   DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video
525            << ", " << audio_config.IsValidConfig()
526            << ", " << video_config.IsValidConfig() << ")";
527
528   if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) {
529     DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!";
530     return false;
531   }
532
533   // Signal an error if we get configuration info for stream types that weren't
534   // specified in AddId() or more configs after a stream is initialized.
535   if (allow_audio != audio_config.IsValidConfig()) {
536     MEDIA_LOG(log_cb_)
537         << "Initialization segment"
538         << (audio_config.IsValidConfig() ? " has" : " does not have")
539         << " an audio track, but the mimetype"
540         << (allow_audio ? " specifies" : " does not specify")
541         << " an audio codec.";
542     return false;
543   }
544
545   if (allow_video != video_config.IsValidConfig()) {
546     MEDIA_LOG(log_cb_)
547         << "Initialization segment"
548         << (video_config.IsValidConfig() ? " has" : " does not have")
549         << " a video track, but the mimetype"
550         << (allow_video ? " specifies" : " does not specify")
551         << " a video codec.";
552     return false;
553   }
554
555   bool success = true;
556   if (audio_config.IsValidConfig()) {
557     if (!audio_) {
558       audio_ = create_demuxer_stream_cb_.Run(DemuxerStream::AUDIO);
559
560       if (!audio_) {
561         DVLOG(1) << "Failed to create an audio stream.";
562         return false;
563       }
564
565       if (!frame_processor_->AddTrack(FrameProcessorBase::kAudioTrackId,
566                                       audio_)) {
567         DVLOG(1) << "Failed to add audio track to frame processor.";
568         return false;
569       }
570     }
571
572     success &= audio_->UpdateAudioConfig(audio_config, log_cb_);
573   }
574
575   if (video_config.IsValidConfig()) {
576     if (!video_) {
577       video_ = create_demuxer_stream_cb_.Run(DemuxerStream::VIDEO);
578
579       if (!video_) {
580         DVLOG(1) << "Failed to create a video stream.";
581         return false;
582       }
583
584       if (!frame_processor_->AddTrack(FrameProcessorBase::kVideoTrackId,
585                                       video_)) {
586         DVLOG(1) << "Failed to add video track to frame processor.";
587         return false;
588       }
589     }
590
591     success &= video_->UpdateVideoConfig(video_config, log_cb_);
592   }
593
594   typedef StreamParser::TextTrackConfigMap::const_iterator TextConfigItr;
595   if (text_stream_map_.empty()) {
596     for (TextConfigItr itr = text_configs.begin();
597          itr != text_configs.end(); ++itr) {
598       ChunkDemuxerStream* const text_stream =
599           create_demuxer_stream_cb_.Run(DemuxerStream::TEXT);
600       if (!frame_processor_->AddTrack(itr->first, text_stream)) {
601         success &= false;
602         MEDIA_LOG(log_cb_) << "Failed to add text track ID " << itr->first
603                            << " to frame processor.";
604         break;
605       }
606       text_stream->UpdateTextConfig(itr->second, log_cb_);
607       text_stream_map_[itr->first] = text_stream;
608       new_text_track_cb_.Run(text_stream, itr->second);
609     }
610   } else {
611     const size_t text_count = text_stream_map_.size();
612     if (text_configs.size() != text_count) {
613       success &= false;
614       MEDIA_LOG(log_cb_) << "The number of text track configs changed.";
615     } else if (text_count == 1) {
616       TextConfigItr config_itr = text_configs.begin();
617       const TextTrackConfig& new_config = config_itr->second;
618       TextStreamMap::iterator stream_itr = text_stream_map_.begin();
619       ChunkDemuxerStream* text_stream = stream_itr->second;
620       TextTrackConfig old_config = text_stream->text_track_config();
621       if (!new_config.Matches(old_config)) {
622         success &= false;
623         MEDIA_LOG(log_cb_) << "New text track config does not match old one.";
624       } else {
625         text_stream_map_.clear();
626         text_stream_map_[config_itr->first] = text_stream;
627       }
628     } else {
629       for (TextConfigItr config_itr = text_configs.begin();
630            config_itr != text_configs.end(); ++config_itr) {
631         TextStreamMap::iterator stream_itr =
632             text_stream_map_.find(config_itr->first);
633         if (stream_itr == text_stream_map_.end()) {
634           success &= false;
635           MEDIA_LOG(log_cb_) << "Unexpected text track configuration "
636                                 "for track ID "
637                              << config_itr->first;
638           break;
639         }
640
641         const TextTrackConfig& new_config = config_itr->second;
642         ChunkDemuxerStream* stream = stream_itr->second;
643         TextTrackConfig old_config = stream->text_track_config();
644         if (!new_config.Matches(old_config)) {
645           success &= false;
646           MEDIA_LOG(log_cb_) << "New text track config for track ID "
647                              << config_itr->first
648                              << " does not match old one.";
649           break;
650         }
651       }
652     }
653   }
654
655   DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed");
656   return success;
657 }
658
659 void SourceState::OnNewMediaSegment() {
660   DVLOG(2) << "OnNewMediaSegment()";
661   parsing_media_segment_ = true;
662   new_media_segment_ = true;
663 }
664
665 void SourceState::OnEndOfMediaSegment() {
666   DVLOG(2) << "OnEndOfMediaSegment()";
667   parsing_media_segment_ = false;
668   new_media_segment_ = false;
669 }
670
671 bool SourceState::OnNewBuffers(
672     const StreamParser::BufferQueue& audio_buffers,
673     const StreamParser::BufferQueue& video_buffers,
674     const StreamParser::TextBufferQueueMap& text_map) {
675   DVLOG(2) << "OnNewBuffers()";
676   DCHECK(timestamp_offset_during_append_);
677   DCHECK(parsing_media_segment_);
678
679   const TimeDelta timestamp_offset_before_processing =
680       *timestamp_offset_during_append_;
681
682   // Calculate the new timestamp offset for audio/video tracks if the stream
683   // parser has requested automatic updates.
684   TimeDelta new_timestamp_offset = timestamp_offset_before_processing;
685   if (auto_update_timestamp_offset_) {
686     const bool have_audio_buffers = !audio_buffers.empty();
687     const bool have_video_buffers = !video_buffers.empty();
688     if (have_audio_buffers && have_video_buffers) {
689       new_timestamp_offset +=
690           std::min(EndTimestamp(audio_buffers), EndTimestamp(video_buffers));
691     } else if (have_audio_buffers) {
692       new_timestamp_offset += EndTimestamp(audio_buffers);
693     } else if (have_video_buffers) {
694       new_timestamp_offset += EndTimestamp(video_buffers);
695     }
696   }
697
698   if (!frame_processor_->ProcessFrames(audio_buffers,
699                                        video_buffers,
700                                        text_map,
701                                        append_window_start_during_append_,
702                                        append_window_end_during_append_,
703                                        &new_media_segment_,
704                                        timestamp_offset_during_append_)) {
705     return false;
706   }
707
708   // Only update the timestamp offset if the frame processor hasn't already.
709   if (auto_update_timestamp_offset_ &&
710       timestamp_offset_before_processing == *timestamp_offset_during_append_) {
711     *timestamp_offset_during_append_ = new_timestamp_offset;
712   }
713
714   return true;
715 }
716
717 void SourceState::OnSourceInitDone(bool success,
718                                    const StreamParser::InitParameters& params) {
719   auto_update_timestamp_offset_ = params.auto_update_timestamp_offset;
720   base::ResetAndReturn(&init_cb_).Run(success, params);
721 }
722
723 ChunkDemuxerStream::ChunkDemuxerStream(Type type, bool splice_frames_enabled)
724     : type_(type),
725       state_(UNINITIALIZED),
726       splice_frames_enabled_(splice_frames_enabled),
727       partial_append_window_trimming_enabled_(false) {
728 }
729
730 void ChunkDemuxerStream::StartReturningData() {
731   DVLOG(1) << "ChunkDemuxerStream::StartReturningData()";
732   base::AutoLock auto_lock(lock_);
733   DCHECK(read_cb_.is_null());
734   ChangeState_Locked(RETURNING_DATA_FOR_READS);
735 }
736
737 void ChunkDemuxerStream::AbortReads() {
738   DVLOG(1) << "ChunkDemuxerStream::AbortReads()";
739   base::AutoLock auto_lock(lock_);
740   ChangeState_Locked(RETURNING_ABORT_FOR_READS);
741   if (!read_cb_.is_null())
742     base::ResetAndReturn(&read_cb_).Run(kAborted, NULL);
743 }
744
745 void ChunkDemuxerStream::CompletePendingReadIfPossible() {
746   base::AutoLock auto_lock(lock_);
747   if (read_cb_.is_null())
748     return;
749
750   CompletePendingReadIfPossible_Locked();
751 }
752
753 void ChunkDemuxerStream::Shutdown() {
754   DVLOG(1) << "ChunkDemuxerStream::Shutdown()";
755   base::AutoLock auto_lock(lock_);
756   ChangeState_Locked(SHUTDOWN);
757
758   // Pass an end of stream buffer to the pending callback to signal that no more
759   // data will be sent.
760   if (!read_cb_.is_null()) {
761     base::ResetAndReturn(&read_cb_).Run(DemuxerStream::kOk,
762                                         StreamParserBuffer::CreateEOSBuffer());
763   }
764 }
765
766 bool ChunkDemuxerStream::IsSeekWaitingForData() const {
767   base::AutoLock auto_lock(lock_);
768
769   // This method should not be called for text tracks. See the note in
770   // SourceState::IsSeekWaitingForData().
771   DCHECK_NE(type_, DemuxerStream::TEXT);
772
773   return stream_->IsSeekPending();
774 }
775
776 void ChunkDemuxerStream::Seek(TimeDelta time) {
777   DVLOG(1) << "ChunkDemuxerStream::Seek(" << time.InSecondsF() << ")";
778   base::AutoLock auto_lock(lock_);
779   DCHECK(read_cb_.is_null());
780   DCHECK(state_ == UNINITIALIZED || state_ == RETURNING_ABORT_FOR_READS)
781       << state_;
782
783   stream_->Seek(time);
784 }
785
786 bool ChunkDemuxerStream::Append(const StreamParser::BufferQueue& buffers) {
787   if (buffers.empty())
788     return false;
789
790   base::AutoLock auto_lock(lock_);
791   DCHECK_NE(state_, SHUTDOWN);
792   if (!stream_->Append(buffers)) {
793     DVLOG(1) << "ChunkDemuxerStream::Append() : stream append failed";
794     return false;
795   }
796
797   if (!read_cb_.is_null())
798     CompletePendingReadIfPossible_Locked();
799
800   return true;
801 }
802
803 void ChunkDemuxerStream::Remove(TimeDelta start, TimeDelta end,
804                                 TimeDelta duration) {
805   base::AutoLock auto_lock(lock_);
806   stream_->Remove(start, end, duration);
807 }
808
809 void ChunkDemuxerStream::OnSetDuration(TimeDelta duration) {
810   base::AutoLock auto_lock(lock_);
811   stream_->OnSetDuration(duration);
812 }
813
814 Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedRanges(
815     TimeDelta duration) const {
816   base::AutoLock auto_lock(lock_);
817
818   if (type_ == TEXT) {
819     // Since text tracks are discontinuous and the lack of cues should not block
820     // playback, report the buffered range for text tracks as [0, |duration|) so
821     // that intesections with audio & video tracks are computed correctly when
822     // no cues are present.
823     Ranges<TimeDelta> text_range;
824     text_range.Add(TimeDelta(), duration);
825     return text_range;
826   }
827
828   Ranges<TimeDelta> range = stream_->GetBufferedTime();
829
830   if (range.size() == 0u)
831     return range;
832
833   // Clamp the end of the stream's buffered ranges to fit within the duration.
834   // This can be done by intersecting the stream's range with the valid time
835   // range.
836   Ranges<TimeDelta> valid_time_range;
837   valid_time_range.Add(range.start(0), duration);
838   return range.IntersectionWith(valid_time_range);
839 }
840
841 TimeDelta ChunkDemuxerStream::GetBufferedDuration() const {
842   return stream_->GetBufferedDuration();
843 }
844
845 void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) {
846   DVLOG(2) << "ChunkDemuxerStream::OnNewMediaSegment("
847            << start_timestamp.InSecondsF() << ")";
848   base::AutoLock auto_lock(lock_);
849   stream_->OnNewMediaSegment(start_timestamp);
850 }
851
852 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config,
853                                            const LogCB& log_cb) {
854   DCHECK(config.IsValidConfig());
855   DCHECK_EQ(type_, AUDIO);
856   base::AutoLock auto_lock(lock_);
857   if (!stream_) {
858     DCHECK_EQ(state_, UNINITIALIZED);
859
860     // On platforms which support splice frames, enable splice frames and
861     // partial append window support for a limited set of codecs.
862     // TODO(dalecurtis): Verify this works for codecs other than MP3 and Vorbis.
863     // Right now we want to be extremely conservative to ensure we don't break
864     // the world.
865     const bool mp3_or_vorbis =
866         config.codec() == kCodecMP3 || config.codec() == kCodecVorbis;
867     splice_frames_enabled_ = splice_frames_enabled_ && mp3_or_vorbis;
868     partial_append_window_trimming_enabled_ =
869         splice_frames_enabled_ && mp3_or_vorbis;
870
871     stream_.reset(
872         new SourceBufferStream(config, log_cb, splice_frames_enabled_));
873     return true;
874   }
875
876   return stream_->UpdateAudioConfig(config);
877 }
878
879 bool ChunkDemuxerStream::UpdateVideoConfig(const VideoDecoderConfig& config,
880                                            const LogCB& log_cb) {
881   DCHECK(config.IsValidConfig());
882   DCHECK_EQ(type_, VIDEO);
883   base::AutoLock auto_lock(lock_);
884
885   if (!stream_) {
886     DCHECK_EQ(state_, UNINITIALIZED);
887     stream_.reset(
888         new SourceBufferStream(config, log_cb, splice_frames_enabled_));
889     return true;
890   }
891
892   return stream_->UpdateVideoConfig(config);
893 }
894
895 void ChunkDemuxerStream::UpdateTextConfig(const TextTrackConfig& config,
896                                           const LogCB& log_cb) {
897   DCHECK_EQ(type_, TEXT);
898   base::AutoLock auto_lock(lock_);
899   DCHECK(!stream_);
900   DCHECK_EQ(state_, UNINITIALIZED);
901   stream_.reset(new SourceBufferStream(config, log_cb, splice_frames_enabled_));
902 }
903
904 void ChunkDemuxerStream::MarkEndOfStream() {
905   base::AutoLock auto_lock(lock_);
906   stream_->MarkEndOfStream();
907 }
908
909 void ChunkDemuxerStream::UnmarkEndOfStream() {
910   base::AutoLock auto_lock(lock_);
911   stream_->UnmarkEndOfStream();
912 }
913
914 // DemuxerStream methods.
915 void ChunkDemuxerStream::Read(const ReadCB& read_cb) {
916   base::AutoLock auto_lock(lock_);
917   DCHECK_NE(state_, UNINITIALIZED);
918   DCHECK(read_cb_.is_null());
919
920   read_cb_ = BindToCurrentLoop(read_cb);
921   CompletePendingReadIfPossible_Locked();
922 }
923
924 DemuxerStream::Type ChunkDemuxerStream::type() { return type_; }
925
926 void ChunkDemuxerStream::EnableBitstreamConverter() {}
927
928 AudioDecoderConfig ChunkDemuxerStream::audio_decoder_config() {
929   CHECK_EQ(type_, AUDIO);
930   base::AutoLock auto_lock(lock_);
931   return stream_->GetCurrentAudioDecoderConfig();
932 }
933
934 VideoDecoderConfig ChunkDemuxerStream::video_decoder_config() {
935   CHECK_EQ(type_, VIDEO);
936   base::AutoLock auto_lock(lock_);
937   return stream_->GetCurrentVideoDecoderConfig();
938 }
939
940 bool ChunkDemuxerStream::SupportsConfigChanges() { return true; }
941
942 TextTrackConfig ChunkDemuxerStream::text_track_config() {
943   CHECK_EQ(type_, TEXT);
944   base::AutoLock auto_lock(lock_);
945   return stream_->GetCurrentTextTrackConfig();
946 }
947
948 void ChunkDemuxerStream::ChangeState_Locked(State state) {
949   lock_.AssertAcquired();
950   DVLOG(1) << "ChunkDemuxerStream::ChangeState_Locked() : "
951            << "type " << type_
952            << " - " << state_ << " -> " << state;
953   state_ = state;
954 }
955
956 ChunkDemuxerStream::~ChunkDemuxerStream() {}
957
958 void ChunkDemuxerStream::CompletePendingReadIfPossible_Locked() {
959   lock_.AssertAcquired();
960   DCHECK(!read_cb_.is_null());
961
962   DemuxerStream::Status status;
963   scoped_refptr<StreamParserBuffer> buffer;
964
965   switch (state_) {
966     case UNINITIALIZED:
967       NOTREACHED();
968       return;
969     case RETURNING_DATA_FOR_READS:
970       switch (stream_->GetNextBuffer(&buffer)) {
971         case SourceBufferStream::kSuccess:
972           status = DemuxerStream::kOk;
973           break;
974         case SourceBufferStream::kNeedBuffer:
975           // Return early without calling |read_cb_| since we don't have
976           // any data to return yet.
977           return;
978         case SourceBufferStream::kEndOfStream:
979           status = DemuxerStream::kOk;
980           buffer = StreamParserBuffer::CreateEOSBuffer();
981           break;
982         case SourceBufferStream::kConfigChange:
983           DVLOG(2) << "Config change reported to ChunkDemuxerStream.";
984           status = kConfigChanged;
985           buffer = NULL;
986           break;
987       }
988       break;
989     case RETURNING_ABORT_FOR_READS:
990       // Null buffers should be returned in this state since we are waiting
991       // for a seek. Any buffers in the SourceBuffer should NOT be returned
992       // because they are associated with the seek.
993       status = DemuxerStream::kAborted;
994       buffer = NULL;
995       break;
996     case SHUTDOWN:
997       status = DemuxerStream::kOk;
998       buffer = StreamParserBuffer::CreateEOSBuffer();
999       break;
1000   }
1001
1002   base::ResetAndReturn(&read_cb_).Run(status, buffer);
1003 }
1004
1005 ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb,
1006                            const NeedKeyCB& need_key_cb,
1007                            const LogCB& log_cb,
1008                            bool splice_frames_enabled)
1009     : state_(WAITING_FOR_INIT),
1010       cancel_next_seek_(false),
1011       host_(NULL),
1012       open_cb_(open_cb),
1013       need_key_cb_(need_key_cb),
1014       enable_text_(false),
1015       log_cb_(log_cb),
1016       duration_(kNoTimestamp()),
1017       user_specified_duration_(-1),
1018       liveness_(LIVENESS_UNKNOWN),
1019       splice_frames_enabled_(splice_frames_enabled) {
1020   DCHECK(!open_cb_.is_null());
1021   DCHECK(!need_key_cb_.is_null());
1022 }
1023
1024 void ChunkDemuxer::Initialize(
1025     DemuxerHost* host,
1026     const PipelineStatusCB& cb,
1027     bool enable_text_tracks) {
1028   DVLOG(1) << "Init()";
1029
1030   base::AutoLock auto_lock(lock_);
1031
1032   init_cb_ = BindToCurrentLoop(cb);
1033   if (state_ == SHUTDOWN) {
1034     base::ResetAndReturn(&init_cb_).Run(DEMUXER_ERROR_COULD_NOT_OPEN);
1035     return;
1036   }
1037   DCHECK_EQ(state_, WAITING_FOR_INIT);
1038   host_ = host;
1039   enable_text_ = enable_text_tracks;
1040
1041   ChangeState_Locked(INITIALIZING);
1042
1043   base::ResetAndReturn(&open_cb_).Run();
1044 }
1045
1046 void ChunkDemuxer::Stop(const base::Closure& callback) {
1047   DVLOG(1) << "Stop()";
1048   Shutdown();
1049   callback.Run();
1050 }
1051
1052 void ChunkDemuxer::Seek(TimeDelta time, const PipelineStatusCB& cb) {
1053   DVLOG(1) << "Seek(" << time.InSecondsF() << ")";
1054   DCHECK(time >= TimeDelta());
1055
1056   base::AutoLock auto_lock(lock_);
1057   DCHECK(seek_cb_.is_null());
1058
1059   seek_cb_ = BindToCurrentLoop(cb);
1060   if (state_ != INITIALIZED && state_ != ENDED) {
1061     base::ResetAndReturn(&seek_cb_).Run(PIPELINE_ERROR_INVALID_STATE);
1062     return;
1063   }
1064
1065   if (cancel_next_seek_) {
1066     cancel_next_seek_ = false;
1067     base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
1068     return;
1069   }
1070
1071   SeekAllSources(time);
1072   StartReturningData();
1073
1074   if (IsSeekWaitingForData_Locked()) {
1075     DVLOG(1) << "Seek() : waiting for more data to arrive.";
1076     return;
1077   }
1078
1079   base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
1080 }
1081
1082 // Demuxer implementation.
1083 DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) {
1084   DCHECK_NE(type, DemuxerStream::TEXT);
1085   base::AutoLock auto_lock(lock_);
1086   if (type == DemuxerStream::VIDEO)
1087     return video_.get();
1088
1089   if (type == DemuxerStream::AUDIO)
1090     return audio_.get();
1091
1092   return NULL;
1093 }
1094
1095 TimeDelta ChunkDemuxer::GetStartTime() const {
1096   return TimeDelta();
1097 }
1098
1099 base::Time ChunkDemuxer::GetTimelineOffset() const {
1100   return timeline_offset_;
1101 }
1102
1103 Demuxer::Liveness ChunkDemuxer::GetLiveness() const {
1104   return liveness_;
1105 }
1106
1107 void ChunkDemuxer::StartWaitingForSeek(TimeDelta seek_time) {
1108   DVLOG(1) << "StartWaitingForSeek()";
1109   base::AutoLock auto_lock(lock_);
1110   DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN ||
1111          state_ == PARSE_ERROR) << state_;
1112   DCHECK(seek_cb_.is_null());
1113
1114   if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
1115     return;
1116
1117   AbortPendingReads();
1118   SeekAllSources(seek_time);
1119
1120   // Cancel state set in CancelPendingSeek() since we want to
1121   // accept the next Seek().
1122   cancel_next_seek_ = false;
1123 }
1124
1125 void ChunkDemuxer::CancelPendingSeek(TimeDelta seek_time) {
1126   base::AutoLock auto_lock(lock_);
1127   DCHECK_NE(state_, INITIALIZING);
1128   DCHECK(seek_cb_.is_null() || IsSeekWaitingForData_Locked());
1129
1130   if (cancel_next_seek_)
1131     return;
1132
1133   AbortPendingReads();
1134   SeekAllSources(seek_time);
1135
1136   if (seek_cb_.is_null()) {
1137     cancel_next_seek_ = true;
1138     return;
1139   }
1140
1141   base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
1142 }
1143
1144 ChunkDemuxer::Status ChunkDemuxer::AddId(
1145     const std::string& id,
1146     const std::string& type,
1147     std::vector<std::string>& codecs,
1148     const bool use_legacy_frame_processor) {
1149   base::AutoLock auto_lock(lock_);
1150
1151   if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id))
1152     return kReachedIdLimit;
1153
1154   bool has_audio = false;
1155   bool has_video = false;
1156   scoped_ptr<media::StreamParser> stream_parser(
1157       StreamParserFactory::Create(type, codecs, log_cb_,
1158                                   &has_audio, &has_video));
1159
1160   if (!stream_parser)
1161     return ChunkDemuxer::kNotSupported;
1162
1163   if ((has_audio && !source_id_audio_.empty()) ||
1164       (has_video && !source_id_video_.empty()))
1165     return kReachedIdLimit;
1166
1167   if (has_audio)
1168     source_id_audio_ = id;
1169
1170   if (has_video)
1171     source_id_video_ = id;
1172
1173   scoped_ptr<FrameProcessorBase> frame_processor;
1174   if (use_legacy_frame_processor) {
1175     frame_processor.reset(new LegacyFrameProcessor(
1176         base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary,
1177                    base::Unretained(this))));
1178   } else {
1179     frame_processor.reset(new FrameProcessor(
1180         base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary,
1181                    base::Unretained(this))));
1182   }
1183
1184   scoped_ptr<SourceState> source_state(
1185       new SourceState(stream_parser.Pass(),
1186                       frame_processor.Pass(), log_cb_,
1187                       base::Bind(&ChunkDemuxer::CreateDemuxerStream,
1188                                  base::Unretained(this))));
1189
1190   SourceState::NewTextTrackCB new_text_track_cb;
1191
1192   if (enable_text_) {
1193     new_text_track_cb = base::Bind(&ChunkDemuxer::OnNewTextTrack,
1194                                    base::Unretained(this));
1195   }
1196
1197   source_state->Init(
1198       base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)),
1199       has_audio,
1200       has_video,
1201       need_key_cb_,
1202       new_text_track_cb);
1203
1204   source_state_map_[id] = source_state.release();
1205   return kOk;
1206 }
1207
1208 void ChunkDemuxer::RemoveId(const std::string& id) {
1209   base::AutoLock auto_lock(lock_);
1210   CHECK(IsValidId(id));
1211
1212   delete source_state_map_[id];
1213   source_state_map_.erase(id);
1214
1215   if (source_id_audio_ == id)
1216     source_id_audio_.clear();
1217
1218   if (source_id_video_ == id)
1219     source_id_video_.clear();
1220 }
1221
1222 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const {
1223   base::AutoLock auto_lock(lock_);
1224   DCHECK(!id.empty());
1225
1226   SourceStateMap::const_iterator itr = source_state_map_.find(id);
1227
1228   DCHECK(itr != source_state_map_.end());
1229   return itr->second->GetBufferedRanges(duration_, state_ == ENDED);
1230 }
1231
1232 void ChunkDemuxer::AppendData(const std::string& id,
1233                               const uint8* data, size_t length,
1234                               TimeDelta append_window_start,
1235                               TimeDelta append_window_end,
1236                               TimeDelta* timestamp_offset) {
1237   DVLOG(1) << "AppendData(" << id << ", " << length << ")";
1238
1239   DCHECK(!id.empty());
1240   DCHECK(timestamp_offset);
1241
1242   Ranges<TimeDelta> ranges;
1243
1244   {
1245     base::AutoLock auto_lock(lock_);
1246     DCHECK_NE(state_, ENDED);
1247
1248     // Capture if any of the SourceBuffers are waiting for data before we start
1249     // parsing.
1250     bool old_waiting_for_data = IsSeekWaitingForData_Locked();
1251
1252     if (length == 0u)
1253       return;
1254
1255     DCHECK(data);
1256
1257     switch (state_) {
1258       case INITIALIZING:
1259         DCHECK(IsValidId(id));
1260         if (!source_state_map_[id]->Append(data, length,
1261                                            append_window_start,
1262                                            append_window_end,
1263                                            timestamp_offset)) {
1264           ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1265           return;
1266         }
1267         break;
1268
1269       case INITIALIZED: {
1270         DCHECK(IsValidId(id));
1271         if (!source_state_map_[id]->Append(data, length,
1272                                            append_window_start,
1273                                            append_window_end,
1274                                            timestamp_offset)) {
1275           ReportError_Locked(PIPELINE_ERROR_DECODE);
1276           return;
1277         }
1278       } break;
1279
1280       case PARSE_ERROR:
1281         DVLOG(1) << "AppendData(): Ignoring data after a parse error.";
1282         return;
1283
1284       case WAITING_FOR_INIT:
1285       case ENDED:
1286       case SHUTDOWN:
1287         DVLOG(1) << "AppendData(): called in unexpected state " << state_;
1288         return;
1289     }
1290
1291     // Check to see if data was appended at the pending seek point. This
1292     // indicates we have parsed enough data to complete the seek.
1293     if (old_waiting_for_data && !IsSeekWaitingForData_Locked() &&
1294         !seek_cb_.is_null()) {
1295       base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
1296     }
1297
1298     ranges = GetBufferedRanges_Locked();
1299   }
1300
1301   for (size_t i = 0; i < ranges.size(); ++i)
1302     host_->AddBufferedTimeRange(ranges.start(i), ranges.end(i));
1303 }
1304
1305 void ChunkDemuxer::Abort(const std::string& id,
1306                          TimeDelta append_window_start,
1307                          TimeDelta append_window_end,
1308                          TimeDelta* timestamp_offset) {
1309   DVLOG(1) << "Abort(" << id << ")";
1310   base::AutoLock auto_lock(lock_);
1311   DCHECK(!id.empty());
1312   CHECK(IsValidId(id));
1313   source_state_map_[id]->Abort(append_window_start,
1314                                append_window_end,
1315                                timestamp_offset);
1316 }
1317
1318 void ChunkDemuxer::Remove(const std::string& id, TimeDelta start,
1319                           TimeDelta end) {
1320   DVLOG(1) << "Remove(" << id << ", " << start.InSecondsF()
1321            << ", " << end.InSecondsF() << ")";
1322   base::AutoLock auto_lock(lock_);
1323
1324   DCHECK(!id.empty());
1325   CHECK(IsValidId(id));
1326   source_state_map_[id]->Remove(start, end, duration_);
1327 }
1328
1329 double ChunkDemuxer::GetDuration() {
1330   base::AutoLock auto_lock(lock_);
1331   return GetDuration_Locked();
1332 }
1333
1334 double ChunkDemuxer::GetDuration_Locked() {
1335   lock_.AssertAcquired();
1336   if (duration_ == kNoTimestamp())
1337     return std::numeric_limits<double>::quiet_NaN();
1338
1339   // Return positive infinity if the resource is unbounded.
1340   // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-media-duration
1341   if (duration_ == kInfiniteDuration())
1342     return std::numeric_limits<double>::infinity();
1343
1344   if (user_specified_duration_ >= 0)
1345     return user_specified_duration_;
1346
1347   return duration_.InSecondsF();
1348 }
1349
1350 void ChunkDemuxer::SetDuration(double duration) {
1351   base::AutoLock auto_lock(lock_);
1352   DVLOG(1) << "SetDuration(" << duration << ")";
1353   DCHECK_GE(duration, 0);
1354
1355   if (duration == GetDuration_Locked())
1356     return;
1357
1358   // Compute & bounds check the TimeDelta representation of duration.
1359   // This can be different if the value of |duration| doesn't fit the range or
1360   // precision of TimeDelta.
1361   TimeDelta min_duration = TimeDelta::FromInternalValue(1);
1362   // Don't use TimeDelta::Max() here, as we want the largest finite time delta.
1363   TimeDelta max_duration = TimeDelta::FromInternalValue(kint64max - 1);
1364   double min_duration_in_seconds = min_duration.InSecondsF();
1365   double max_duration_in_seconds = max_duration.InSecondsF();
1366
1367   TimeDelta duration_td;
1368   if (duration == std::numeric_limits<double>::infinity()) {
1369     duration_td = media::kInfiniteDuration();
1370   } else if (duration < min_duration_in_seconds) {
1371     duration_td = min_duration;
1372   } else if (duration > max_duration_in_seconds) {
1373     duration_td = max_duration;
1374   } else {
1375     duration_td = TimeDelta::FromMicroseconds(
1376         duration * base::Time::kMicrosecondsPerSecond);
1377   }
1378
1379   DCHECK(duration_td > TimeDelta());
1380
1381   user_specified_duration_ = duration;
1382   duration_ = duration_td;
1383   host_->SetDuration(duration_);
1384
1385   for (SourceStateMap::iterator itr = source_state_map_.begin();
1386        itr != source_state_map_.end(); ++itr) {
1387     itr->second->OnSetDuration(duration_);
1388   }
1389 }
1390
1391 bool ChunkDemuxer::IsParsingMediaSegment(const std::string& id) {
1392   base::AutoLock auto_lock(lock_);
1393   DVLOG(1) << "IsParsingMediaSegment(" << id << ")";
1394   CHECK(IsValidId(id));
1395
1396   return source_state_map_[id]->parsing_media_segment();
1397 }
1398
1399 void ChunkDemuxer::SetSequenceMode(const std::string& id,
1400                                    bool sequence_mode) {
1401   base::AutoLock auto_lock(lock_);
1402   DVLOG(1) << "SetSequenceMode(" << id << ", " << sequence_mode << ")";
1403   CHECK(IsValidId(id));
1404   DCHECK_NE(state_, ENDED);
1405
1406   source_state_map_[id]->SetSequenceMode(sequence_mode);
1407 }
1408
1409 void ChunkDemuxer::SetGroupStartTimestampIfInSequenceMode(
1410     const std::string& id,
1411     base::TimeDelta timestamp_offset) {
1412   base::AutoLock auto_lock(lock_);
1413   DVLOG(1) << "SetGroupStartTimestampIfInSequenceMode(" << id << ", "
1414            << timestamp_offset.InSecondsF() << ")";
1415   CHECK(IsValidId(id));
1416   DCHECK_NE(state_, ENDED);
1417
1418   source_state_map_[id]->SetGroupStartTimestampIfInSequenceMode(
1419       timestamp_offset);
1420 }
1421
1422
1423 void ChunkDemuxer::MarkEndOfStream(PipelineStatus status) {
1424   DVLOG(1) << "MarkEndOfStream(" << status << ")";
1425   base::AutoLock auto_lock(lock_);
1426   DCHECK_NE(state_, WAITING_FOR_INIT);
1427   DCHECK_NE(state_, ENDED);
1428
1429   if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
1430     return;
1431
1432   if (state_ == INITIALIZING) {
1433     ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1434     return;
1435   }
1436
1437   bool old_waiting_for_data = IsSeekWaitingForData_Locked();
1438   for (SourceStateMap::iterator itr = source_state_map_.begin();
1439        itr != source_state_map_.end(); ++itr) {
1440     itr->second->MarkEndOfStream();
1441   }
1442
1443   CompletePendingReadsIfPossible();
1444
1445   // Give a chance to resume the pending seek process.
1446   if (status != PIPELINE_OK) {
1447     ReportError_Locked(status);
1448     return;
1449   }
1450
1451   ChangeState_Locked(ENDED);
1452   DecreaseDurationIfNecessary();
1453
1454   if (old_waiting_for_data && !IsSeekWaitingForData_Locked() &&
1455       !seek_cb_.is_null()) {
1456     base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
1457   }
1458 }
1459
1460 void ChunkDemuxer::UnmarkEndOfStream() {
1461   DVLOG(1) << "UnmarkEndOfStream()";
1462   base::AutoLock auto_lock(lock_);
1463   DCHECK_EQ(state_, ENDED);
1464
1465   ChangeState_Locked(INITIALIZED);
1466
1467   for (SourceStateMap::iterator itr = source_state_map_.begin();
1468        itr != source_state_map_.end(); ++itr) {
1469     itr->second->UnmarkEndOfStream();
1470   }
1471 }
1472
1473 void ChunkDemuxer::Shutdown() {
1474   DVLOG(1) << "Shutdown()";
1475   base::AutoLock auto_lock(lock_);
1476
1477   if (state_ == SHUTDOWN)
1478     return;
1479
1480   ShutdownAllStreams();
1481
1482   ChangeState_Locked(SHUTDOWN);
1483
1484   if(!seek_cb_.is_null())
1485     base::ResetAndReturn(&seek_cb_).Run(PIPELINE_ERROR_ABORT);
1486 }
1487
1488 void ChunkDemuxer::SetMemoryLimitsForTesting(int memory_limit) {
1489   for (SourceStateMap::iterator itr = source_state_map_.begin();
1490        itr != source_state_map_.end(); ++itr) {
1491     itr->second->SetMemoryLimitsForTesting(memory_limit);
1492   }
1493 }
1494
1495 void ChunkDemuxer::ChangeState_Locked(State new_state) {
1496   lock_.AssertAcquired();
1497   DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : "
1498            << state_ << " -> " << new_state;
1499   state_ = new_state;
1500 }
1501
1502 ChunkDemuxer::~ChunkDemuxer() {
1503   DCHECK_NE(state_, INITIALIZED);
1504
1505   STLDeleteValues(&source_state_map_);
1506 }
1507
1508 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) {
1509   DVLOG(1) << "ReportError_Locked(" << error << ")";
1510   lock_.AssertAcquired();
1511   DCHECK_NE(error, PIPELINE_OK);
1512
1513   ChangeState_Locked(PARSE_ERROR);
1514
1515   PipelineStatusCB cb;
1516
1517   if (!init_cb_.is_null()) {
1518     std::swap(cb, init_cb_);
1519   } else {
1520     if (!seek_cb_.is_null())
1521       std::swap(cb, seek_cb_);
1522
1523     ShutdownAllStreams();
1524   }
1525
1526   if (!cb.is_null()) {
1527     cb.Run(error);
1528     return;
1529   }
1530
1531   base::AutoUnlock auto_unlock(lock_);
1532   host_->OnDemuxerError(error);
1533 }
1534
1535 bool ChunkDemuxer::IsSeekWaitingForData_Locked() const {
1536   lock_.AssertAcquired();
1537   for (SourceStateMap::const_iterator itr = source_state_map_.begin();
1538        itr != source_state_map_.end(); ++itr) {
1539     if (itr->second->IsSeekWaitingForData())
1540       return true;
1541   }
1542
1543   return false;
1544 }
1545
1546 void ChunkDemuxer::OnSourceInitDone(
1547     bool success,
1548     const StreamParser::InitParameters& params) {
1549   DVLOG(1) << "OnSourceInitDone(" << success << ", "
1550            << params.duration.InSecondsF() << ")";
1551   lock_.AssertAcquired();
1552   DCHECK_EQ(state_, INITIALIZING);
1553   if (!success || (!audio_ && !video_)) {
1554     ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1555     return;
1556   }
1557
1558   if (params.duration != TimeDelta() && duration_ == kNoTimestamp())
1559     UpdateDuration(params.duration);
1560
1561   if (!params.timeline_offset.is_null()) {
1562     if (!timeline_offset_.is_null() &&
1563         params.timeline_offset != timeline_offset_) {
1564       MEDIA_LOG(log_cb_)
1565           << "Timeline offset is not the same across all SourceBuffers.";
1566       ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1567       return;
1568     }
1569
1570     timeline_offset_ = params.timeline_offset;
1571   }
1572
1573   if (params.liveness != LIVENESS_UNKNOWN) {
1574     if (liveness_ != LIVENESS_UNKNOWN && params.liveness != liveness_) {
1575       MEDIA_LOG(log_cb_)
1576           << "Liveness is not the same across all SourceBuffers.";
1577       ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1578       return;
1579     }
1580
1581     liveness_ = params.liveness;
1582   }
1583
1584   // Wait until all streams have initialized.
1585   if ((!source_id_audio_.empty() && !audio_) ||
1586       (!source_id_video_.empty() && !video_)) {
1587     return;
1588   }
1589
1590   SeekAllSources(GetStartTime());
1591   StartReturningData();
1592
1593   if (duration_ == kNoTimestamp())
1594     duration_ = kInfiniteDuration();
1595
1596   // The demuxer is now initialized after the |start_timestamp_| was set.
1597   ChangeState_Locked(INITIALIZED);
1598   base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
1599 }
1600
1601 ChunkDemuxerStream*
1602 ChunkDemuxer::CreateDemuxerStream(DemuxerStream::Type type) {
1603   switch (type) {
1604     case DemuxerStream::AUDIO:
1605       if (audio_)
1606         return NULL;
1607       audio_.reset(
1608           new ChunkDemuxerStream(DemuxerStream::AUDIO, splice_frames_enabled_));
1609       return audio_.get();
1610       break;
1611     case DemuxerStream::VIDEO:
1612       if (video_)
1613         return NULL;
1614       video_.reset(
1615           new ChunkDemuxerStream(DemuxerStream::VIDEO, splice_frames_enabled_));
1616       return video_.get();
1617       break;
1618     case DemuxerStream::TEXT: {
1619       return new ChunkDemuxerStream(DemuxerStream::TEXT,
1620                                     splice_frames_enabled_);
1621       break;
1622     }
1623     case DemuxerStream::UNKNOWN:
1624     case DemuxerStream::NUM_TYPES:
1625       NOTREACHED();
1626       return NULL;
1627   }
1628   NOTREACHED();
1629   return NULL;
1630 }
1631
1632 void ChunkDemuxer::OnNewTextTrack(ChunkDemuxerStream* text_stream,
1633                                   const TextTrackConfig& config) {
1634   lock_.AssertAcquired();
1635   DCHECK_NE(state_, SHUTDOWN);
1636   host_->AddTextStream(text_stream, config);
1637 }
1638
1639 bool ChunkDemuxer::IsValidId(const std::string& source_id) const {
1640   lock_.AssertAcquired();
1641   return source_state_map_.count(source_id) > 0u;
1642 }
1643
1644 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) {
1645   DCHECK(duration_ != new_duration);
1646   user_specified_duration_ = -1;
1647   duration_ = new_duration;
1648   host_->SetDuration(new_duration);
1649 }
1650
1651 void ChunkDemuxer::IncreaseDurationIfNecessary(TimeDelta new_duration) {
1652   DCHECK(new_duration != kNoTimestamp());
1653   DCHECK(new_duration != kInfiniteDuration());
1654
1655   // Per April 1, 2014 MSE spec editor's draft:
1656   // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/
1657   //     media-source.html#sourcebuffer-coded-frame-processing
1658   // 5. If the media segment contains data beyond the current duration, then run
1659   //    the duration change algorithm with new duration set to the maximum of
1660   //    the current duration and the group end timestamp.
1661
1662   if (new_duration <= duration_)
1663     return;
1664
1665   DVLOG(2) << __FUNCTION__ << ": Increasing duration: "
1666            << duration_.InSecondsF() << " -> " << new_duration.InSecondsF();
1667
1668   UpdateDuration(new_duration);
1669 }
1670
1671 void ChunkDemuxer::DecreaseDurationIfNecessary() {
1672   lock_.AssertAcquired();
1673
1674   TimeDelta max_duration;
1675
1676   for (SourceStateMap::const_iterator itr = source_state_map_.begin();
1677        itr != source_state_map_.end(); ++itr) {
1678     max_duration = std::max(max_duration,
1679                             itr->second->GetMaxBufferedDuration());
1680   }
1681
1682   if (max_duration == TimeDelta())
1683     return;
1684
1685   if (max_duration < duration_)
1686     UpdateDuration(max_duration);
1687 }
1688
1689 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const {
1690   base::AutoLock auto_lock(lock_);
1691   return GetBufferedRanges_Locked();
1692 }
1693
1694 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges_Locked() const {
1695   lock_.AssertAcquired();
1696
1697   bool ended = state_ == ENDED;
1698   // TODO(acolwell): When we start allowing SourceBuffers that are not active,
1699   // we'll need to update this loop to only add ranges from active sources.
1700   RangesList ranges_list;
1701   for (SourceStateMap::const_iterator itr = source_state_map_.begin();
1702        itr != source_state_map_.end(); ++itr) {
1703     ranges_list.push_back(itr->second->GetBufferedRanges(duration_, ended));
1704   }
1705
1706   return ComputeIntersection(ranges_list, ended);
1707 }
1708
1709 void ChunkDemuxer::StartReturningData() {
1710   for (SourceStateMap::iterator itr = source_state_map_.begin();
1711        itr != source_state_map_.end(); ++itr) {
1712     itr->second->StartReturningData();
1713   }
1714 }
1715
1716 void ChunkDemuxer::AbortPendingReads() {
1717   for (SourceStateMap::iterator itr = source_state_map_.begin();
1718        itr != source_state_map_.end(); ++itr) {
1719     itr->second->AbortReads();
1720   }
1721 }
1722
1723 void ChunkDemuxer::SeekAllSources(TimeDelta seek_time) {
1724   for (SourceStateMap::iterator itr = source_state_map_.begin();
1725        itr != source_state_map_.end(); ++itr) {
1726     itr->second->Seek(seek_time);
1727   }
1728 }
1729
1730 void ChunkDemuxer::CompletePendingReadsIfPossible() {
1731   for (SourceStateMap::iterator itr = source_state_map_.begin();
1732        itr != source_state_map_.end(); ++itr) {
1733     itr->second->CompletePendingReadIfPossible();
1734   }
1735 }
1736
1737 void ChunkDemuxer::ShutdownAllStreams() {
1738   for (SourceStateMap::iterator itr = source_state_map_.begin();
1739        itr != source_state_map_.end(); ++itr) {
1740     itr->second->Shutdown();
1741   }
1742 }
1743
1744 }  // namespace media