roll skia to 4057
[chromium-blink-merge.git] / media / filters / chunk_demuxer.cc
blob6af153a5e025a070fe61ace1edf875f2ecf84e3e
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 "base/bind.h"
8 #include "base/logging.h"
9 #include "base/message_loop.h"
10 #include "media/base/audio_decoder_config.h"
11 #include "media/base/stream_parser_buffer.h"
12 #include "media/base/video_decoder_config.h"
13 #include "media/filters/chunk_demuxer_client.h"
14 #include "media/webm/webm_stream_parser.h"
16 namespace media {
18 struct CodecInfo {
19 const char* name;
20 DemuxerStream::Type type;
23 typedef StreamParser* (*ParserFactoryFunction)();
25 struct SupportedTypeInfo {
26 const char* type;
27 const ParserFactoryFunction factory_function;
28 const CodecInfo** codecs;
31 static const CodecInfo kVP8CodecInfo = { "vp8", DemuxerStream::VIDEO };
32 static const CodecInfo kVorbisCodecInfo = { "vorbis", DemuxerStream::AUDIO };
34 static const CodecInfo* kVideoWebMCodecs[] = {
35 &kVP8CodecInfo,
36 &kVorbisCodecInfo,
37 NULL
40 static const CodecInfo* kAudioWebMCodecs[] = {
41 &kVorbisCodecInfo,
42 NULL
45 static StreamParser* BuildWebMParser() {
46 return new WebMStreamParser();
49 static const SupportedTypeInfo kSupportedTypeInfo[] = {
50 { "video/webm", &BuildWebMParser, kVideoWebMCodecs },
51 { "audio/webm", &BuildWebMParser, kAudioWebMCodecs },
54 // Checks to see if the specified |type| and |codecs| list are supported.
55 // Returns true if |type| and all codecs listed in |codecs| are supported.
56 // |factory_function| contains a function that can build a StreamParser
57 // for this type.
58 // |has_audio| is true if an audio codec was specified.
59 // |has_video| is true if a video codec was specified.
60 // Returns false otherwise. The values of |factory_function|, |has_audio|,
61 // and |has_video| are undefined.
62 static bool IsSupported(const std::string& type,
63 std::vector<std::string>& codecs,
64 ParserFactoryFunction* factory_function,
65 bool* has_audio,
66 bool* has_video) {
67 *factory_function = NULL;
68 *has_audio = false;
69 *has_video = false;
71 // Search for the SupportedTypeInfo for |type|
72 for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) {
73 const SupportedTypeInfo& type_info = kSupportedTypeInfo[i];
74 if (type == type_info.type) {
75 // Make sure all the codecs specified in |codecs| are
76 // in the supported type info.
77 for (size_t j = 0; j < codecs.size(); ++j) {
78 // Search the type info for a match.
79 bool found_codec = false;
80 DemuxerStream::Type codec_type = DemuxerStream::UNKNOWN;
82 for (int k = 0; type_info.codecs[k]; ++k) {
83 if (codecs[j] == type_info.codecs[k]->name) {
84 found_codec = true;
85 codec_type = type_info.codecs[k]->type;
86 break;
90 if (!found_codec)
91 return false;
93 switch (codec_type) {
94 case DemuxerStream::AUDIO:
95 *has_audio = true;
96 break;
97 case DemuxerStream::VIDEO:
98 *has_video = true;
99 break;
100 default:
101 DVLOG(1) << "Unsupported codec type '"<< codec_type << "' for "
102 << codecs[j];
103 return false;
107 *factory_function = type_info.factory_function;
109 // All codecs were supported by this |type|.
110 return true;
114 // |type| didn't match any of the supported types.
115 return false;
118 class ChunkDemuxerStream : public DemuxerStream {
119 public:
120 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue;
121 typedef std::deque<ReadCB> ReadCBQueue;
122 typedef std::deque<base::Closure> ClosureQueue;
124 explicit ChunkDemuxerStream(const AudioDecoderConfig& audio_config);
125 explicit ChunkDemuxerStream(const VideoDecoderConfig& video_config);
127 void Flush();
128 void Seek(base::TimeDelta time);
130 // Checks if it is ok to add the |buffers| to the stream.
131 bool CanAddBuffers(const BufferQueue& buffers) const;
133 void AddBuffers(const BufferQueue& buffers);
134 void Shutdown();
136 // Gets the time range buffered by this object.
137 // Returns true if there is buffered data. |start_out| & |end_out| are set to
138 // the start and end time of the buffered data respectively.
139 // Returns false if no data is buffered.
140 bool GetBufferedRange(base::TimeDelta* start_out,
141 base::TimeDelta* end_out) const;
143 // DemuxerStream methods.
144 virtual void Read(const ReadCB& read_cb) OVERRIDE;
145 virtual Type type() OVERRIDE;
146 virtual void EnableBitstreamConverter() OVERRIDE;
147 virtual const AudioDecoderConfig& audio_decoder_config() OVERRIDE;
148 virtual const VideoDecoderConfig& video_decoder_config() OVERRIDE;
150 protected:
151 virtual ~ChunkDemuxerStream();
153 private:
154 enum State {
155 RETURNING_DATA_FOR_READS,
156 WAITING_FOR_SEEK,
157 RECEIVED_EOS_WHILE_WAITING_FOR_SEEK, // EOS = End of stream.
158 RECEIVED_EOS,
159 RETURNING_EOS_FOR_READS,
160 SHUTDOWN,
163 // Assigns |state_| to |state|
164 void ChangeState_Locked(State state);
166 // Adds the callback to |read_cbs_| so it can be called later when we
167 // have data.
168 void DeferRead_Locked(const ReadCB& read_cb);
170 // Creates closures that bind ReadCBs in |read_cbs_| to data in
171 // |buffers_| and pops the callbacks & buffers from the respecive queues.
172 void CreateReadDoneClosures_Locked(ClosureQueue* closures);
174 Type type_;
175 AudioDecoderConfig audio_config_;
176 VideoDecoderConfig video_config_;
178 mutable base::Lock lock_;
179 State state_;
180 ReadCBQueue read_cbs_;
181 BufferQueue buffers_;
183 // Keeps track of the timestamp of the last buffer we have
184 // added to |buffers_|. This is used to enforce buffers with strictly
185 // monotonically increasing timestamps.
186 base::TimeDelta last_buffer_timestamp_;
188 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream);
191 ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config)
192 : type_(AUDIO),
193 state_(RETURNING_DATA_FOR_READS),
194 last_buffer_timestamp_(kNoTimestamp()) {
195 audio_config_.CopyFrom(audio_config);
199 ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config)
200 : type_(VIDEO),
201 state_(RETURNING_DATA_FOR_READS),
202 last_buffer_timestamp_(kNoTimestamp()) {
203 video_config_.CopyFrom(video_config);
206 void ChunkDemuxerStream::Flush() {
207 DVLOG(1) << "Flush()";
208 ReadCBQueue read_cbs;
210 base::AutoLock auto_lock(lock_);
211 buffers_.clear();
212 ChangeState_Locked(WAITING_FOR_SEEK);
213 last_buffer_timestamp_ = kNoTimestamp();
215 std::swap(read_cbs_, read_cbs);
218 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it)
219 it->Run(scoped_refptr<Buffer>());
222 void ChunkDemuxerStream::Seek(base::TimeDelta time) {
223 base::AutoLock auto_lock(lock_);
225 DCHECK(read_cbs_.empty());
227 if (state_ == WAITING_FOR_SEEK) {
228 ChangeState_Locked(RETURNING_DATA_FOR_READS);
229 return;
232 if (state_ == RECEIVED_EOS_WHILE_WAITING_FOR_SEEK) {
233 ChangeState_Locked(RECEIVED_EOS);
234 return;
238 bool ChunkDemuxerStream::CanAddBuffers(const BufferQueue& buffers) const {
239 base::AutoLock auto_lock(lock_);
241 // If we haven't seen any buffers yet, then anything can be added.
242 if (last_buffer_timestamp_ == kNoTimestamp())
243 return true;
245 if (buffers.empty())
246 return true;
248 return (buffers.front()->GetTimestamp() > last_buffer_timestamp_);
251 void ChunkDemuxerStream::AddBuffers(const BufferQueue& buffers) {
252 if (buffers.empty())
253 return;
255 ClosureQueue closures;
257 base::AutoLock auto_lock(lock_);
259 for (BufferQueue::const_iterator itr = buffers.begin();
260 itr != buffers.end(); itr++) {
261 // Make sure we aren't trying to add a buffer after we have received and
262 // "end of stream" buffer.
263 DCHECK_NE(state_, RECEIVED_EOS_WHILE_WAITING_FOR_SEEK);
264 DCHECK_NE(state_, RECEIVED_EOS);
265 DCHECK_NE(state_, RETURNING_EOS_FOR_READS);
267 if ((*itr)->IsEndOfStream()) {
268 if (state_ == WAITING_FOR_SEEK) {
269 ChangeState_Locked(RECEIVED_EOS_WHILE_WAITING_FOR_SEEK);
270 } else {
271 ChangeState_Locked(RECEIVED_EOS);
273 } else {
274 base::TimeDelta current_ts = (*itr)->GetTimestamp();
275 if (last_buffer_timestamp_ != kNoTimestamp()) {
276 DCHECK_GT(current_ts.ToInternalValue(),
277 last_buffer_timestamp_.ToInternalValue());
280 last_buffer_timestamp_ = current_ts;
281 buffers_.push_back(*itr);
285 CreateReadDoneClosures_Locked(&closures);
288 for (ClosureQueue::iterator it = closures.begin(); it != closures.end(); ++it)
289 it->Run();
292 void ChunkDemuxerStream::Shutdown() {
293 ReadCBQueue read_cbs;
295 base::AutoLock auto_lock(lock_);
296 ChangeState_Locked(SHUTDOWN);
298 std::swap(read_cbs_, read_cbs);
299 buffers_.clear();
302 // Pass end of stream buffers to all callbacks to signal that no more data
303 // will be sent.
304 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it)
305 it->Run(StreamParserBuffer::CreateEOSBuffer());
308 bool ChunkDemuxerStream::GetBufferedRange(
309 base::TimeDelta* start_out, base::TimeDelta* end_out) const {
310 base::AutoLock auto_lock(lock_);
312 if (buffers_.empty())
313 return false;
315 *start_out = buffers_.front()->GetTimestamp();
316 *end_out = buffers_.back()->GetTimestamp();
318 base::TimeDelta end_duration = buffers_.back()->GetDuration();
319 if (end_duration != kNoTimestamp())
320 *end_out += end_duration;
322 return true;
325 // Helper function that makes sure |read_cb| runs on |message_loop|.
326 static void RunOnMessageLoop(const DemuxerStream::ReadCB& read_cb,
327 MessageLoop* message_loop,
328 const scoped_refptr<Buffer>& buffer) {
329 if (MessageLoop::current() != message_loop) {
330 message_loop->PostTask(FROM_HERE, base::Bind(
331 &RunOnMessageLoop, read_cb, message_loop, buffer));
332 return;
335 read_cb.Run(buffer);
338 // DemuxerStream methods.
339 void ChunkDemuxerStream::Read(const ReadCB& read_cb) {
340 scoped_refptr<Buffer> buffer;
343 base::AutoLock auto_lock(lock_);
345 switch (state_) {
346 case RETURNING_DATA_FOR_READS:
347 // If we don't have any buffers ready or already have
348 // pending reads, then defer this read.
349 if (buffers_.empty() || !read_cbs_.empty()) {
350 DeferRead_Locked(read_cb);
351 return;
354 buffer = buffers_.front();
355 buffers_.pop_front();
356 break;
358 case WAITING_FOR_SEEK:
359 case RECEIVED_EOS_WHILE_WAITING_FOR_SEEK:
360 // Null buffers should be returned in this state since we are waiting
361 // for a seek. Any buffers in |buffers_| should NOT be returned because
362 // they are associated with the seek.
363 DCHECK(read_cbs_.empty());
364 break;
365 case RECEIVED_EOS:
366 DCHECK(read_cbs_.empty());
368 if (buffers_.empty()) {
369 ChangeState_Locked(RETURNING_EOS_FOR_READS);
370 buffer = StreamParserBuffer::CreateEOSBuffer();
371 } else {
372 buffer = buffers_.front();
373 buffers_.pop_front();
375 break;
377 case RETURNING_EOS_FOR_READS:
378 case SHUTDOWN:
379 DCHECK(buffers_.empty());
380 DCHECK(read_cbs_.empty());
381 buffer = StreamParserBuffer::CreateEOSBuffer();
385 read_cb.Run(buffer);
388 DemuxerStream::Type ChunkDemuxerStream::type() { return type_; }
390 void ChunkDemuxerStream::EnableBitstreamConverter() {}
392 const AudioDecoderConfig& ChunkDemuxerStream::audio_decoder_config() {
393 CHECK_EQ(type_, AUDIO);
394 return audio_config_;
397 const VideoDecoderConfig& ChunkDemuxerStream::video_decoder_config() {
398 CHECK_EQ(type_, VIDEO);
399 return video_config_;
402 void ChunkDemuxerStream::ChangeState_Locked(State state) {
403 lock_.AssertAcquired();
404 state_ = state;
407 ChunkDemuxerStream::~ChunkDemuxerStream() {}
409 void ChunkDemuxerStream::DeferRead_Locked(const ReadCB& read_cb) {
410 lock_.AssertAcquired();
411 // Wrap & store |read_cb| so that it will
412 // get called on the current MessageLoop.
413 read_cbs_.push_back(base::Bind(&RunOnMessageLoop, read_cb,
414 MessageLoop::current()));
417 void ChunkDemuxerStream::CreateReadDoneClosures_Locked(ClosureQueue* closures) {
418 lock_.AssertAcquired();
420 if (state_ != RETURNING_DATA_FOR_READS && state_ != RECEIVED_EOS)
421 return;
423 while (!buffers_.empty() && !read_cbs_.empty()) {
424 closures->push_back(base::Bind(read_cbs_.front(), buffers_.front()));
425 buffers_.pop_front();
426 read_cbs_.pop_front();
429 if (state_ != RECEIVED_EOS || !buffers_.empty() || read_cbs_.empty())
430 return;
432 // Push enough EOS buffers to satisfy outstanding Read() requests.
433 scoped_refptr<Buffer> end_of_stream_buffer =
434 StreamParserBuffer::CreateEOSBuffer();
435 while (!read_cbs_.empty()) {
436 closures->push_back(base::Bind(read_cbs_.front(), end_of_stream_buffer));
437 read_cbs_.pop_front();
440 ChangeState_Locked(RETURNING_EOS_FOR_READS);
443 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client)
444 : state_(WAITING_FOR_INIT),
445 host_(NULL),
446 client_(client),
447 buffered_bytes_(0),
448 seek_waits_for_data_(true) {
449 DCHECK(client);
452 void ChunkDemuxer::Initialize(DemuxerHost* host,
453 const PipelineStatusCB& cb) {
454 DVLOG(1) << "Init()";
456 base::AutoLock auto_lock(lock_);
457 DCHECK_EQ(state_, WAITING_FOR_INIT);
458 host_ = host;
460 ChangeState_Locked(INITIALIZING);
461 init_cb_ = cb;
464 client_->DemuxerOpened(this);
467 void ChunkDemuxer::Stop(const base::Closure& callback) {
468 DVLOG(1) << "Stop()";
469 Shutdown();
470 callback.Run();
473 void ChunkDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) {
474 DVLOG(1) << "Seek(" << time.InSecondsF() << ")";
476 PipelineStatus status = PIPELINE_ERROR_INVALID_STATE;
478 base::AutoLock auto_lock(lock_);
480 if (state_ == INITIALIZED || state_ == ENDED) {
481 if (audio_)
482 audio_->Seek(time);
484 if (video_)
485 video_->Seek(time);
487 if (seek_waits_for_data_) {
488 DVLOG(1) << "Seek() : waiting for more data to arrive.";
489 seek_cb_ = cb;
490 return;
493 status = PIPELINE_OK;
497 cb.Run(status);
500 void ChunkDemuxer::OnAudioRendererDisabled() {
501 base::AutoLock auto_lock(lock_);
502 audio_ = NULL;
505 int ChunkDemuxer::GetBitrate() {
506 // TODO(acolwell): Implement bitrate reporting.
507 return 0;
510 // Demuxer implementation.
511 scoped_refptr<DemuxerStream> ChunkDemuxer::GetStream(
512 DemuxerStream::Type type) {
513 if (type == DemuxerStream::VIDEO)
514 return video_;
516 if (type == DemuxerStream::AUDIO)
517 return audio_;
519 return NULL;
522 base::TimeDelta ChunkDemuxer::GetStartTime() const {
523 DVLOG(1) << "GetStartTime()";
524 // TODO(acolwell) : Fix this so it uses the time on the first packet.
525 return base::TimeDelta();
528 void ChunkDemuxer::FlushData() {
529 DVLOG(1) << "FlushData()";
530 base::AutoLock auto_lock(lock_);
531 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN);
533 if (state_ == SHUTDOWN)
534 return;
536 if (audio_.get())
537 audio_->Flush();
539 if (video_.get())
540 video_->Flush();
542 source_buffer_->Flush();
544 seek_waits_for_data_ = true;
545 ChangeState_Locked(INITIALIZED);
548 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id,
549 const std::string& type,
550 std::vector<std::string>& codecs) {
551 DCHECK_GT(codecs.size(), 0u);
553 bool has_audio = false;
554 bool has_video = false;
555 ParserFactoryFunction factory_function = NULL;
556 if (!IsSupported(type, codecs, &factory_function, &has_audio, &has_video))
557 return kNotSupported;
559 // TODO(acolwell): Support for more than one ID
560 // will be added as part of http://crbug.com/122909
561 if (!source_id_.empty())
562 return kReachedIdLimit;
564 source_id_ = id;
566 StreamParser::NewBuffersCB audio_cb;
567 StreamParser::NewBuffersCB video_cb;
569 if (has_audio) {
570 audio_cb = base::Bind(&ChunkDemuxer::OnAudioBuffers,
571 base::Unretained(this));
574 if (has_video) {
575 video_cb = base::Bind(&ChunkDemuxer::OnVideoBuffers,
576 base::Unretained(this));
579 scoped_ptr<StreamParser> stream_parser(factory_function());
581 CHECK(stream_parser.get());
583 source_buffer_.reset(new SourceBuffer());
584 source_buffer_->Init(
585 stream_parser.Pass(),
586 base::Bind(&ChunkDemuxer::OnSourceBufferInitDone, this),
587 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this)),
588 audio_cb,
589 video_cb,
590 base::Bind(&ChunkDemuxer::OnKeyNeeded, base::Unretained(this)));
592 return kOk;
595 void ChunkDemuxer::RemoveId(const std::string& id) {
596 CHECK(!source_id_.empty());
597 CHECK_EQ(source_id_, id);
598 source_id_ = "";
601 bool ChunkDemuxer::GetBufferedRanges(const std::string& id,
602 Ranges* ranges_out) const {
603 DCHECK(!id.empty());
604 DCHECK_EQ(source_id_, id);
605 DCHECK(ranges_out);
607 base::AutoLock auto_lock(lock_);
608 base::TimeDelta start = kNoTimestamp();
609 base::TimeDelta end;
610 base::TimeDelta tmp_start;
611 base::TimeDelta tmp_end;
613 if (audio_ && audio_->GetBufferedRange(&tmp_start, &tmp_end)) {
614 start = tmp_start;
615 end = tmp_end;
618 if (video_ && video_->GetBufferedRange(&tmp_start, &tmp_end)) {
619 if (start == kNoTimestamp()) {
620 start = tmp_start;
621 end = tmp_end;
622 } else {
623 start = std::min(start, tmp_start);
624 end = std::max(end, tmp_end);
628 if (start == kNoTimestamp())
629 return false;
631 ranges_out->resize(1);
632 (*ranges_out)[0].first = start;
633 (*ranges_out)[0].second = end;
634 return true;
637 bool ChunkDemuxer::AppendData(const std::string& id,
638 const uint8* data,
639 size_t length) {
640 DVLOG(1) << "AppendData(" << id << ", " << length << ")";
642 // TODO(acolwell): Remove when http://webk.it/83788 fix lands.
643 if (source_id_.empty()) {
644 std::vector<std::string> codecs(2);
645 codecs[0] = "vp8";
646 codecs[1] = "vorbis";
647 AddId(id, "video/webm", codecs);
650 DCHECK(!source_id_.empty());
651 DCHECK_EQ(source_id_, id);
652 DCHECK(!id.empty());
653 DCHECK(data);
654 DCHECK_GT(length, 0u);
656 int64 buffered_bytes = 0;
658 PipelineStatusCB cb;
660 base::AutoLock auto_lock(lock_);
662 // Capture |seek_waits_for_data_| state before we start parsing.
663 // Its state can be changed by OnAudioBuffers() or OnVideoBuffers()
664 // calls during the parse.
665 bool old_seek_waits_for_data = seek_waits_for_data_;
667 switch (state_) {
668 case INITIALIZING:
669 if (!source_buffer_->AppendData(data, length)) {
670 DCHECK_EQ(state_, INITIALIZING);
671 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
672 return true;
674 break;
676 case INITIALIZED: {
677 if (!source_buffer_->AppendData(data, length)) {
678 ReportError_Locked(PIPELINE_ERROR_DECODE);
679 return true;
681 } break;
683 case WAITING_FOR_INIT:
684 case ENDED:
685 case PARSE_ERROR:
686 case SHUTDOWN:
687 DVLOG(1) << "AppendData(): called in unexpected state " << state_;
688 return false;
691 // Check to see if parsing triggered seek_waits_for_data_ to go from true to
692 // false. This indicates we have parsed enough data to complete the seek.
693 if (old_seek_waits_for_data && !seek_waits_for_data_ &&
694 !seek_cb_.is_null()) {
695 std::swap(cb, seek_cb_);
698 buffered_bytes_ += length;
699 buffered_bytes = buffered_bytes_;
702 // Notify the host of 'network activity' because we got data.
703 host_->SetBufferedBytes(buffered_bytes);
705 host_->SetNetworkActivity(true);
707 if (!cb.is_null())
708 cb.Run(PIPELINE_OK);
710 return true;
713 void ChunkDemuxer::Abort(const std::string& id) {
714 DCHECK(!id.empty());
715 DCHECK_EQ(source_id_, id);
717 source_buffer_->Flush();
720 void ChunkDemuxer::EndOfStream(PipelineStatus status) {
721 DVLOG(1) << "EndOfStream(" << status << ")";
722 base::AutoLock auto_lock(lock_);
723 DCHECK_NE(state_, WAITING_FOR_INIT);
724 DCHECK_NE(state_, ENDED);
726 if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
727 return;
729 if (state_ == INITIALIZING) {
730 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
731 return;
734 ChangeState_Locked(ENDED);
736 if (status != PIPELINE_OK) {
737 ReportError_Locked(status);
738 return;
741 // Create an end of stream buffer.
742 ChunkDemuxerStream::BufferQueue buffers;
743 buffers.push_back(StreamParserBuffer::CreateEOSBuffer());
745 if (audio_.get())
746 audio_->AddBuffers(buffers);
748 if (video_.get())
749 video_->AddBuffers(buffers);
752 bool ChunkDemuxer::HasEnded() {
753 base::AutoLock auto_lock(lock_);
754 return (state_ == ENDED);
757 void ChunkDemuxer::Shutdown() {
758 DVLOG(1) << "Shutdown()";
759 PipelineStatusCB cb;
761 base::AutoLock auto_lock(lock_);
763 if (state_ == SHUTDOWN)
764 return;
766 std::swap(cb, seek_cb_);
768 if (audio_.get())
769 audio_->Shutdown();
771 if (video_.get())
772 video_->Shutdown();
774 source_buffer_.reset();
776 ChangeState_Locked(SHUTDOWN);
779 if (!cb.is_null())
780 cb.Run(PIPELINE_ERROR_ABORT);
782 client_->DemuxerClosed();
785 void ChunkDemuxer::ChangeState_Locked(State new_state) {
786 lock_.AssertAcquired();
787 state_ = new_state;
790 ChunkDemuxer::~ChunkDemuxer() {
791 DCHECK_NE(state_, INITIALIZED);
794 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) {
795 lock_.AssertAcquired();
796 DCHECK_NE(error, PIPELINE_OK);
798 ChangeState_Locked(PARSE_ERROR);
800 PipelineStatusCB cb;
802 if (!init_cb_.is_null()) {
803 std::swap(cb, init_cb_);
804 } else {
805 if (!seek_cb_.is_null())
806 std::swap(cb, seek_cb_);
808 if (audio_.get())
809 audio_->Shutdown();
811 if (video_.get())
812 video_->Shutdown();
815 if (!cb.is_null()) {
816 base::AutoUnlock auto_unlock(lock_);
817 cb.Run(error);
818 return;
821 base::AutoUnlock auto_unlock(lock_);
822 host_->OnDemuxerError(error);
825 void ChunkDemuxer::OnSourceBufferInitDone(bool success,
826 base::TimeDelta duration) {
827 lock_.AssertAcquired();
828 DCHECK_EQ(state_, INITIALIZING);
829 if (!success || (!audio_.get() && !video_.get())) {
830 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
831 return;
834 duration_ = duration;
835 host_->SetDuration(duration_);
836 host_->SetCurrentReadPosition(0);
838 ChangeState_Locked(INITIALIZED);
839 PipelineStatusCB cb;
840 std::swap(cb, init_cb_);
841 cb.Run(PIPELINE_OK);
844 bool ChunkDemuxer::OnNewConfigs(const AudioDecoderConfig& audio_config,
845 const VideoDecoderConfig& video_config) {
846 CHECK(audio_config.IsValidConfig() || video_config.IsValidConfig());
847 lock_.AssertAcquired();
849 // Only allow a single audio config for now.
850 if (audio_config.IsValidConfig()) {
851 if (audio_.get())
852 return false;
854 audio_ = new ChunkDemuxerStream(audio_config);
857 // Only allow a single video config for now.
858 if (video_config.IsValidConfig()) {
859 if (video_.get())
860 return false;
862 video_ = new ChunkDemuxerStream(video_config);
865 return true;
868 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) {
869 if (!audio_.get())
870 return false;
872 if (!audio_->CanAddBuffers(buffers))
873 return false;
875 audio_->AddBuffers(buffers);
876 seek_waits_for_data_ = false;
878 return true;
881 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) {
882 if (!video_.get())
883 return false;
885 if (!video_->CanAddBuffers(buffers))
886 return false;
888 video_->AddBuffers(buffers);
889 seek_waits_for_data_ = false;
891 return true;
894 bool ChunkDemuxer::OnKeyNeeded(scoped_array<uint8> init_data,
895 int init_data_size) {
896 client_->KeyNeeded(init_data.Pass(), init_data_size);
897 return true;
900 } // namespace media