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 |