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