Fix some potential after free errors on TestCompletionCallback
[chromium-blink-merge.git] / media / filters / chunk_demuxer.cc
blobba27e1258a11581a67fc021fef0353ee45b99a04
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.
5 #include "media/filters/chunk_demuxer.h"
7 #include <algorithm>
8 #include <deque>
9 #include <limits>
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"
22 using base::TimeDelta;
24 namespace media {
26 // Contains state belonging to a source id.
27 class SourceState {
28 public:
29 explicit SourceState(scoped_ptr<StreamParser> stream_parser);
31 void Init(const StreamParser::InitCB& init_cb,
32 const StreamParser::NewConfigCB& config_cb,
33 const StreamParser::NewBuffersCB& audio_cb,
34 const StreamParser::NewBuffersCB& video_cb,
35 const StreamParser::NewTextBuffersCB& text_cb,
36 const StreamParser::NeedKeyCB& need_key_cb,
37 const AddTextTrackCB& add_text_track_cb,
38 const StreamParser::NewMediaSegmentCB& new_segment_cb,
39 const LogCB& log_cb);
41 // Appends new data to the StreamParser.
42 // Returns true if the data was successfully appended. Returns false if an
43 // error occurred.
44 bool Append(const uint8* data, size_t length);
46 // Aborts the current append sequence and resets the parser.
47 void Abort();
49 // Sets |timestamp_offset_| if possible.
50 // Returns if the offset was set. Returns false if the offset could not be
51 // updated at this time.
52 bool SetTimestampOffset(TimeDelta timestamp_offset);
54 TimeDelta timestamp_offset() const { return timestamp_offset_; }
56 private:
57 // Called by the |stream_parser_| at the beginning of a new media segment.
58 // |timestamp| is the timestamp on the first buffer in the segment.
59 // It modifies the state of this object and then calls |new_segment_cb| with
60 // modified version of |timestamp|.
61 void OnNewMediaSegment(const StreamParser::NewMediaSegmentCB& new_segment_cb,
62 TimeDelta timestamp);
64 // Called by the |stream_parser_| at the end of a media segment.
65 void OnEndOfMediaSegment();
67 // Called by the |stream_parser_| when new buffers have been parsed. It
68 // applies |timestamp_offset_| to all buffers in |buffers| and then calls
69 // |new_buffers_cb| with the modified buffers.
70 // Returns true on a successful call. Returns false if an error occured while
71 // processing the buffers.
72 bool OnBuffers(const StreamParser::NewBuffersCB& new_buffers_cb,
73 const StreamParser::BufferQueue& buffers);
75 // Called by the |stream_parser_| when new text buffers have been parsed. It
76 // applies |timestamp_offset_| to all buffers in |buffers| and then calls
77 // |new_buffers_cb| with the modified buffers.
78 // Returns true on a successful call. Returns false if an error occured while
79 // processing the buffers.
80 bool OnTextBuffers(const StreamParser::NewTextBuffersCB& new_buffers_cb,
81 TextTrack* text_track,
82 const StreamParser::BufferQueue& buffers);
84 // Helper function that adds |timestamp_offset_| to each buffer in |buffers|.
85 void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers);
87 // The offset to apply to media segment timestamps.
88 TimeDelta timestamp_offset_;
90 // Keeps track of whether |timestamp_offset_| can be modified.
91 bool can_update_offset_;
93 // The object used to parse appended data.
94 scoped_ptr<StreamParser> stream_parser_;
96 DISALLOW_COPY_AND_ASSIGN(SourceState);
99 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser)
100 : can_update_offset_(true),
101 stream_parser_(stream_parser.release()) {
104 void SourceState::Init(const StreamParser::InitCB& init_cb,
105 const StreamParser::NewConfigCB& config_cb,
106 const StreamParser::NewBuffersCB& audio_cb,
107 const StreamParser::NewBuffersCB& video_cb,
108 const StreamParser::NewTextBuffersCB& text_cb,
109 const StreamParser::NeedKeyCB& need_key_cb,
110 const AddTextTrackCB& add_text_track_cb,
111 const StreamParser::NewMediaSegmentCB& new_segment_cb,
112 const LogCB& log_cb) {
113 stream_parser_->Init(init_cb, config_cb,
114 base::Bind(&SourceState::OnBuffers,
115 base::Unretained(this), audio_cb),
116 base::Bind(&SourceState::OnBuffers,
117 base::Unretained(this), video_cb),
118 base::Bind(&SourceState::OnTextBuffers,
119 base::Unretained(this), text_cb),
120 need_key_cb,
121 add_text_track_cb,
122 base::Bind(&SourceState::OnNewMediaSegment,
123 base::Unretained(this), new_segment_cb),
124 base::Bind(&SourceState::OnEndOfMediaSegment,
125 base::Unretained(this)),
126 log_cb);
129 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) {
130 if (!can_update_offset_)
131 return false;
133 timestamp_offset_ = timestamp_offset;
134 return true;
137 bool SourceState::Append(const uint8* data, size_t length) {
138 return stream_parser_->Parse(data, length);
141 void SourceState::Abort() {
142 stream_parser_->Flush();
143 can_update_offset_ = true;
146 void SourceState::AdjustBufferTimestamps(
147 const StreamParser::BufferQueue& buffers) {
148 if (timestamp_offset_ == TimeDelta())
149 return;
151 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin();
152 itr != buffers.end(); ++itr) {
153 (*itr)->SetDecodeTimestamp(
154 (*itr)->GetDecodeTimestamp() + timestamp_offset_);
155 (*itr)->SetTimestamp((*itr)->GetTimestamp() + timestamp_offset_);
159 void SourceState::OnNewMediaSegment(
160 const StreamParser::NewMediaSegmentCB& new_segment_cb,
161 TimeDelta timestamp) {
162 DCHECK(timestamp != kNoTimestamp());
163 DVLOG(2) << "OnNewMediaSegment(" << timestamp.InSecondsF() << ")";
165 can_update_offset_ = false;
166 new_segment_cb.Run(timestamp + timestamp_offset_);
169 void SourceState::OnEndOfMediaSegment() {
170 DVLOG(2) << "OnEndOfMediaSegment()";
171 can_update_offset_ = true;
174 bool SourceState::OnBuffers(const StreamParser::NewBuffersCB& new_buffers_cb,
175 const StreamParser::BufferQueue& buffers) {
176 if (new_buffers_cb.is_null())
177 return false;
179 AdjustBufferTimestamps(buffers);
181 return new_buffers_cb.Run(buffers);
184 bool SourceState::OnTextBuffers(
185 const StreamParser::NewTextBuffersCB& new_buffers_cb,
186 TextTrack* text_track,
187 const StreamParser::BufferQueue& buffers) {
188 if (new_buffers_cb.is_null())
189 return false;
191 AdjustBufferTimestamps(buffers);
193 return new_buffers_cb.Run(text_track, buffers);
196 class ChunkDemuxerStream : public DemuxerStream {
197 public:
198 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue;
199 typedef std::deque<ReadCB> ReadCBQueue;
200 typedef std::deque<base::Closure> ClosureQueue;
202 ChunkDemuxerStream(const AudioDecoderConfig& audio_config,
203 const LogCB& log_cb);
204 ChunkDemuxerStream(const VideoDecoderConfig& video_config,
205 const LogCB& log_cb);
206 virtual ~ChunkDemuxerStream();
208 void AbortReadsAndSeekStream(TimeDelta seek_time);
209 void Seek(TimeDelta time);
210 bool IsSeekWaitingForData() const;
212 // Add buffers to this stream. Buffers are stored in SourceBufferStreams,
213 // which handle ordering and overlap resolution.
214 // Returns true if buffers were successfully added.
215 bool Append(const StreamParser::BufferQueue& buffers);
217 // Signal to the stream that duration has changed to |duration|.
218 void OnSetDuration(TimeDelta duration);
220 // Returns the range of buffered data in this stream, capped at |duration|.
221 Ranges<TimeDelta> GetBufferedRanges(TimeDelta duration) const;
223 // Signal to the stream that buffers handed in through subsequent calls to
224 // Append() belong to a media segment that starts at |start_timestamp|.
225 void OnNewMediaSegment(TimeDelta start_timestamp);
227 // Called when midstream config updates occur.
228 // Returns true if the new config is accepted.
229 // Returns false if the new config should trigger an error.
230 bool UpdateAudioConfig(const AudioDecoderConfig& config);
231 bool UpdateVideoConfig(const VideoDecoderConfig& config);
233 void EndOfStream();
234 void CancelEndOfStream();
236 void Shutdown();
238 // DemuxerStream methods.
239 virtual void Read(const ReadCB& read_cb) OVERRIDE;
240 virtual Type type() OVERRIDE;
241 virtual void EnableBitstreamConverter() OVERRIDE;
242 virtual AudioDecoderConfig audio_decoder_config() OVERRIDE;
243 virtual VideoDecoderConfig video_decoder_config() OVERRIDE;
245 void set_memory_limit_for_testing(int memory_limit) {
246 stream_->set_memory_limit_for_testing(memory_limit);
249 private:
250 enum State {
251 UNINITIALIZED,
252 RETURNING_DATA_FOR_READS,
253 RETURNING_ABORT_FOR_READS,
254 SHUTDOWN,
257 // Assigns |state_| to |state|
258 void ChangeState_Locked(State state);
260 // Adds the callback to |read_cbs_| so it can be called later when we
261 // have data.
262 void DeferRead_Locked(const ReadCB& read_cb);
264 // Creates closures that bind ReadCBs in |read_cbs_| to data in
265 // |buffers_| and pops the callbacks & buffers from the respective queues.
266 void CreateReadDoneClosures_Locked(ClosureQueue* closures);
268 // Gets the value to pass to the next Read() callback. Returns true if
269 // |status| and |buffer| should be passed to the callback. False indicates
270 // that |status| and |buffer| were not set and more data is needed.
271 bool GetNextBuffer_Locked(DemuxerStream::Status* status,
272 scoped_refptr<StreamParserBuffer>* buffer);
274 // Specifies the type of the stream (must be AUDIO or VIDEO for now).
275 Type type_;
277 scoped_ptr<SourceBufferStream> stream_;
279 mutable base::Lock lock_;
280 State state_;
281 ReadCBQueue read_cbs_;
283 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream);
286 ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config,
287 const LogCB& log_cb)
288 : type_(AUDIO),
289 state_(UNINITIALIZED) {
290 stream_.reset(new SourceBufferStream(audio_config, log_cb));
293 ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config,
294 const LogCB& log_cb)
295 : type_(VIDEO),
296 state_(UNINITIALIZED) {
297 stream_.reset(new SourceBufferStream(video_config, log_cb));
300 void ChunkDemuxerStream::AbortReadsAndSeekStream(TimeDelta seek_time) {
301 DVLOG(1) << "ChunkDemuxerStream::AbortReads()";
302 ReadCBQueue read_cbs;
304 base::AutoLock auto_lock(lock_);
305 ChangeState_Locked(RETURNING_ABORT_FOR_READS);
306 stream_->Seek(seek_time);
307 std::swap(read_cbs_, read_cbs);
310 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it)
311 it->Run(kAborted, NULL);
314 void ChunkDemuxerStream::Seek(TimeDelta time) {
315 base::AutoLock auto_lock(lock_);
316 DCHECK(read_cbs_.empty());
317 DCHECK(state_ == UNINITIALIZED || state_ == RETURNING_ABORT_FOR_READS);
319 stream_->Seek(time);
320 ChangeState_Locked(RETURNING_DATA_FOR_READS);
323 bool ChunkDemuxerStream::IsSeekWaitingForData() const {
324 base::AutoLock auto_lock(lock_);
325 return stream_->IsSeekPending();
328 void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) {
329 base::AutoLock auto_lock(lock_);
330 stream_->OnNewMediaSegment(start_timestamp);
333 bool ChunkDemuxerStream::Append(const StreamParser::BufferQueue& buffers) {
334 if (buffers.empty())
335 return false;
337 ClosureQueue closures;
339 base::AutoLock auto_lock(lock_);
340 DCHECK_NE(state_, SHUTDOWN);
341 if (!stream_->Append(buffers)) {
342 DVLOG(1) << "ChunkDemuxerStream::Append() : stream append failed";
343 return false;
345 CreateReadDoneClosures_Locked(&closures);
348 for (ClosureQueue::iterator it = closures.begin(); it != closures.end(); ++it)
349 it->Run();
351 return true;
354 void ChunkDemuxerStream::OnSetDuration(TimeDelta duration) {
355 base::AutoLock auto_lock(lock_);
356 stream_->OnSetDuration(duration);
359 Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedRanges(
360 TimeDelta duration) const {
361 base::AutoLock auto_lock(lock_);
362 Ranges<TimeDelta> range = stream_->GetBufferedTime();
364 if (range.size() == 0u)
365 return range;
367 // Clamp the end of the stream's buffered ranges to fit within the duration.
368 // This can be done by intersecting the stream's range with the valid time
369 // range.
370 Ranges<TimeDelta> valid_time_range;
371 valid_time_range.Add(range.start(0), duration);
372 return range.IntersectionWith(valid_time_range);
375 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config) {
376 DCHECK(config.IsValidConfig());
377 DCHECK_EQ(type_, AUDIO);
378 base::AutoLock auto_lock(lock_);
379 return stream_->UpdateAudioConfig(config);
382 bool ChunkDemuxerStream::UpdateVideoConfig(const VideoDecoderConfig& config) {
383 DCHECK(config.IsValidConfig());
384 DCHECK_EQ(type_, VIDEO);
385 base::AutoLock auto_lock(lock_);
386 return stream_->UpdateVideoConfig(config);
389 void ChunkDemuxerStream::EndOfStream() {
390 ClosureQueue closures;
392 base::AutoLock auto_lock(lock_);
393 stream_->EndOfStream();
394 CreateReadDoneClosures_Locked(&closures);
397 for (ClosureQueue::iterator it = closures.begin(); it != closures.end(); ++it)
398 it->Run();
401 void ChunkDemuxerStream::CancelEndOfStream() {
402 base::AutoLock auto_lock(lock_);
403 stream_->CancelEndOfStream();
406 void ChunkDemuxerStream::Shutdown() {
407 ReadCBQueue read_cbs;
409 base::AutoLock auto_lock(lock_);
410 ChangeState_Locked(SHUTDOWN);
411 std::swap(read_cbs_, read_cbs);
414 // Pass end of stream buffers to all callbacks to signal that no more data
415 // will be sent.
416 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it)
417 it->Run(DemuxerStream::kOk, StreamParserBuffer::CreateEOSBuffer());
420 // Helper function that makes sure |read_cb| runs on |message_loop_proxy|.
421 static void RunOnMessageLoop(
422 const DemuxerStream::ReadCB& read_cb,
423 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
424 DemuxerStream::Status status,
425 const scoped_refptr<DecoderBuffer>& buffer) {
426 if (!message_loop_proxy->BelongsToCurrentThread()) {
427 message_loop_proxy->PostTask(FROM_HERE, base::Bind(
428 &RunOnMessageLoop, read_cb, message_loop_proxy, status, buffer));
429 return;
432 read_cb.Run(status, buffer);
435 // DemuxerStream methods.
436 void ChunkDemuxerStream::Read(const ReadCB& read_cb) {
437 base::AutoLock auto_lock(lock_);
438 DCHECK_NE(state_, UNINITIALIZED);
440 DemuxerStream::Status status = kOk;
441 scoped_refptr<StreamParserBuffer> buffer;
443 if (!read_cbs_.empty() || !GetNextBuffer_Locked(&status, &buffer)) {
444 DeferRead_Locked(read_cb);
445 return;
448 base::MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind(
449 read_cb, status, buffer));
452 DemuxerStream::Type ChunkDemuxerStream::type() { return type_; }
454 void ChunkDemuxerStream::EnableBitstreamConverter() {}
456 AudioDecoderConfig ChunkDemuxerStream::audio_decoder_config() {
457 CHECK_EQ(type_, AUDIO);
458 base::AutoLock auto_lock(lock_);
459 return stream_->GetCurrentAudioDecoderConfig();
462 VideoDecoderConfig ChunkDemuxerStream::video_decoder_config() {
463 CHECK_EQ(type_, VIDEO);
464 base::AutoLock auto_lock(lock_);
465 return stream_->GetCurrentVideoDecoderConfig();
468 void ChunkDemuxerStream::ChangeState_Locked(State state) {
469 lock_.AssertAcquired();
470 DVLOG(1) << "ChunkDemuxerStream::ChangeState_Locked() : "
471 << "type " << type_
472 << " - " << state_ << " -> " << state;
473 state_ = state;
476 ChunkDemuxerStream::~ChunkDemuxerStream() {}
478 void ChunkDemuxerStream::DeferRead_Locked(const ReadCB& read_cb) {
479 lock_.AssertAcquired();
480 // Wrap & store |read_cb| so that it will
481 // get called on the current MessageLoop.
482 read_cbs_.push_back(base::Bind(&RunOnMessageLoop, read_cb,
483 base::MessageLoopProxy::current()));
486 void ChunkDemuxerStream::CreateReadDoneClosures_Locked(ClosureQueue* closures) {
487 lock_.AssertAcquired();
489 if (state_ != RETURNING_DATA_FOR_READS)
490 return;
492 DemuxerStream::Status status;
493 scoped_refptr<StreamParserBuffer> buffer;
494 while (!read_cbs_.empty()) {
495 if (!GetNextBuffer_Locked(&status, &buffer))
496 return;
497 closures->push_back(base::Bind(read_cbs_.front(),
498 status, buffer));
499 read_cbs_.pop_front();
503 bool ChunkDemuxerStream::GetNextBuffer_Locked(
504 DemuxerStream::Status* status,
505 scoped_refptr<StreamParserBuffer>* buffer) {
506 lock_.AssertAcquired();
508 switch (state_) {
509 case UNINITIALIZED:
510 NOTREACHED();
511 return false;
512 case RETURNING_DATA_FOR_READS:
513 switch (stream_->GetNextBuffer(buffer)) {
514 case SourceBufferStream::kSuccess:
515 *status = DemuxerStream::kOk;
516 return true;
517 case SourceBufferStream::kNeedBuffer:
518 return false;
519 case SourceBufferStream::kEndOfStream:
520 *status = DemuxerStream::kOk;
521 *buffer = StreamParserBuffer::CreateEOSBuffer();
522 return true;
523 case SourceBufferStream::kConfigChange:
524 DVLOG(2) << "Config change reported to ChunkDemuxerStream.";
525 *status = kConfigChanged;
526 *buffer = NULL;
527 return true;
529 break;
530 case RETURNING_ABORT_FOR_READS:
531 // Null buffers should be returned in this state since we are waiting
532 // for a seek. Any buffers in the SourceBuffer should NOT be returned
533 // because they are associated with the seek.
534 DCHECK(read_cbs_.empty());
535 *status = DemuxerStream::kAborted;
536 *buffer = NULL;
537 return true;
538 case SHUTDOWN:
539 DCHECK(read_cbs_.empty());
540 *status = DemuxerStream::kOk;
541 *buffer = StreamParserBuffer::CreateEOSBuffer();
542 return true;
545 NOTREACHED();
546 return false;
549 ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb,
550 const NeedKeyCB& need_key_cb,
551 const AddTextTrackCB& add_text_track_cb,
552 const LogCB& log_cb)
553 : state_(WAITING_FOR_INIT),
554 cancel_next_seek_(false),
555 host_(NULL),
556 open_cb_(open_cb),
557 need_key_cb_(need_key_cb),
558 add_text_track_cb_(add_text_track_cb),
559 log_cb_(log_cb),
560 duration_(kNoTimestamp()),
561 user_specified_duration_(-1) {
562 DCHECK(!open_cb_.is_null());
563 DCHECK(!need_key_cb_.is_null());
566 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) {
567 DVLOG(1) << "Init()";
569 base::AutoLock auto_lock(lock_);
571 init_cb_ = BindToCurrentLoop(cb);
572 if (state_ == SHUTDOWN) {
573 base::ResetAndReturn(&init_cb_).Run(DEMUXER_ERROR_COULD_NOT_OPEN);
574 return;
576 DCHECK_EQ(state_, WAITING_FOR_INIT);
577 host_ = host;
579 ChangeState_Locked(INITIALIZING);
581 base::ResetAndReturn(&open_cb_).Run();
584 void ChunkDemuxer::Stop(const base::Closure& callback) {
585 DVLOG(1) << "Stop()";
586 Shutdown();
587 callback.Run();
590 void ChunkDemuxer::Seek(TimeDelta time, const PipelineStatusCB& cb) {
591 DVLOG(1) << "Seek(" << time.InSecondsF() << ")";
592 DCHECK(time >= TimeDelta());
594 base::AutoLock auto_lock(lock_);
595 DCHECK(seek_cb_.is_null());
597 seek_cb_ = BindToCurrentLoop(cb);
598 if (state_ != INITIALIZED && state_ != ENDED) {
599 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_ERROR_INVALID_STATE);
600 return;
603 if (cancel_next_seek_) {
604 cancel_next_seek_ = false;
605 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
606 return;
609 if (audio_)
610 audio_->Seek(time);
612 if (video_)
613 video_->Seek(time);
615 if (IsSeekWaitingForData_Locked()) {
616 DVLOG(1) << "Seek() : waiting for more data to arrive.";
617 return;
620 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
623 void ChunkDemuxer::OnAudioRendererDisabled() {
624 base::AutoLock auto_lock(lock_);
625 audio_->Shutdown();
626 disabled_audio_ = audio_.Pass();
629 // Demuxer implementation.
630 DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) {
631 base::AutoLock auto_lock(lock_);
632 if (type == DemuxerStream::VIDEO)
633 return video_.get();
635 if (type == DemuxerStream::AUDIO)
636 return audio_.get();
638 return NULL;
641 TimeDelta ChunkDemuxer::GetStartTime() const {
642 return TimeDelta();
645 void ChunkDemuxer::StartWaitingForSeek(TimeDelta seek_time) {
646 DVLOG(1) << "StartWaitingForSeek()";
647 base::AutoLock auto_lock(lock_);
648 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN);
649 DCHECK(seek_cb_.is_null());
651 if (state_ == SHUTDOWN)
652 return;
654 if (audio_)
655 audio_->AbortReadsAndSeekStream(seek_time);
657 if (video_)
658 video_->AbortReadsAndSeekStream(seek_time);
660 // Cancel state set in CancelPendingSeek() since we want to
661 // accept the next Seek().
662 cancel_next_seek_ = false;
665 void ChunkDemuxer::CancelPendingSeek(TimeDelta seek_time) {
666 base::AutoLock auto_lock(lock_);
667 DCHECK_NE(state_, INITIALIZING);
668 DCHECK(seek_cb_.is_null() || IsSeekWaitingForData_Locked());
670 if (cancel_next_seek_)
671 return;
673 if (audio_)
674 audio_->AbortReadsAndSeekStream(seek_time);
676 if (video_)
677 video_->AbortReadsAndSeekStream(seek_time);
679 if (seek_cb_.is_null()) {
680 cancel_next_seek_ = true;
681 return;
684 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
687 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id,
688 const std::string& type,
689 std::vector<std::string>& codecs) {
690 DCHECK_GT(codecs.size(), 0u);
691 base::AutoLock auto_lock(lock_);
693 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id))
694 return kReachedIdLimit;
696 bool has_audio = false;
697 bool has_video = false;
698 scoped_ptr<media::StreamParser> stream_parser(
699 StreamParserFactory::Create(type, codecs, log_cb_,
700 &has_audio, &has_video));
702 if (!stream_parser)
703 return ChunkDemuxer::kNotSupported;
705 if ((has_audio && !source_id_audio_.empty()) ||
706 (has_video && !source_id_video_.empty()))
707 return kReachedIdLimit;
709 StreamParser::NewBuffersCB audio_cb;
710 StreamParser::NewBuffersCB video_cb;
712 if (has_audio) {
713 source_id_audio_ = id;
714 audio_cb = base::Bind(&ChunkDemuxer::OnAudioBuffers,
715 base::Unretained(this));
718 if (has_video) {
719 source_id_video_ = id;
720 video_cb = base::Bind(&ChunkDemuxer::OnVideoBuffers,
721 base::Unretained(this));
724 scoped_ptr<SourceState> source_state(new SourceState(stream_parser.Pass()));
725 source_state->Init(
726 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)),
727 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this),
728 has_audio, has_video),
729 audio_cb,
730 video_cb,
731 base::Bind(&ChunkDemuxer::OnTextBuffers, base::Unretained(this)),
732 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)),
733 add_text_track_cb_,
734 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id),
735 log_cb_);
737 source_state_map_[id] = source_state.release();
738 return kOk;
741 void ChunkDemuxer::RemoveId(const std::string& id) {
742 base::AutoLock auto_lock(lock_);
743 CHECK(IsValidId(id));
745 delete source_state_map_[id];
746 source_state_map_.erase(id);
748 if (source_id_audio_ == id) {
749 if (audio_)
750 audio_->Shutdown();
751 source_id_audio_.clear();
754 if (source_id_video_ == id) {
755 if (video_)
756 video_->Shutdown();
757 source_id_video_.clear();
761 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const {
762 base::AutoLock auto_lock(lock_);
763 DCHECK(!id.empty());
764 DCHECK(IsValidId(id));
765 DCHECK(id == source_id_audio_ || id == source_id_video_);
767 if (id == source_id_audio_ && id != source_id_video_) {
768 // Only include ranges that have been buffered in |audio_|
769 return audio_ ? audio_->GetBufferedRanges(duration_) : Ranges<TimeDelta>();
772 if (id != source_id_audio_ && id == source_id_video_) {
773 // Only include ranges that have been buffered in |video_|
774 return video_ ? video_->GetBufferedRanges(duration_) : Ranges<TimeDelta>();
777 return ComputeIntersection();
780 Ranges<TimeDelta> ChunkDemuxer::ComputeIntersection() const {
781 lock_.AssertAcquired();
783 if (!audio_ || !video_)
784 return Ranges<TimeDelta>();
786 // Include ranges that have been buffered in both |audio_| and |video_|.
787 Ranges<TimeDelta> audio_ranges = audio_->GetBufferedRanges(duration_);
788 Ranges<TimeDelta> video_ranges = video_->GetBufferedRanges(duration_);
789 Ranges<TimeDelta> result = audio_ranges.IntersectionWith(video_ranges);
791 if (state_ == ENDED && result.size() > 0) {
792 // If appending has ended, extend the last intersection range to include the
793 // max end time of the last audio/video range. This allows the buffered
794 // information to match the actual time range that will get played out if
795 // the streams have slightly different lengths.
796 TimeDelta audio_start = audio_ranges.start(audio_ranges.size() - 1);
797 TimeDelta audio_end = audio_ranges.end(audio_ranges.size() - 1);
798 TimeDelta video_start = video_ranges.start(video_ranges.size() - 1);
799 TimeDelta video_end = video_ranges.end(video_ranges.size() - 1);
801 // Verify the last audio range overlaps with the last video range.
802 // This is enforced by the logic that controls the transition to ENDED.
803 DCHECK((audio_start <= video_start && video_start <= audio_end) ||
804 (video_start <= audio_start && audio_start <= video_end));
805 result.Add(result.end(result.size()-1), std::max(audio_end, video_end));
808 return result;
811 void ChunkDemuxer::AppendData(const std::string& id,
812 const uint8* data,
813 size_t length) {
814 DVLOG(1) << "AppendData(" << id << ", " << length << ")";
816 DCHECK(!id.empty());
818 Ranges<TimeDelta> ranges;
821 base::AutoLock auto_lock(lock_);
823 // Capture if any of the SourceBuffers are waiting for data before we start
824 // parsing.
825 bool old_waiting_for_data = IsSeekWaitingForData_Locked();
827 if (state_ == ENDED) {
828 ChangeState_Locked(INITIALIZED);
830 if (audio_)
831 audio_->CancelEndOfStream();
833 if (video_)
834 video_->CancelEndOfStream();
837 if (length == 0u)
838 return;
840 DCHECK(data);
842 switch (state_) {
843 case INITIALIZING:
844 DCHECK(IsValidId(id));
845 if (!source_state_map_[id]->Append(data, length)) {
846 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
847 return;
849 break;
851 case INITIALIZED: {
852 DCHECK(IsValidId(id));
853 if (!source_state_map_[id]->Append(data, length)) {
854 ReportError_Locked(PIPELINE_ERROR_DECODE);
855 return;
857 } break;
859 case PARSE_ERROR:
860 DVLOG(1) << "AppendData(): Ignoring data after a parse error.";
861 return;
863 case WAITING_FOR_INIT:
864 case ENDED:
865 case SHUTDOWN:
866 DVLOG(1) << "AppendData(): called in unexpected state " << state_;
867 return;
870 // Check to see if data was appended at the pending seek point. This
871 // indicates we have parsed enough data to complete the seek.
872 if (old_waiting_for_data && !IsSeekWaitingForData_Locked() &&
873 !seek_cb_.is_null()) {
874 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
877 ranges = GetBufferedRanges();
880 for (size_t i = 0; i < ranges.size(); ++i)
881 host_->AddBufferedTimeRange(ranges.start(i), ranges.end(i));
884 void ChunkDemuxer::Abort(const std::string& id) {
885 DVLOG(1) << "Abort(" << id << ")";
886 base::AutoLock auto_lock(lock_);
887 DCHECK(!id.empty());
888 CHECK(IsValidId(id));
889 source_state_map_[id]->Abort();
892 double ChunkDemuxer::GetDuration() {
893 base::AutoLock auto_lock(lock_);
894 return GetDuration_Locked();
897 double ChunkDemuxer::GetDuration_Locked() {
898 lock_.AssertAcquired();
899 if (duration_ == kNoTimestamp())
900 return std::numeric_limits<double>::quiet_NaN();
902 // Return positive infinity if the resource is unbounded.
903 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-media-duration
904 if (duration_ == kInfiniteDuration())
905 return std::numeric_limits<double>::infinity();
907 if (user_specified_duration_ >= 0)
908 return user_specified_duration_;
910 return duration_.InSecondsF();
913 void ChunkDemuxer::SetDuration(double duration) {
914 base::AutoLock auto_lock(lock_);
915 DVLOG(1) << "SetDuration(" << duration << ")";
916 DCHECK_GE(duration, 0);
918 if (duration == GetDuration_Locked())
919 return;
921 // Compute & bounds check the TimeDelta representation of duration.
922 // This can be different if the value of |duration| doesn't fit the range or
923 // precision of TimeDelta.
924 TimeDelta min_duration = TimeDelta::FromInternalValue(1);
925 TimeDelta max_duration = TimeDelta::FromInternalValue(kint64max - 1);
926 double min_duration_in_seconds = min_duration.InSecondsF();
927 double max_duration_in_seconds = max_duration.InSecondsF();
929 TimeDelta duration_td;
930 if (duration == std::numeric_limits<double>::infinity()) {
931 duration_td = media::kInfiniteDuration();
932 } else if (duration < min_duration_in_seconds) {
933 duration_td = min_duration;
934 } else if (duration > max_duration_in_seconds) {
935 duration_td = max_duration;
936 } else {
937 duration_td = TimeDelta::FromMicroseconds(
938 duration * base::Time::kMicrosecondsPerSecond);
941 DCHECK(duration_td > TimeDelta());
943 user_specified_duration_ = duration;
944 duration_ = duration_td;
945 host_->SetDuration(duration_);
947 if (audio_)
948 audio_->OnSetDuration(duration_);
950 if (video_)
951 video_->OnSetDuration(duration_);
954 bool ChunkDemuxer::SetTimestampOffset(const std::string& id, TimeDelta offset) {
955 base::AutoLock auto_lock(lock_);
956 DVLOG(1) << "SetTimestampOffset(" << id << ", " << offset.InSecondsF() << ")";
957 CHECK(IsValidId(id));
959 return source_state_map_[id]->SetTimestampOffset(offset);
962 void ChunkDemuxer::EndOfStream(PipelineStatus status) {
963 DVLOG(1) << "EndOfStream(" << status << ")";
964 base::AutoLock auto_lock(lock_);
965 DCHECK_NE(state_, WAITING_FOR_INIT);
966 DCHECK_NE(state_, ENDED);
968 if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
969 return;
971 if (state_ == INITIALIZING) {
972 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
973 return;
976 bool old_waiting_for_data = IsSeekWaitingForData_Locked();
977 if (audio_)
978 audio_->EndOfStream();
980 if (video_)
981 video_->EndOfStream();
983 // Give a chance to resume the pending seek process.
984 if (status != PIPELINE_OK) {
985 ReportError_Locked(status);
986 return;
989 ChangeState_Locked(ENDED);
990 DecreaseDurationIfNecessary();
992 if (old_waiting_for_data && !IsSeekWaitingForData_Locked() &&
993 !seek_cb_.is_null()) {
994 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
998 void ChunkDemuxer::Shutdown() {
999 DVLOG(1) << "Shutdown()";
1000 base::AutoLock auto_lock(lock_);
1002 if (state_ == SHUTDOWN)
1003 return;
1005 if (audio_)
1006 audio_->Shutdown();
1008 if (video_)
1009 video_->Shutdown();
1011 ChangeState_Locked(SHUTDOWN);
1013 if(!seek_cb_.is_null())
1014 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_ERROR_ABORT);
1017 void ChunkDemuxer::SetMemoryLimitsForTesting(int memory_limit) {
1018 if (audio_)
1019 audio_->set_memory_limit_for_testing(memory_limit);
1021 if (video_)
1022 video_->set_memory_limit_for_testing(memory_limit);
1025 void ChunkDemuxer::ChangeState_Locked(State new_state) {
1026 lock_.AssertAcquired();
1027 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : "
1028 << state_ << " -> " << new_state;
1029 state_ = new_state;
1032 ChunkDemuxer::~ChunkDemuxer() {
1033 DCHECK_NE(state_, INITIALIZED);
1034 for (SourceStateMap::iterator it = source_state_map_.begin();
1035 it != source_state_map_.end(); ++it) {
1036 delete it->second;
1038 source_state_map_.clear();
1041 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) {
1042 DVLOG(1) << "ReportError_Locked(" << error << ")";
1043 lock_.AssertAcquired();
1044 DCHECK_NE(error, PIPELINE_OK);
1046 ChangeState_Locked(PARSE_ERROR);
1048 PipelineStatusCB cb;
1050 if (!init_cb_.is_null()) {
1051 std::swap(cb, init_cb_);
1052 } else {
1053 if (!seek_cb_.is_null())
1054 std::swap(cb, seek_cb_);
1056 if (audio_)
1057 audio_->Shutdown();
1059 if (video_)
1060 video_->Shutdown();
1063 if (!cb.is_null()) {
1064 cb.Run(error);
1065 return;
1068 base::AutoUnlock auto_unlock(lock_);
1069 host_->OnDemuxerError(error);
1072 bool ChunkDemuxer::IsSeekWaitingForData_Locked() const {
1073 lock_.AssertAcquired();
1074 bool waiting_for_data = false;
1076 if (audio_)
1077 waiting_for_data = audio_->IsSeekWaitingForData();
1079 if (!waiting_for_data && video_)
1080 waiting_for_data = video_->IsSeekWaitingForData();
1082 return waiting_for_data;
1085 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) {
1086 DVLOG(1) << "OnSourceInitDone(" << success << ", "
1087 << duration.InSecondsF() << ")";
1088 lock_.AssertAcquired();
1089 DCHECK_EQ(state_, INITIALIZING);
1090 if (!success || (!audio_ && !video_)) {
1091 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1092 return;
1095 if (duration != TimeDelta() && duration_ == kNoTimestamp())
1096 UpdateDuration(duration);
1098 // Wait until all streams have initialized.
1099 if ((!source_id_audio_.empty() && !audio_) ||
1100 (!source_id_video_.empty() && !video_))
1101 return;
1103 TimeDelta start_time = GetStartTime();
1104 if (audio_)
1105 audio_->Seek(start_time);
1107 if (video_)
1108 video_->Seek(start_time);
1110 if (duration_ == kNoTimestamp())
1111 duration_ = kInfiniteDuration();
1113 // The demuxer is now initialized after the |start_timestamp_| was set.
1114 ChangeState_Locked(INITIALIZED);
1115 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
1118 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video,
1119 const AudioDecoderConfig& audio_config,
1120 const VideoDecoderConfig& video_config) {
1121 DVLOG(1) << "OnNewConfigs(" << has_audio << ", " << has_video
1122 << ", " << audio_config.IsValidConfig()
1123 << ", " << video_config.IsValidConfig() << ")";
1124 lock_.AssertAcquired();
1126 if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) {
1127 DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!";
1128 return false;
1131 // Signal an error if we get configuration info for stream types that weren't
1132 // specified in AddId() or more configs after a stream is initialized.
1133 // Only allow a single audio config for now.
1134 if (has_audio != audio_config.IsValidConfig()) {
1135 MEDIA_LOG(log_cb_)
1136 << "Initialization segment"
1137 << (audio_config.IsValidConfig() ? " has" : " does not have")
1138 << " an audio track, but the mimetype"
1139 << (has_audio ? " specifies" : " does not specify")
1140 << " an audio codec.";
1141 return false;
1144 // Only allow a single video config for now.
1145 if (has_video != video_config.IsValidConfig()) {
1146 MEDIA_LOG(log_cb_)
1147 << "Initialization segment"
1148 << (video_config.IsValidConfig() ? " has" : " does not have")
1149 << " a video track, but the mimetype"
1150 << (has_video ? " specifies" : " does not specify")
1151 << " a video codec.";
1152 return false;
1155 bool success = true;
1156 if (audio_config.IsValidConfig()) {
1157 if (audio_) {
1158 success &= audio_->UpdateAudioConfig(audio_config);
1159 } else {
1160 audio_.reset(new ChunkDemuxerStream(audio_config, log_cb_));
1164 if (video_config.IsValidConfig()) {
1165 if (video_) {
1166 success &= video_->UpdateVideoConfig(video_config);
1167 } else {
1168 video_.reset(new ChunkDemuxerStream(video_config, log_cb_));
1172 DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed");
1173 return success;
1176 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) {
1177 lock_.AssertAcquired();
1178 DCHECK_NE(state_, SHUTDOWN);
1180 if (!audio_)
1181 return false;
1183 CHECK(IsValidId(source_id_audio_));
1184 if (!audio_->Append(buffers))
1185 return false;
1187 IncreaseDurationIfNecessary(buffers, audio_.get());
1188 return true;
1191 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) {
1192 lock_.AssertAcquired();
1193 DCHECK_NE(state_, SHUTDOWN);
1195 if (!video_)
1196 return false;
1198 CHECK(IsValidId(source_id_video_));
1199 if (!video_->Append(buffers))
1200 return false;
1202 IncreaseDurationIfNecessary(buffers, video_.get());
1203 return true;
1206 bool ChunkDemuxer::OnTextBuffers(
1207 TextTrack* text_track,
1208 const StreamParser::BufferQueue& buffers) {
1209 lock_.AssertAcquired();
1210 DCHECK_NE(state_, SHUTDOWN);
1212 // TODO(matthewjheaney): IncreaseDurationIfNecessary
1214 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin();
1215 itr != buffers.end(); ++itr) {
1216 const StreamParserBuffer* const buffer = itr->get();
1217 const TimeDelta start = buffer->GetTimestamp();
1218 const TimeDelta end = start + buffer->GetDuration();
1220 std::string id, settings, content;
1222 WebMWebVTTParser::Parse(buffer->GetData(),
1223 buffer->GetDataSize(),
1224 &id, &settings, &content);
1226 text_track->addWebVTTCue(start, end, id, content, settings);
1229 return true;
1232 // TODO(acolwell): Remove bool from StreamParser::NeedKeyCB so that
1233 // this method can be removed and need_key_cb_ can be passed directly
1234 // to the parser.
1235 bool ChunkDemuxer::OnNeedKey(const std::string& type,
1236 scoped_ptr<uint8[]> init_data,
1237 int init_data_size) {
1238 lock_.AssertAcquired();
1239 need_key_cb_.Run(type, init_data.Pass(), init_data_size);
1240 return true;
1243 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id,
1244 TimeDelta timestamp) {
1245 DCHECK(timestamp != kNoTimestamp());
1246 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", "
1247 << timestamp.InSecondsF() << ")";
1248 lock_.AssertAcquired();
1250 CHECK(IsValidId(source_id));
1251 if (audio_ && source_id == source_id_audio_)
1252 audio_->OnNewMediaSegment(timestamp);
1253 if (video_ && source_id == source_id_video_)
1254 video_->OnNewMediaSegment(timestamp);
1257 bool ChunkDemuxer::IsValidId(const std::string& source_id) const {
1258 lock_.AssertAcquired();
1259 return source_state_map_.count(source_id) > 0u;
1262 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) {
1263 DCHECK(duration_ != new_duration);
1264 user_specified_duration_ = -1;
1265 duration_ = new_duration;
1266 host_->SetDuration(new_duration);
1269 void ChunkDemuxer::IncreaseDurationIfNecessary(
1270 const StreamParser::BufferQueue& buffers,
1271 ChunkDemuxerStream* stream) {
1272 DCHECK(!buffers.empty());
1273 if (buffers.back()->GetTimestamp() <= duration_)
1274 return;
1276 Ranges<TimeDelta> ranges = stream->GetBufferedRanges(kInfiniteDuration());
1277 DCHECK_GT(ranges.size(), 0u);
1279 TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1);
1280 if (last_timestamp_buffered > duration_)
1281 UpdateDuration(last_timestamp_buffered);
1284 void ChunkDemuxer::DecreaseDurationIfNecessary() {
1285 Ranges<TimeDelta> ranges = GetBufferedRanges();
1286 if (ranges.size() == 0u)
1287 return;
1289 TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1);
1290 if (last_timestamp_buffered < duration_)
1291 UpdateDuration(last_timestamp_buffered);
1294 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const {
1295 if (audio_ && !video_)
1296 return audio_->GetBufferedRanges(duration_);
1297 else if (!audio_ && video_)
1298 return video_->GetBufferedRanges(duration_);
1299 return ComputeIntersection();
1302 } // namespace media