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