Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/filters/chunk_demuxer.h" | 5 #include "media/filters/chunk_demuxer.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <deque> | 8 #include <deque> |
| 9 #include <limits> | 9 #include <limits> |
| 10 | 10 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 43 bool Append(const uint8* data, size_t length); | 43 bool Append(const uint8* data, size_t length); |
| 44 | 44 |
| 45 // Aborts the current append sequence and resets the parser. | 45 // Aborts the current append sequence and resets the parser. |
| 46 void Abort(); | 46 void Abort(); |
| 47 | 47 |
| 48 // Sets |timestamp_offset_| if possible. | 48 // Sets |timestamp_offset_| if possible. |
| 49 // Returns if the offset was set. Returns false if the offset could not be | 49 // Returns if the offset was set. Returns false if the offset could not be |
| 50 // updated at this time. | 50 // updated at this time. |
| 51 bool SetTimestampOffset(TimeDelta timestamp_offset); | 51 bool SetTimestampOffset(TimeDelta timestamp_offset); |
| 52 | 52 |
| 53 TimeDelta timestamp_offset() const { return timestamp_offset_; } | 53 TimeDelta GetTimestampOffset() const { |
|
scherkus (not reviewing)
2013/06/22 00:39:17
whoops -- this is still incorrect
the original co
| |
| 54 return timestamp_offset_; | |
| 55 } | |
| 54 | 56 |
| 55 private: | 57 private: |
| 56 // Called by the |stream_parser_| at the beginning of a new media segment. | 58 // Called by the |stream_parser_| at the beginning of a new media segment. |
| 57 // |timestamp| is the timestamp on the first buffer in the segment. | 59 // |timestamp| is the timestamp on the first buffer in the segment. |
| 58 // It modifies the state of this object and then calls |new_segment_cb| with | 60 // It modifies the state of this object and then calls |new_segment_cb| with |
| 59 // modified version of |timestamp|. | 61 // modified version of |timestamp|. |
| 60 void OnNewMediaSegment(const StreamParser::NewMediaSegmentCB& new_segment_cb, | 62 void OnNewMediaSegment(const StreamParser::NewMediaSegmentCB& new_segment_cb, |
| 61 TimeDelta timestamp); | 63 TimeDelta timestamp); |
| 62 | 64 |
| 63 // Called by the |stream_parser_| at the end of a media segment. | 65 // Called by the |stream_parser_| at the end of a media segment. |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 89 // Keeps track of whether |timestamp_offset_| can be modified. | 91 // Keeps track of whether |timestamp_offset_| can be modified. |
| 90 bool can_update_offset_; | 92 bool can_update_offset_; |
| 91 | 93 |
| 92 // The object used to parse appended data. | 94 // The object used to parse appended data. |
| 93 scoped_ptr<StreamParser> stream_parser_; | 95 scoped_ptr<StreamParser> stream_parser_; |
| 94 | 96 |
| 95 DISALLOW_COPY_AND_ASSIGN(SourceState); | 97 DISALLOW_COPY_AND_ASSIGN(SourceState); |
| 96 }; | 98 }; |
| 97 | 99 |
| 98 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser) | 100 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser) |
| 99 : can_update_offset_(true), | 101 : can_update_offset_(true), stream_parser_(stream_parser.release()) {} |
| 100 stream_parser_(stream_parser.release()) { | |
| 101 } | |
| 102 | 102 |
| 103 void SourceState::Init(const StreamParser::InitCB& init_cb, | 103 void SourceState::Init(const StreamParser::InitCB& init_cb, |
| 104 const StreamParser::NewConfigCB& config_cb, | 104 const StreamParser::NewConfigCB& config_cb, |
| 105 const StreamParser::NewBuffersCB& audio_cb, | 105 const StreamParser::NewBuffersCB& audio_cb, |
| 106 const StreamParser::NewBuffersCB& video_cb, | 106 const StreamParser::NewBuffersCB& video_cb, |
| 107 const StreamParser::NewTextBuffersCB& text_cb, | 107 const StreamParser::NewTextBuffersCB& text_cb, |
| 108 const StreamParser::NeedKeyCB& need_key_cb, | 108 const StreamParser::NeedKeyCB& need_key_cb, |
| 109 const AddTextTrackCB& add_text_track_cb, | 109 const AddTextTrackCB& add_text_track_cb, |
| 110 const StreamParser::NewMediaSegmentCB& new_segment_cb, | 110 const StreamParser::NewMediaSegmentCB& new_segment_cb, |
| 111 const LogCB& log_cb) { | 111 const LogCB& log_cb) { |
| 112 stream_parser_->Init(init_cb, config_cb, | 112 stream_parser_->Init( |
| 113 base::Bind(&SourceState::OnBuffers, | 113 init_cb, |
| 114 base::Unretained(this), audio_cb), | 114 config_cb, |
| 115 base::Bind(&SourceState::OnBuffers, | 115 base::Bind(&SourceState::OnBuffers, base::Unretained(this), audio_cb), |
| 116 base::Unretained(this), video_cb), | 116 base::Bind(&SourceState::OnBuffers, base::Unretained(this), video_cb), |
| 117 base::Bind(&SourceState::OnTextBuffers, | 117 base::Bind(&SourceState::OnTextBuffers, base::Unretained(this), text_cb), |
| 118 base::Unretained(this), text_cb), | 118 need_key_cb, |
| 119 need_key_cb, | 119 add_text_track_cb, |
| 120 add_text_track_cb, | 120 base::Bind(&SourceState::OnNewMediaSegment, |
| 121 base::Bind(&SourceState::OnNewMediaSegment, | 121 base::Unretained(this), |
| 122 base::Unretained(this), new_segment_cb), | 122 new_segment_cb), |
| 123 base::Bind(&SourceState::OnEndOfMediaSegment, | 123 base::Bind(&SourceState::OnEndOfMediaSegment, base::Unretained(this)), |
| 124 base::Unretained(this)), | 124 log_cb); |
| 125 log_cb); | |
| 126 } | 125 } |
| 127 | 126 |
| 128 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) { | 127 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) { |
| 129 if (!can_update_offset_) | 128 if (!can_update_offset_) |
| 130 return false; | 129 return false; |
| 131 | 130 |
| 132 timestamp_offset_ = timestamp_offset; | 131 timestamp_offset_ = timestamp_offset; |
| 133 return true; | 132 return true; |
| 134 } | 133 } |
| 135 | 134 |
| 136 bool SourceState::Append(const uint8* data, size_t length) { | 135 bool SourceState::Append(const uint8* data, size_t length) { |
| 137 return stream_parser_->Parse(data, length); | 136 return stream_parser_->Parse(data, length); |
| 138 } | 137 } |
| 139 | 138 |
| 140 void SourceState::Abort() { | 139 void SourceState::Abort() { |
| 141 stream_parser_->Flush(); | 140 stream_parser_->Flush(); |
| 142 can_update_offset_ = true; | 141 can_update_offset_ = true; |
| 143 } | 142 } |
| 144 | 143 |
| 145 void SourceState::AdjustBufferTimestamps( | 144 void SourceState::AdjustBufferTimestamps( |
| 146 const StreamParser::BufferQueue& buffers) { | 145 const StreamParser::BufferQueue& buffers) { |
| 147 if (timestamp_offset_ == TimeDelta()) | 146 if (timestamp_offset_ == TimeDelta()) |
| 148 return; | 147 return; |
| 149 | 148 |
| 150 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); | 149 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); |
| 151 itr != buffers.end(); ++itr) { | 150 itr != buffers.end(); |
| 152 (*itr)->SetDecodeTimestamp( | 151 ++itr) { |
| 153 (*itr)->GetDecodeTimestamp() + timestamp_offset_); | 152 (*itr) |
| 154 (*itr)->SetTimestamp((*itr)->GetTimestamp() + timestamp_offset_); | 153 ->SetDecodeTimestamp((*itr)->GetDecodeTimestamp() + timestamp_offset_); |
| 154 (*itr)->set_timestamp((*itr)->timestamp() + timestamp_offset_); | |
| 155 } | 155 } |
| 156 } | 156 } |
| 157 | 157 |
| 158 void SourceState::OnNewMediaSegment( | 158 void SourceState::OnNewMediaSegment( |
| 159 const StreamParser::NewMediaSegmentCB& new_segment_cb, | 159 const StreamParser::NewMediaSegmentCB& new_segment_cb, |
| 160 TimeDelta timestamp) { | 160 TimeDelta timestamp) { |
| 161 DCHECK(timestamp != kNoTimestamp()); | 161 DCHECK(timestamp != kNoTimestamp()); |
| 162 DVLOG(2) << "OnNewMediaSegment(" << timestamp.InSecondsF() << ")"; | 162 DVLOG(2) << "OnNewMediaSegment(" << timestamp.InSecondsF() << ")"; |
| 163 | 163 |
| 164 can_update_offset_ = false; | 164 can_update_offset_ = false; |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 274 | 274 |
| 275 mutable base::Lock lock_; | 275 mutable base::Lock lock_; |
| 276 State state_; | 276 State state_; |
| 277 ReadCBQueue read_cbs_; | 277 ReadCBQueue read_cbs_; |
| 278 | 278 |
| 279 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); | 279 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); |
| 280 }; | 280 }; |
| 281 | 281 |
| 282 ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config, | 282 ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config, |
| 283 const LogCB& log_cb) | 283 const LogCB& log_cb) |
| 284 : type_(AUDIO), | 284 : type_(AUDIO), state_(RETURNING_DATA_FOR_READS) { |
| 285 state_(RETURNING_DATA_FOR_READS) { | |
| 286 stream_.reset(new SourceBufferStream(audio_config, log_cb)); | 285 stream_.reset(new SourceBufferStream(audio_config, log_cb)); |
| 287 } | 286 } |
| 288 | 287 |
| 289 ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config, | 288 ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config, |
| 290 const LogCB& log_cb) | 289 const LogCB& log_cb) |
| 291 : type_(VIDEO), | 290 : type_(VIDEO), state_(RETURNING_DATA_FOR_READS) { |
| 292 state_(RETURNING_DATA_FOR_READS) { | |
| 293 stream_.reset(new SourceBufferStream(video_config, log_cb)); | 291 stream_.reset(new SourceBufferStream(video_config, log_cb)); |
| 294 } | 292 } |
| 295 | 293 |
| 296 void ChunkDemuxerStream::StartWaitingForSeek() { | 294 void ChunkDemuxerStream::StartWaitingForSeek() { |
| 297 DVLOG(1) << "ChunkDemuxerStream::StartWaitingForSeek()"; | 295 DVLOG(1) << "ChunkDemuxerStream::StartWaitingForSeek()"; |
| 298 ReadCBQueue read_cbs; | 296 ReadCBQueue read_cbs; |
| 299 { | 297 { |
| 300 base::AutoLock auto_lock(lock_); | 298 base::AutoLock auto_lock(lock_); |
| 301 ChangeState_Locked(WAITING_FOR_SEEK); | 299 ChangeState_Locked(WAITING_FOR_SEEK); |
| 302 std::swap(read_cbs_, read_cbs); | 300 std::swap(read_cbs_, read_cbs); |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 431 it->Run(DemuxerStream::kOk, StreamParserBuffer::CreateEOSBuffer()); | 429 it->Run(DemuxerStream::kOk, StreamParserBuffer::CreateEOSBuffer()); |
| 432 } | 430 } |
| 433 | 431 |
| 434 // Helper function that makes sure |read_cb| runs on |message_loop_proxy|. | 432 // Helper function that makes sure |read_cb| runs on |message_loop_proxy|. |
| 435 static void RunOnMessageLoop( | 433 static void RunOnMessageLoop( |
| 436 const DemuxerStream::ReadCB& read_cb, | 434 const DemuxerStream::ReadCB& read_cb, |
| 437 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy, | 435 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy, |
| 438 DemuxerStream::Status status, | 436 DemuxerStream::Status status, |
| 439 const scoped_refptr<DecoderBuffer>& buffer) { | 437 const scoped_refptr<DecoderBuffer>& buffer) { |
| 440 if (!message_loop_proxy->BelongsToCurrentThread()) { | 438 if (!message_loop_proxy->BelongsToCurrentThread()) { |
| 441 message_loop_proxy->PostTask(FROM_HERE, base::Bind( | 439 message_loop_proxy->PostTask( |
| 442 &RunOnMessageLoop, read_cb, message_loop_proxy, status, buffer)); | 440 FROM_HERE, |
| 441 base::Bind( | |
| 442 &RunOnMessageLoop, read_cb, message_loop_proxy, status, buffer)); | |
| 443 return; | 443 return; |
| 444 } | 444 } |
| 445 | 445 |
| 446 read_cb.Run(status, buffer); | 446 read_cb.Run(status, buffer); |
| 447 } | 447 } |
| 448 | 448 |
| 449 // DemuxerStream methods. | 449 // DemuxerStream methods. |
| 450 void ChunkDemuxerStream::Read(const ReadCB& read_cb) { | 450 void ChunkDemuxerStream::Read(const ReadCB& read_cb) { |
| 451 DemuxerStream::Status status = kOk; | 451 DemuxerStream::Status status = kOk; |
| 452 scoped_refptr<StreamParserBuffer> buffer; | 452 scoped_refptr<StreamParserBuffer> buffer; |
| 453 { | 453 { |
| 454 base::AutoLock auto_lock(lock_); | 454 base::AutoLock auto_lock(lock_); |
| 455 if (!read_cbs_.empty() || !GetNextBuffer_Locked(&status, &buffer)) { | 455 if (!read_cbs_.empty() || !GetNextBuffer_Locked(&status, &buffer)) { |
| 456 DeferRead_Locked(read_cb); | 456 DeferRead_Locked(read_cb); |
| 457 return; | 457 return; |
| 458 } | 458 } |
| 459 } | 459 } |
| 460 | 460 |
| 461 base::MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( | 461 base::MessageLoopProxy::current()->PostTask( |
| 462 read_cb, status, buffer)); | 462 FROM_HERE, base::Bind(read_cb, status, buffer)); |
| 463 } | 463 } |
| 464 | 464 |
| 465 DemuxerStream::Type ChunkDemuxerStream::type() { return type_; } | 465 DemuxerStream::Type ChunkDemuxerStream::type() { return type_; } |
| 466 | 466 |
| 467 void ChunkDemuxerStream::EnableBitstreamConverter() {} | 467 void ChunkDemuxerStream::EnableBitstreamConverter() {} |
| 468 | 468 |
| 469 AudioDecoderConfig ChunkDemuxerStream::audio_decoder_config() { | 469 AudioDecoderConfig ChunkDemuxerStream::audio_decoder_config() { |
| 470 CHECK_EQ(type_, AUDIO); | 470 CHECK_EQ(type_, AUDIO); |
| 471 base::AutoLock auto_lock(lock_); | 471 base::AutoLock auto_lock(lock_); |
| 472 return stream_->GetCurrentAudioDecoderConfig(); | 472 return stream_->GetCurrentAudioDecoderConfig(); |
| 473 } | 473 } |
| 474 | 474 |
| 475 VideoDecoderConfig ChunkDemuxerStream::video_decoder_config() { | 475 VideoDecoderConfig ChunkDemuxerStream::video_decoder_config() { |
| 476 CHECK_EQ(type_, VIDEO); | 476 CHECK_EQ(type_, VIDEO); |
| 477 base::AutoLock auto_lock(lock_); | 477 base::AutoLock auto_lock(lock_); |
| 478 return stream_->GetCurrentVideoDecoderConfig(); | 478 return stream_->GetCurrentVideoDecoderConfig(); |
| 479 } | 479 } |
| 480 | 480 |
| 481 void ChunkDemuxerStream::ChangeState_Locked(State state) { | 481 void ChunkDemuxerStream::ChangeState_Locked(State state) { |
| 482 lock_.AssertAcquired(); | 482 lock_.AssertAcquired(); |
| 483 DVLOG(1) << "ChunkDemuxerStream::ChangeState_Locked() : " | 483 DVLOG(1) << "ChunkDemuxerStream::ChangeState_Locked() : " |
| 484 << "type " << type_ | 484 << "type " << type_ << " - " << state_ << " -> " << state; |
| 485 << " - " << state_ << " -> " << state; | |
| 486 state_ = state; | 485 state_ = state; |
| 487 } | 486 } |
| 488 | 487 |
| 489 ChunkDemuxerStream::~ChunkDemuxerStream() {} | 488 ChunkDemuxerStream::~ChunkDemuxerStream() {} |
| 490 | 489 |
| 491 void ChunkDemuxerStream::DeferRead_Locked(const ReadCB& read_cb) { | 490 void ChunkDemuxerStream::DeferRead_Locked(const ReadCB& read_cb) { |
| 492 lock_.AssertAcquired(); | 491 lock_.AssertAcquired(); |
| 493 // Wrap & store |read_cb| so that it will | 492 // Wrap & store |read_cb| so that it will |
| 494 // get called on the current MessageLoop. | 493 // get called on the current MessageLoop. |
| 495 read_cbs_.push_back(base::Bind(&RunOnMessageLoop, read_cb, | 494 read_cbs_.push_back(base::Bind( |
| 496 base::MessageLoopProxy::current())); | 495 &RunOnMessageLoop, read_cb, base::MessageLoopProxy::current())); |
| 497 } | 496 } |
| 498 | 497 |
| 499 void ChunkDemuxerStream::CreateReadDoneClosures_Locked(ClosureQueue* closures) { | 498 void ChunkDemuxerStream::CreateReadDoneClosures_Locked(ClosureQueue* closures) { |
| 500 lock_.AssertAcquired(); | 499 lock_.AssertAcquired(); |
| 501 | 500 |
| 502 if (state_ != RETURNING_DATA_FOR_READS) | 501 if (state_ != RETURNING_DATA_FOR_READS) |
| 503 return; | 502 return; |
| 504 | 503 |
| 505 DemuxerStream::Status status; | 504 DemuxerStream::Status status; |
| 506 scoped_refptr<StreamParserBuffer> buffer; | 505 scoped_refptr<StreamParserBuffer> buffer; |
| 507 while (!read_cbs_.empty()) { | 506 while (!read_cbs_.empty()) { |
| 508 if (!GetNextBuffer_Locked(&status, &buffer)) | 507 if (!GetNextBuffer_Locked(&status, &buffer)) |
| 509 return; | 508 return; |
| 510 closures->push_back(base::Bind(read_cbs_.front(), | 509 closures->push_back(base::Bind(read_cbs_.front(), status, buffer)); |
| 511 status, buffer)); | |
| 512 read_cbs_.pop_front(); | 510 read_cbs_.pop_front(); |
| 513 } | 511 } |
| 514 } | 512 } |
| 515 | 513 |
| 516 bool ChunkDemuxerStream::GetNextBuffer_Locked( | 514 bool ChunkDemuxerStream::GetNextBuffer_Locked( |
| 517 DemuxerStream::Status* status, | 515 DemuxerStream::Status* status, |
| 518 scoped_refptr<StreamParserBuffer>* buffer) { | 516 scoped_refptr<StreamParserBuffer>* buffer) { |
| 519 lock_.AssertAcquired(); | 517 lock_.AssertAcquired(); |
| 520 | 518 |
| 521 switch (state_) { | 519 switch (state_) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 572 DCHECK(!open_cb_.is_null()); | 570 DCHECK(!open_cb_.is_null()); |
| 573 DCHECK(!need_key_cb_.is_null()); | 571 DCHECK(!need_key_cb_.is_null()); |
| 574 } | 572 } |
| 575 | 573 |
| 576 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) { | 574 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) { |
| 577 DVLOG(1) << "Init()"; | 575 DVLOG(1) << "Init()"; |
| 578 | 576 |
| 579 base::AutoLock auto_lock(lock_); | 577 base::AutoLock auto_lock(lock_); |
| 580 | 578 |
| 581 if (state_ == SHUTDOWN) { | 579 if (state_ == SHUTDOWN) { |
| 582 base::MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( | 580 base::MessageLoopProxy::current()->PostTask( |
| 583 cb, DEMUXER_ERROR_COULD_NOT_OPEN)); | 581 FROM_HERE, base::Bind(cb, DEMUXER_ERROR_COULD_NOT_OPEN)); |
| 584 return; | 582 return; |
| 585 } | 583 } |
| 586 DCHECK_EQ(state_, WAITING_FOR_INIT); | 584 DCHECK_EQ(state_, WAITING_FOR_INIT); |
| 587 host_ = host; | 585 host_ = host; |
| 588 | 586 |
| 589 ChangeState_Locked(INITIALIZING); | 587 ChangeState_Locked(INITIALIZING); |
| 590 init_cb_ = cb; | 588 init_cb_ = cb; |
| 591 | 589 |
| 592 base::ResetAndReturn(&open_cb_).Run(); | 590 base::ResetAndReturn(&open_cb_).Run(); |
| 593 } | 591 } |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 638 base::AutoLock auto_lock(lock_); | 636 base::AutoLock auto_lock(lock_); |
| 639 if (type == DemuxerStream::VIDEO) | 637 if (type == DemuxerStream::VIDEO) |
| 640 return video_.get(); | 638 return video_.get(); |
| 641 | 639 |
| 642 if (type == DemuxerStream::AUDIO) | 640 if (type == DemuxerStream::AUDIO) |
| 643 return audio_.get(); | 641 return audio_.get(); |
| 644 | 642 |
| 645 return NULL; | 643 return NULL; |
| 646 } | 644 } |
| 647 | 645 |
| 648 TimeDelta ChunkDemuxer::GetStartTime() const { | 646 TimeDelta ChunkDemuxer::GetStartTime() const { return TimeDelta(); } |
| 649 return TimeDelta(); | |
| 650 } | |
| 651 | 647 |
| 652 void ChunkDemuxer::StartWaitingForSeek() { | 648 void ChunkDemuxer::StartWaitingForSeek() { |
| 653 DVLOG(1) << "StartWaitingForSeek()"; | 649 DVLOG(1) << "StartWaitingForSeek()"; |
| 654 base::AutoLock auto_lock(lock_); | 650 base::AutoLock auto_lock(lock_); |
| 655 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN); | 651 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN); |
| 656 | 652 |
| 657 if (state_ == SHUTDOWN) | 653 if (state_ == SHUTDOWN) |
| 658 return; | 654 return; |
| 659 | 655 |
| 660 if (audio_) | 656 if (audio_) |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 686 const std::string& type, | 682 const std::string& type, |
| 687 std::vector<std::string>& codecs) { | 683 std::vector<std::string>& codecs) { |
| 688 DCHECK_GT(codecs.size(), 0u); | 684 DCHECK_GT(codecs.size(), 0u); |
| 689 base::AutoLock auto_lock(lock_); | 685 base::AutoLock auto_lock(lock_); |
| 690 | 686 |
| 691 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id)) | 687 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id)) |
| 692 return kReachedIdLimit; | 688 return kReachedIdLimit; |
| 693 | 689 |
| 694 bool has_audio = false; | 690 bool has_audio = false; |
| 695 bool has_video = false; | 691 bool has_video = false; |
| 696 scoped_ptr<media::StreamParser> stream_parser( | 692 scoped_ptr<media::StreamParser> stream_parser(StreamParserFactory::Create( |
| 697 StreamParserFactory::Create(type, codecs, log_cb_, | 693 type, codecs, log_cb_, &has_audio, &has_video)); |
| 698 &has_audio, &has_video)); | |
| 699 | 694 |
| 700 if (!stream_parser) | 695 if (!stream_parser) |
| 701 return ChunkDemuxer::kNotSupported; | 696 return ChunkDemuxer::kNotSupported; |
| 702 | 697 |
| 703 if ((has_audio && !source_id_audio_.empty()) || | 698 if ((has_audio && !source_id_audio_.empty()) || |
| 704 (has_video && !source_id_video_.empty())) | 699 (has_video && !source_id_video_.empty())) |
| 705 return kReachedIdLimit; | 700 return kReachedIdLimit; |
| 706 | 701 |
| 707 StreamParser::NewBuffersCB audio_cb; | 702 StreamParser::NewBuffersCB audio_cb; |
| 708 StreamParser::NewBuffersCB video_cb; | 703 StreamParser::NewBuffersCB video_cb; |
| 709 | 704 |
| 710 if (has_audio) { | 705 if (has_audio) { |
| 711 source_id_audio_ = id; | 706 source_id_audio_ = id; |
| 712 audio_cb = base::Bind(&ChunkDemuxer::OnAudioBuffers, | 707 audio_cb = |
| 713 base::Unretained(this)); | 708 base::Bind(&ChunkDemuxer::OnAudioBuffers, base::Unretained(this)); |
| 714 } | 709 } |
| 715 | 710 |
| 716 if (has_video) { | 711 if (has_video) { |
| 717 source_id_video_ = id; | 712 source_id_video_ = id; |
| 718 video_cb = base::Bind(&ChunkDemuxer::OnVideoBuffers, | 713 video_cb = |
| 719 base::Unretained(this)); | 714 base::Bind(&ChunkDemuxer::OnVideoBuffers, base::Unretained(this)); |
| 720 } | 715 } |
| 721 | 716 |
| 722 scoped_ptr<SourceState> source_state(new SourceState(stream_parser.Pass())); | 717 scoped_ptr<SourceState> source_state(new SourceState(stream_parser.Pass())); |
| 723 source_state->Init( | 718 source_state->Init( |
| 724 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), | 719 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), |
| 725 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), | 720 base::Bind(&ChunkDemuxer::OnNewConfigs, |
| 726 has_audio, has_video), | 721 base::Unretained(this), |
| 722 has_audio, | |
| 723 has_video), | |
| 727 audio_cb, | 724 audio_cb, |
| 728 video_cb, | 725 video_cb, |
| 729 base::Bind(&ChunkDemuxer::OnTextBuffers, base::Unretained(this)), | 726 base::Bind(&ChunkDemuxer::OnTextBuffers, base::Unretained(this)), |
| 730 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), | 727 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), |
| 731 add_text_track_cb_, | 728 add_text_track_cb_, |
| 732 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id), | 729 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id), |
| 733 log_cb_); | 730 log_cb_); |
| 734 | 731 |
| 735 source_state_map_[id] = source_state.release(); | 732 source_state_map_[id] = source_state.release(); |
| 736 return kOk; | 733 return kOk; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 793 // the streams have slightly different lengths. | 790 // the streams have slightly different lengths. |
| 794 TimeDelta audio_start = audio_ranges.start(audio_ranges.size() - 1); | 791 TimeDelta audio_start = audio_ranges.start(audio_ranges.size() - 1); |
| 795 TimeDelta audio_end = audio_ranges.end(audio_ranges.size() - 1); | 792 TimeDelta audio_end = audio_ranges.end(audio_ranges.size() - 1); |
| 796 TimeDelta video_start = video_ranges.start(video_ranges.size() - 1); | 793 TimeDelta video_start = video_ranges.start(video_ranges.size() - 1); |
| 797 TimeDelta video_end = video_ranges.end(video_ranges.size() - 1); | 794 TimeDelta video_end = video_ranges.end(video_ranges.size() - 1); |
| 798 | 795 |
| 799 // Verify the last audio range overlaps with the last video range. | 796 // Verify the last audio range overlaps with the last video range. |
| 800 // This is enforced by the logic that controls the transition to ENDED. | 797 // This is enforced by the logic that controls the transition to ENDED. |
| 801 DCHECK((audio_start <= video_start && video_start <= audio_end) || | 798 DCHECK((audio_start <= video_start && video_start <= audio_end) || |
| 802 (video_start <= audio_start && audio_start <= video_end)); | 799 (video_start <= audio_start && audio_start <= video_end)); |
| 803 result.Add(result.end(result.size()-1), std::max(audio_end, video_end)); | 800 result.Add(result.end(result.size() - 1), std::max(audio_end, video_end)); |
| 804 } | 801 } |
| 805 | 802 |
| 806 return result; | 803 return result; |
| 807 } | 804 } |
| 808 | 805 |
| 809 void ChunkDemuxer::AppendData(const std::string& id, | 806 void ChunkDemuxer::AppendData(const std::string& id, |
| 810 const uint8* data, | 807 const uint8* data, |
| 811 size_t length) { | 808 size_t length) { |
| 812 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; | 809 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; |
| 813 | 810 |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1019 | 1016 |
| 1020 ChangeState_Locked(SHUTDOWN); | 1017 ChangeState_Locked(SHUTDOWN); |
| 1021 } | 1018 } |
| 1022 | 1019 |
| 1023 if (!cb.is_null()) | 1020 if (!cb.is_null()) |
| 1024 cb.Run(PIPELINE_ERROR_ABORT); | 1021 cb.Run(PIPELINE_ERROR_ABORT); |
| 1025 } | 1022 } |
| 1026 | 1023 |
| 1027 void ChunkDemuxer::ChangeState_Locked(State new_state) { | 1024 void ChunkDemuxer::ChangeState_Locked(State new_state) { |
| 1028 lock_.AssertAcquired(); | 1025 lock_.AssertAcquired(); |
| 1029 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : " | 1026 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : " << state_ << " -> " |
| 1030 << state_ << " -> " << new_state; | 1027 << new_state; |
| 1031 state_ = new_state; | 1028 state_ = new_state; |
| 1032 } | 1029 } |
| 1033 | 1030 |
| 1034 ChunkDemuxer::~ChunkDemuxer() { | 1031 ChunkDemuxer::~ChunkDemuxer() { |
| 1035 DCHECK_NE(state_, INITIALIZED); | 1032 DCHECK_NE(state_, INITIALIZED); |
| 1036 for (SourceStateMap::iterator it = source_state_map_.begin(); | 1033 for (SourceStateMap::iterator it = source_state_map_.begin(); |
| 1037 it != source_state_map_.end(); ++it) { | 1034 it != source_state_map_.end(); |
| 1035 ++it) { | |
| 1038 delete it->second; | 1036 delete it->second; |
| 1039 } | 1037 } |
| 1040 source_state_map_.clear(); | 1038 source_state_map_.clear(); |
| 1041 } | 1039 } |
| 1042 | 1040 |
| 1043 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { | 1041 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { |
| 1044 DVLOG(1) << "ReportError_Locked(" << error << ")"; | 1042 DVLOG(1) << "ReportError_Locked(" << error << ")"; |
| 1045 lock_.AssertAcquired(); | 1043 lock_.AssertAcquired(); |
| 1046 DCHECK_NE(error, PIPELINE_OK); | 1044 DCHECK_NE(error, PIPELINE_OK); |
| 1047 | 1045 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1079 if (audio_) | 1077 if (audio_) |
| 1080 seek_pending = audio_->IsSeekPending(); | 1078 seek_pending = audio_->IsSeekPending(); |
| 1081 | 1079 |
| 1082 if (!seek_pending && video_) | 1080 if (!seek_pending && video_) |
| 1083 seek_pending = video_->IsSeekPending(); | 1081 seek_pending = video_->IsSeekPending(); |
| 1084 | 1082 |
| 1085 return seek_pending; | 1083 return seek_pending; |
| 1086 } | 1084 } |
| 1087 | 1085 |
| 1088 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { | 1086 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { |
| 1089 DVLOG(1) << "OnSourceInitDone(" << success << ", " | 1087 DVLOG(1) << "OnSourceInitDone(" << success << ", " << duration.InSecondsF() |
| 1090 << duration.InSecondsF() << ")"; | 1088 << ")"; |
| 1091 lock_.AssertAcquired(); | 1089 lock_.AssertAcquired(); |
| 1092 DCHECK_EQ(state_, INITIALIZING); | 1090 DCHECK_EQ(state_, INITIALIZING); |
| 1093 if (!success || (!audio_ && !video_)) { | 1091 if (!success || (!audio_ && !video_)) { |
| 1094 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); | 1092 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
| 1095 return; | 1093 return; |
| 1096 } | 1094 } |
| 1097 | 1095 |
| 1098 if (duration != base::TimeDelta() && duration_ == kNoTimestamp()) | 1096 if (duration != base::TimeDelta() && duration_ == kNoTimestamp()) |
| 1099 UpdateDuration(duration); | 1097 UpdateDuration(duration); |
| 1100 | 1098 |
| 1101 // Wait until all streams have initialized. | 1099 // Wait until all streams have initialized. |
| 1102 if ((!source_id_audio_.empty() && !audio_) || | 1100 if ((!source_id_audio_.empty() && !audio_) || |
| 1103 (!source_id_video_.empty() && !video_)) | 1101 (!source_id_video_.empty() && !video_)) |
| 1104 return; | 1102 return; |
| 1105 | 1103 |
| 1106 if (audio_) | 1104 if (audio_) |
| 1107 audio_->Seek(TimeDelta()); | 1105 audio_->Seek(TimeDelta()); |
| 1108 | 1106 |
| 1109 if (video_) | 1107 if (video_) |
| 1110 video_->Seek(TimeDelta()); | 1108 video_->Seek(TimeDelta()); |
| 1111 | 1109 |
| 1112 if (duration_ == kNoTimestamp()) | 1110 if (duration_ == kNoTimestamp()) |
| 1113 duration_ = kInfiniteDuration(); | 1111 duration_ = kInfiniteDuration(); |
| 1114 | 1112 |
| 1115 // The demuxer is now initialized after the |start_timestamp_| was set. | 1113 // The demuxer is now initialized after the |start_timestamp_| was set. |
| 1116 ChangeState_Locked(INITIALIZED); | 1114 ChangeState_Locked(INITIALIZED); |
| 1117 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 1115 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
| 1118 } | 1116 } |
| 1119 | 1117 |
| 1120 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video, | 1118 bool ChunkDemuxer::OnNewConfigs(bool has_audio, |
| 1119 bool has_video, | |
| 1121 const AudioDecoderConfig& audio_config, | 1120 const AudioDecoderConfig& audio_config, |
| 1122 const VideoDecoderConfig& video_config) { | 1121 const VideoDecoderConfig& video_config) { |
| 1123 DVLOG(1) << "OnNewConfigs(" << has_audio << ", " << has_video | 1122 DVLOG(1) << "OnNewConfigs(" << has_audio << ", " << has_video << ", " |
| 1124 << ", " << audio_config.IsValidConfig() | 1123 << audio_config.IsValidConfig() << ", " |
| 1125 << ", " << video_config.IsValidConfig() << ")"; | 1124 << video_config.IsValidConfig() << ")"; |
| 1126 lock_.AssertAcquired(); | 1125 lock_.AssertAcquired(); |
| 1127 | 1126 |
| 1128 if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { | 1127 if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { |
| 1129 DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; | 1128 DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; |
| 1130 return false; | 1129 return false; |
| 1131 } | 1130 } |
| 1132 | 1131 |
| 1133 // Signal an error if we get configuration info for stream types that weren't | 1132 // Signal an error if we get configuration info for stream types that weren't |
| 1134 // specified in AddId() or more configs after a stream is initialized. | 1133 // specified in AddId() or more configs after a stream is initialized. |
| 1135 // Only allow a single audio config for now. | 1134 // Only allow a single audio config for now. |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1198 return false; | 1197 return false; |
| 1199 | 1198 |
| 1200 CHECK(IsValidId(source_id_video_)); | 1199 CHECK(IsValidId(source_id_video_)); |
| 1201 if (!video_->Append(buffers)) | 1200 if (!video_->Append(buffers)) |
| 1202 return false; | 1201 return false; |
| 1203 | 1202 |
| 1204 IncreaseDurationIfNecessary(buffers, video_.get()); | 1203 IncreaseDurationIfNecessary(buffers, video_.get()); |
| 1205 return true; | 1204 return true; |
| 1206 } | 1205 } |
| 1207 | 1206 |
| 1208 bool ChunkDemuxer::OnTextBuffers( | 1207 bool ChunkDemuxer::OnTextBuffers(TextTrack* text_track, |
| 1209 TextTrack* text_track, | 1208 const StreamParser::BufferQueue& buffers) { |
| 1210 const StreamParser::BufferQueue& buffers) { | |
| 1211 lock_.AssertAcquired(); | 1209 lock_.AssertAcquired(); |
| 1212 DCHECK_NE(state_, SHUTDOWN); | 1210 DCHECK_NE(state_, SHUTDOWN); |
| 1213 | 1211 |
| 1214 // TODO(matthewjheaney): IncreaseDurationIfNecessary | 1212 // TODO(matthewjheaney): IncreaseDurationIfNecessary |
| 1215 | 1213 |
| 1216 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); | 1214 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); |
| 1217 itr != buffers.end(); ++itr) { | 1215 itr != buffers.end(); |
| 1216 ++itr) { | |
| 1218 const StreamParserBuffer* const buffer = itr->get(); | 1217 const StreamParserBuffer* const buffer = itr->get(); |
| 1219 const base::TimeDelta start = buffer->GetTimestamp(); | 1218 const base::TimeDelta start = buffer->timestamp(); |
| 1220 const base::TimeDelta end = start + buffer->GetDuration(); | 1219 const base::TimeDelta end = start + buffer->duration(); |
| 1221 | 1220 |
| 1222 std::string id, settings, content; | 1221 std::string id, settings, content; |
| 1223 | 1222 |
| 1224 WebMWebVTTParser::Parse(buffer->GetData(), | 1223 WebMWebVTTParser::Parse( |
| 1225 buffer->GetDataSize(), | 1224 buffer->data(), buffer->data_size(), &id, &settings, &content); |
| 1226 &id, &settings, &content); | |
| 1227 | 1225 |
| 1228 text_track->addWebVTTCue(start, end, id, content, settings); | 1226 text_track->addWebVTTCue(start, end, id, content, settings); |
| 1229 } | 1227 } |
| 1230 | 1228 |
| 1231 return true; | 1229 return true; |
| 1232 } | 1230 } |
| 1233 | 1231 |
| 1234 // TODO(acolwell): Remove bool from StreamParser::NeedKeyCB so that | 1232 // TODO(acolwell): Remove bool from StreamParser::NeedKeyCB so that |
| 1235 // this method can be removed and need_key_cb_ can be passed directly | 1233 // this method can be removed and need_key_cb_ can be passed directly |
| 1236 // to the parser. | 1234 // to the parser. |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 1265 DCHECK(duration_ != new_duration); | 1263 DCHECK(duration_ != new_duration); |
| 1266 user_specified_duration_ = -1; | 1264 user_specified_duration_ = -1; |
| 1267 duration_ = new_duration; | 1265 duration_ = new_duration; |
| 1268 host_->SetDuration(new_duration); | 1266 host_->SetDuration(new_duration); |
| 1269 } | 1267 } |
| 1270 | 1268 |
| 1271 void ChunkDemuxer::IncreaseDurationIfNecessary( | 1269 void ChunkDemuxer::IncreaseDurationIfNecessary( |
| 1272 const StreamParser::BufferQueue& buffers, | 1270 const StreamParser::BufferQueue& buffers, |
| 1273 ChunkDemuxerStream* stream) { | 1271 ChunkDemuxerStream* stream) { |
| 1274 DCHECK(!buffers.empty()); | 1272 DCHECK(!buffers.empty()); |
| 1275 if (buffers.back()->GetTimestamp() <= duration_) | 1273 if (buffers.back()->timestamp() <= duration_) |
| 1276 return; | 1274 return; |
| 1277 | 1275 |
| 1278 Ranges<TimeDelta> ranges = stream->GetBufferedRanges(kInfiniteDuration()); | 1276 Ranges<TimeDelta> ranges = stream->GetBufferedRanges(kInfiniteDuration()); |
| 1279 DCHECK_GT(ranges.size(), 0u); | 1277 DCHECK_GT(ranges.size(), 0u); |
| 1280 | 1278 |
| 1281 base::TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1); | 1279 base::TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1); |
| 1282 if (last_timestamp_buffered > duration_) | 1280 if (last_timestamp_buffered > duration_) |
| 1283 UpdateDuration(last_timestamp_buffered); | 1281 UpdateDuration(last_timestamp_buffered); |
| 1284 } | 1282 } |
| 1285 | 1283 |
| 1286 void ChunkDemuxer::DecreaseDurationIfNecessary() { | 1284 void ChunkDemuxer::DecreaseDurationIfNecessary() { |
| 1287 Ranges<TimeDelta> ranges = GetBufferedRanges(); | 1285 Ranges<TimeDelta> ranges = GetBufferedRanges(); |
| 1288 if (ranges.size() == 0u) | 1286 if (ranges.size() == 0u) |
| 1289 return; | 1287 return; |
| 1290 | 1288 |
| 1291 base::TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1); | 1289 base::TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1); |
| 1292 if (last_timestamp_buffered < duration_) | 1290 if (last_timestamp_buffered < duration_) |
| 1293 UpdateDuration(last_timestamp_buffered); | 1291 UpdateDuration(last_timestamp_buffered); |
| 1294 } | 1292 } |
| 1295 | 1293 |
| 1296 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { | 1294 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { |
| 1297 if (audio_ && !video_) | 1295 if (audio_ && !video_) |
| 1298 return audio_->GetBufferedRanges(duration_); | 1296 return audio_->GetBufferedRanges(duration_); |
| 1299 else if (!audio_ && video_) | 1297 else if (!audio_ && video_) |
| 1300 return video_->GetBufferedRanges(duration_); | 1298 return video_->GetBufferedRanges(duration_); |
| 1301 return ComputeIntersection(); | 1299 return ComputeIntersection(); |
| 1302 } | 1300 } |
| 1303 | 1301 |
| 1304 } // namespace media | 1302 } // namespace media |
| OLD | NEW |