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 #include <list> | 10 #include <list> |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 const NewTextTrackCB& new_text_track_cb); | 107 const NewTextTrackCB& new_text_track_cb); |
108 | 108 |
109 // Appends new data to the StreamParser. | 109 // Appends new data to the StreamParser. |
110 // Returns true if the data was successfully appended. Returns false if an | 110 // Returns true if the data was successfully appended. Returns false if an |
111 // error occurred. | 111 // error occurred. |
112 bool Append(const uint8* data, size_t length); | 112 bool Append(const uint8* data, size_t length); |
113 | 113 |
114 // Aborts the current append sequence and resets the parser. | 114 // Aborts the current append sequence and resets the parser. |
115 void Abort(); | 115 void Abort(); |
116 | 116 |
| 117 // Calls Remove(|start|, |end|, |duration|) on all |
| 118 // ChunkDemuxerStreams managed by this object. |
| 119 void Remove(TimeDelta start, TimeDelta end, TimeDelta duration); |
| 120 |
117 // Sets |timestamp_offset_| if possible. | 121 // Sets |timestamp_offset_| if possible. |
118 // Returns if the offset was set. Returns false if the offset could not be | 122 // Returns if the offset was set. Returns false if the offset could not be |
119 // updated at this time. | 123 // updated at this time. |
120 bool SetTimestampOffset(TimeDelta timestamp_offset); | 124 bool SetTimestampOffset(TimeDelta timestamp_offset); |
121 | 125 |
122 TimeDelta timestamp_offset() const { return timestamp_offset_; } | 126 TimeDelta timestamp_offset() const { return timestamp_offset_; } |
123 | 127 |
124 void set_append_window_start(TimeDelta start) { | 128 void set_append_window_start(TimeDelta start) { |
125 append_window_start_ = start; | 129 append_window_start_ = start; |
126 } | 130 } |
(...skipping 11 matching lines...) Expand all Loading... |
138 | 142 |
139 // Helper methods that call methods with similar names on all the | 143 // Helper methods that call methods with similar names on all the |
140 // ChunkDemuxerStreams managed by this object. | 144 // ChunkDemuxerStreams managed by this object. |
141 void StartReturningData(); | 145 void StartReturningData(); |
142 void AbortReads(); | 146 void AbortReads(); |
143 void Seek(TimeDelta seek_time); | 147 void Seek(TimeDelta seek_time); |
144 void CompletePendingReadIfPossible(); | 148 void CompletePendingReadIfPossible(); |
145 void OnSetDuration(TimeDelta duration); | 149 void OnSetDuration(TimeDelta duration); |
146 void MarkEndOfStream(); | 150 void MarkEndOfStream(); |
147 void UnmarkEndOfStream(); | 151 void UnmarkEndOfStream(); |
| 152 void Shutdown(); |
| 153 // Sets the memory limit on each stream. |memory_limit| is the |
| 154 // maximum number of bytes each stream is allowed to hold in its buffer. |
| 155 void SetMemoryLimitsForTesting(int memory_limit); |
| 156 bool IsSeekWaitingForData() const; |
148 | 157 |
149 private: | 158 private: |
150 // Called by the |stream_parser_| when a new initialization segment is | 159 // Called by the |stream_parser_| when a new initialization segment is |
151 // encountered. | 160 // encountered. |
152 // Returns true on a successful call. Returns false if an error occured while | 161 // Returns true on a successful call. Returns false if an error occured while |
153 // processing decoder configurations. | 162 // processing decoder configurations. |
154 bool OnNewConfigs(bool allow_audio, bool allow_video, | 163 bool OnNewConfigs(bool allow_audio, bool allow_video, |
155 const AudioDecoderConfig& audio_config, | 164 const AudioDecoderConfig& audio_config, |
156 const VideoDecoderConfig& video_config, | 165 const VideoDecoderConfig& video_config, |
157 const StreamParser::TextTrackConfigMap& text_configs); | 166 const StreamParser::TextTrackConfigMap& text_configs); |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
298 virtual void Read(const ReadCB& read_cb) OVERRIDE; | 307 virtual void Read(const ReadCB& read_cb) OVERRIDE; |
299 virtual Type type() OVERRIDE; | 308 virtual Type type() OVERRIDE; |
300 virtual void EnableBitstreamConverter() OVERRIDE; | 309 virtual void EnableBitstreamConverter() OVERRIDE; |
301 virtual AudioDecoderConfig audio_decoder_config() OVERRIDE; | 310 virtual AudioDecoderConfig audio_decoder_config() OVERRIDE; |
302 virtual VideoDecoderConfig video_decoder_config() OVERRIDE; | 311 virtual VideoDecoderConfig video_decoder_config() OVERRIDE; |
303 | 312 |
304 // Returns the text track configuration. It is an error to call this method | 313 // Returns the text track configuration. It is an error to call this method |
305 // if type() != TEXT. | 314 // if type() != TEXT. |
306 TextTrackConfig text_track_config(); | 315 TextTrackConfig text_track_config(); |
307 | 316 |
| 317 // Sets the memory limit, in bytes, on the SourceBufferStream. |
308 void set_memory_limit_for_testing(int memory_limit) { | 318 void set_memory_limit_for_testing(int memory_limit) { |
309 stream_->set_memory_limit_for_testing(memory_limit); | 319 stream_->set_memory_limit_for_testing(memory_limit); |
310 } | 320 } |
311 | 321 |
312 private: | 322 private: |
313 enum State { | 323 enum State { |
314 UNINITIALIZED, | 324 UNINITIALIZED, |
315 RETURNING_DATA_FOR_READS, | 325 RETURNING_DATA_FOR_READS, |
316 RETURNING_ABORT_FOR_READS, | 326 RETURNING_ABORT_FOR_READS, |
317 SHUTDOWN, | 327 SHUTDOWN, |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
353 audio_(NULL), | 363 audio_(NULL), |
354 audio_needs_keyframe_(true), | 364 audio_needs_keyframe_(true), |
355 video_(NULL), | 365 video_(NULL), |
356 video_needs_keyframe_(true), | 366 video_needs_keyframe_(true), |
357 log_cb_(log_cb) { | 367 log_cb_(log_cb) { |
358 DCHECK(!create_demuxer_stream_cb_.is_null()); | 368 DCHECK(!create_demuxer_stream_cb_.is_null()); |
359 DCHECK(!increase_duration_cb_.is_null()); | 369 DCHECK(!increase_duration_cb_.is_null()); |
360 } | 370 } |
361 | 371 |
362 SourceState::~SourceState() { | 372 SourceState::~SourceState() { |
363 if (audio_) | 373 Shutdown(); |
364 audio_->Shutdown(); | |
365 | 374 |
366 if (video_) | 375 STLDeleteValues(&text_stream_map_); |
367 video_->Shutdown(); | |
368 | |
369 for (TextStreamMap::iterator itr = text_stream_map_.begin(); | |
370 itr != text_stream_map_.end(); ++itr) { | |
371 itr->second->Shutdown(); | |
372 delete itr->second; | |
373 } | |
374 } | 376 } |
375 | 377 |
376 void SourceState::Init(const StreamParser::InitCB& init_cb, | 378 void SourceState::Init(const StreamParser::InitCB& init_cb, |
377 bool allow_audio, | 379 bool allow_audio, |
378 bool allow_video, | 380 bool allow_video, |
379 const StreamParser::NeedKeyCB& need_key_cb, | 381 const StreamParser::NeedKeyCB& need_key_cb, |
380 const NewTextTrackCB& new_text_track_cb) { | 382 const NewTextTrackCB& new_text_track_cb) { |
381 new_text_track_cb_ = new_text_track_cb; | 383 new_text_track_cb_ = new_text_track_cb; |
382 | 384 |
383 StreamParser::NewTextBuffersCB new_text_buffers_cb; | 385 StreamParser::NewTextBuffersCB new_text_buffers_cb; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
415 return stream_parser_->Parse(data, length); | 417 return stream_parser_->Parse(data, length); |
416 } | 418 } |
417 | 419 |
418 void SourceState::Abort() { | 420 void SourceState::Abort() { |
419 stream_parser_->Flush(); | 421 stream_parser_->Flush(); |
420 audio_needs_keyframe_ = true; | 422 audio_needs_keyframe_ = true; |
421 video_needs_keyframe_ = true; | 423 video_needs_keyframe_ = true; |
422 can_update_offset_ = true; | 424 can_update_offset_ = true; |
423 } | 425 } |
424 | 426 |
| 427 void SourceState::Remove(TimeDelta start, TimeDelta end, TimeDelta duration) { |
| 428 if (audio_) |
| 429 audio_->Remove(start, end, duration); |
| 430 |
| 431 if (video_) |
| 432 video_->Remove(start, end, duration); |
| 433 |
| 434 for (TextStreamMap::iterator itr = text_stream_map_.begin(); |
| 435 itr != text_stream_map_.end(); ++itr) { |
| 436 itr->second->Remove(start, end, duration); |
| 437 } |
| 438 } |
| 439 |
425 Ranges<TimeDelta> SourceState::GetBufferedRanges(TimeDelta duration, | 440 Ranges<TimeDelta> SourceState::GetBufferedRanges(TimeDelta duration, |
426 bool ended) const { | 441 bool ended) const { |
427 // TODO(acolwell): When we start allowing disabled tracks we'll need to update | 442 // TODO(acolwell): When we start allowing disabled tracks we'll need to update |
428 // this code to only add ranges from active tracks. | 443 // this code to only add ranges from active tracks. |
429 RangesList ranges_list; | 444 RangesList ranges_list; |
430 if (audio_) | 445 if (audio_) |
431 ranges_list.push_back(audio_->GetBufferedRanges(duration)); | 446 ranges_list.push_back(audio_->GetBufferedRanges(duration)); |
432 | 447 |
433 if (video_) | 448 if (video_) |
434 ranges_list.push_back(video_->GetBufferedRanges(duration)); | 449 ranges_list.push_back(video_->GetBufferedRanges(duration)); |
435 | 450 |
436 for (TextStreamMap::const_iterator itr = text_stream_map_.begin(); | 451 for (TextStreamMap::const_iterator itr = text_stream_map_.begin(); |
437 itr != text_stream_map_.end(); ++itr) { | 452 itr != text_stream_map_.end(); ++itr) { |
438 ranges_list.push_back(itr->second->GetBufferedRanges(duration)); | 453 ranges_list.push_back(itr->second->GetBufferedRanges(duration)); |
439 } | 454 } |
440 | 455 |
441 return ComputeIntersection(ranges_list, ended); | 456 return ComputeIntersection(ranges_list, ended); |
442 } | 457 } |
443 | 458 |
444 TimeDelta SourceState::GetMaxBufferedDuration() const { | 459 TimeDelta SourceState::GetMaxBufferedDuration() const { |
445 TimeDelta max_duration; | 460 TimeDelta max_duration; |
446 | 461 |
447 if (audio_) | 462 if (audio_) |
448 max_duration = std::max(max_duration, audio_->GetBufferedDuration()); | 463 max_duration = std::max(max_duration, audio_->GetBufferedDuration()); |
449 | 464 |
450 if (video_) | 465 if (video_) |
451 max_duration = std::max(max_duration, video_->GetBufferedDuration()); | 466 max_duration = std::max(max_duration, video_->GetBufferedDuration()); |
452 | 467 |
453 | |
454 for (TextStreamMap::const_iterator itr = text_stream_map_.begin(); | 468 for (TextStreamMap::const_iterator itr = text_stream_map_.begin(); |
455 itr != text_stream_map_.end(); ++itr) { | 469 itr != text_stream_map_.end(); ++itr) { |
456 max_duration = std::max(max_duration, itr->second->GetBufferedDuration()); | 470 max_duration = std::max(max_duration, itr->second->GetBufferedDuration()); |
457 } | 471 } |
458 | 472 |
459 return max_duration; | 473 return max_duration; |
460 } | 474 } |
461 | 475 |
462 void SourceState::StartReturningData() { | 476 void SourceState::StartReturningData() { |
463 if (audio_) | 477 if (audio_) |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
543 | 557 |
544 if (video_) | 558 if (video_) |
545 video_->UnmarkEndOfStream(); | 559 video_->UnmarkEndOfStream(); |
546 | 560 |
547 for (TextStreamMap::iterator itr = text_stream_map_.begin(); | 561 for (TextStreamMap::iterator itr = text_stream_map_.begin(); |
548 itr != text_stream_map_.end(); ++itr) { | 562 itr != text_stream_map_.end(); ++itr) { |
549 itr->second->UnmarkEndOfStream(); | 563 itr->second->UnmarkEndOfStream(); |
550 } | 564 } |
551 } | 565 } |
552 | 566 |
| 567 void SourceState::Shutdown() { |
| 568 if (audio_) |
| 569 audio_->Shutdown(); |
| 570 |
| 571 if (video_) |
| 572 video_->Shutdown(); |
| 573 |
| 574 for (TextStreamMap::iterator itr = text_stream_map_.begin(); |
| 575 itr != text_stream_map_.end(); ++itr) { |
| 576 itr->second->Shutdown(); |
| 577 } |
| 578 } |
| 579 |
| 580 void SourceState::SetMemoryLimitsForTesting(int memory_limit) { |
| 581 if (audio_) |
| 582 audio_->set_memory_limit_for_testing(memory_limit); |
| 583 |
| 584 if (video_) |
| 585 video_->set_memory_limit_for_testing(memory_limit); |
| 586 |
| 587 for (TextStreamMap::iterator itr = text_stream_map_.begin(); |
| 588 itr != text_stream_map_.end(); ++itr) { |
| 589 itr->second->set_memory_limit_for_testing(memory_limit); |
| 590 } |
| 591 } |
| 592 |
| 593 bool SourceState::IsSeekWaitingForData() const { |
| 594 if (audio_ && audio_->IsSeekWaitingForData()) |
| 595 return true; |
| 596 |
| 597 if (video_ && video_->IsSeekWaitingForData()) |
| 598 return true; |
| 599 |
| 600 // NOTE: We are intentionally not checking the text tracks |
| 601 // because text tracks are discontinuous and may not have data |
| 602 // for the seek position. This is ok and playback should not be |
| 603 // stalled because we don't have cues. If cues, with timestamps after |
| 604 // the seek time, eventually arrive they will be delivered properly |
| 605 // in response to ChunkDemuxerStream::Read() calls. |
| 606 |
| 607 return false; |
| 608 } |
| 609 |
553 void SourceState::AdjustBufferTimestamps( | 610 void SourceState::AdjustBufferTimestamps( |
554 const StreamParser::BufferQueue& buffers) { | 611 const StreamParser::BufferQueue& buffers) { |
555 if (timestamp_offset_ == TimeDelta()) | 612 if (timestamp_offset_ == TimeDelta()) |
556 return; | 613 return; |
557 | 614 |
558 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); | 615 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); |
559 itr != buffers.end(); ++itr) { | 616 itr != buffers.end(); ++itr) { |
560 (*itr)->SetDecodeTimestamp( | 617 (*itr)->SetDecodeTimestamp( |
561 (*itr)->GetDecodeTimestamp() + timestamp_offset_); | 618 (*itr)->GetDecodeTimestamp() + timestamp_offset_); |
562 (*itr)->set_timestamp((*itr)->timestamp() + timestamp_offset_); | 619 (*itr)->set_timestamp((*itr)->timestamp() + timestamp_offset_); |
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
877 // Pass an end of stream buffer to the pending callback to signal that no more | 934 // Pass an end of stream buffer to the pending callback to signal that no more |
878 // data will be sent. | 935 // data will be sent. |
879 if (!read_cb_.is_null()) { | 936 if (!read_cb_.is_null()) { |
880 base::ResetAndReturn(&read_cb_).Run(DemuxerStream::kOk, | 937 base::ResetAndReturn(&read_cb_).Run(DemuxerStream::kOk, |
881 StreamParserBuffer::CreateEOSBuffer()); | 938 StreamParserBuffer::CreateEOSBuffer()); |
882 } | 939 } |
883 } | 940 } |
884 | 941 |
885 bool ChunkDemuxerStream::IsSeekWaitingForData() const { | 942 bool ChunkDemuxerStream::IsSeekWaitingForData() const { |
886 base::AutoLock auto_lock(lock_); | 943 base::AutoLock auto_lock(lock_); |
| 944 |
| 945 // This method should not be called for text tracks. See the note in |
| 946 // SourceState::IsSeekWaitingForData(). |
| 947 DCHECK_NE(type_, DemuxerStream::TEXT); |
| 948 |
887 return stream_->IsSeekPending(); | 949 return stream_->IsSeekPending(); |
888 } | 950 } |
889 | 951 |
890 void ChunkDemuxerStream::Seek(TimeDelta time) { | 952 void ChunkDemuxerStream::Seek(TimeDelta time) { |
891 DVLOG(1) << "ChunkDemuxerStream::Seek(" << time.InSecondsF() << ")"; | 953 DVLOG(1) << "ChunkDemuxerStream::Seek(" << time.InSecondsF() << ")"; |
892 base::AutoLock auto_lock(lock_); | 954 base::AutoLock auto_lock(lock_); |
893 DCHECK(read_cb_.is_null()); | 955 DCHECK(read_cb_.is_null()); |
894 DCHECK(state_ == UNINITIALIZED || state_ == RETURNING_ABORT_FOR_READS) | 956 DCHECK(state_ == UNINITIALIZED || state_ == RETURNING_ABORT_FOR_READS) |
895 << state_; | 957 << state_; |
896 | 958 |
(...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1375 } | 1437 } |
1376 | 1438 |
1377 void ChunkDemuxer::Abort(const std::string& id) { | 1439 void ChunkDemuxer::Abort(const std::string& id) { |
1378 DVLOG(1) << "Abort(" << id << ")"; | 1440 DVLOG(1) << "Abort(" << id << ")"; |
1379 base::AutoLock auto_lock(lock_); | 1441 base::AutoLock auto_lock(lock_); |
1380 DCHECK(!id.empty()); | 1442 DCHECK(!id.empty()); |
1381 CHECK(IsValidId(id)); | 1443 CHECK(IsValidId(id)); |
1382 source_state_map_[id]->Abort(); | 1444 source_state_map_[id]->Abort(); |
1383 } | 1445 } |
1384 | 1446 |
1385 void ChunkDemuxer::Remove(const std::string& id, base::TimeDelta start, | 1447 void ChunkDemuxer::Remove(const std::string& id, TimeDelta start, |
1386 base::TimeDelta end) { | 1448 TimeDelta end) { |
1387 DVLOG(1) << "Remove(" << id << ", " << start.InSecondsF() | 1449 DVLOG(1) << "Remove(" << id << ", " << start.InSecondsF() |
1388 << ", " << end.InSecondsF() << ")"; | 1450 << ", " << end.InSecondsF() << ")"; |
1389 base::AutoLock auto_lock(lock_); | 1451 base::AutoLock auto_lock(lock_); |
1390 | 1452 |
1391 if (id == source_id_audio_ && audio_) | 1453 DCHECK(!id.empty()); |
1392 audio_->Remove(start, end, duration_); | 1454 CHECK(IsValidId(id)); |
1393 | 1455 source_state_map_[id]->Remove(start, end, duration_); |
1394 if (id == source_id_video_ && video_) | |
1395 video_->Remove(start, end, duration_); | |
1396 } | 1456 } |
1397 | 1457 |
1398 double ChunkDemuxer::GetDuration() { | 1458 double ChunkDemuxer::GetDuration() { |
1399 base::AutoLock auto_lock(lock_); | 1459 base::AutoLock auto_lock(lock_); |
1400 return GetDuration_Locked(); | 1460 return GetDuration_Locked(); |
1401 } | 1461 } |
1402 | 1462 |
1403 double ChunkDemuxer::GetDuration_Locked() { | 1463 double ChunkDemuxer::GetDuration_Locked() { |
1404 lock_.AssertAcquired(); | 1464 lock_.AssertAcquired(); |
1405 if (duration_ == kNoTimestamp()) | 1465 if (duration_ == kNoTimestamp()) |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1530 source_state_map_[id]->set_append_window_end(end); | 1590 source_state_map_[id]->set_append_window_end(end); |
1531 } | 1591 } |
1532 | 1592 |
1533 void ChunkDemuxer::Shutdown() { | 1593 void ChunkDemuxer::Shutdown() { |
1534 DVLOG(1) << "Shutdown()"; | 1594 DVLOG(1) << "Shutdown()"; |
1535 base::AutoLock auto_lock(lock_); | 1595 base::AutoLock auto_lock(lock_); |
1536 | 1596 |
1537 if (state_ == SHUTDOWN) | 1597 if (state_ == SHUTDOWN) |
1538 return; | 1598 return; |
1539 | 1599 |
1540 if (audio_) | 1600 ShutdownAllStreams(); |
1541 audio_->Shutdown(); | |
1542 | |
1543 if (video_) | |
1544 video_->Shutdown(); | |
1545 | 1601 |
1546 ChangeState_Locked(SHUTDOWN); | 1602 ChangeState_Locked(SHUTDOWN); |
1547 | 1603 |
1548 if(!seek_cb_.is_null()) | 1604 if(!seek_cb_.is_null()) |
1549 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_ERROR_ABORT); | 1605 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_ERROR_ABORT); |
1550 } | 1606 } |
1551 | 1607 |
1552 void ChunkDemuxer::SetMemoryLimitsForTesting(int memory_limit) { | 1608 void ChunkDemuxer::SetMemoryLimitsForTesting(int memory_limit) { |
1553 if (audio_) | 1609 for (SourceStateMap::iterator itr = source_state_map_.begin(); |
1554 audio_->set_memory_limit_for_testing(memory_limit); | 1610 itr != source_state_map_.end(); ++itr) { |
1555 | 1611 itr->second->SetMemoryLimitsForTesting(memory_limit); |
1556 if (video_) | 1612 } |
1557 video_->set_memory_limit_for_testing(memory_limit); | |
1558 } | 1613 } |
1559 | 1614 |
1560 void ChunkDemuxer::ChangeState_Locked(State new_state) { | 1615 void ChunkDemuxer::ChangeState_Locked(State new_state) { |
1561 lock_.AssertAcquired(); | 1616 lock_.AssertAcquired(); |
1562 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : " | 1617 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : " |
1563 << state_ << " -> " << new_state; | 1618 << state_ << " -> " << new_state; |
1564 state_ = new_state; | 1619 state_ = new_state; |
1565 } | 1620 } |
1566 | 1621 |
1567 ChunkDemuxer::~ChunkDemuxer() { | 1622 ChunkDemuxer::~ChunkDemuxer() { |
1568 DCHECK_NE(state_, INITIALIZED); | 1623 DCHECK_NE(state_, INITIALIZED); |
1569 for (SourceStateMap::iterator it = source_state_map_.begin(); | 1624 |
1570 it != source_state_map_.end(); ++it) { | 1625 STLDeleteValues(&source_state_map_); |
1571 delete it->second; | |
1572 } | |
1573 source_state_map_.clear(); | |
1574 } | 1626 } |
1575 | 1627 |
1576 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { | 1628 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { |
1577 DVLOG(1) << "ReportError_Locked(" << error << ")"; | 1629 DVLOG(1) << "ReportError_Locked(" << error << ")"; |
1578 lock_.AssertAcquired(); | 1630 lock_.AssertAcquired(); |
1579 DCHECK_NE(error, PIPELINE_OK); | 1631 DCHECK_NE(error, PIPELINE_OK); |
1580 | 1632 |
1581 ChangeState_Locked(PARSE_ERROR); | 1633 ChangeState_Locked(PARSE_ERROR); |
1582 | 1634 |
1583 PipelineStatusCB cb; | 1635 PipelineStatusCB cb; |
1584 | 1636 |
1585 if (!init_cb_.is_null()) { | 1637 if (!init_cb_.is_null()) { |
1586 std::swap(cb, init_cb_); | 1638 std::swap(cb, init_cb_); |
1587 } else { | 1639 } else { |
1588 if (!seek_cb_.is_null()) | 1640 if (!seek_cb_.is_null()) |
1589 std::swap(cb, seek_cb_); | 1641 std::swap(cb, seek_cb_); |
1590 | 1642 |
1591 if (audio_) | 1643 ShutdownAllStreams(); |
1592 audio_->Shutdown(); | |
1593 | |
1594 if (video_) | |
1595 video_->Shutdown(); | |
1596 } | 1644 } |
1597 | 1645 |
1598 if (!cb.is_null()) { | 1646 if (!cb.is_null()) { |
1599 cb.Run(error); | 1647 cb.Run(error); |
1600 return; | 1648 return; |
1601 } | 1649 } |
1602 | 1650 |
1603 base::AutoUnlock auto_unlock(lock_); | 1651 base::AutoUnlock auto_unlock(lock_); |
1604 host_->OnDemuxerError(error); | 1652 host_->OnDemuxerError(error); |
1605 } | 1653 } |
1606 | 1654 |
1607 bool ChunkDemuxer::IsSeekWaitingForData_Locked() const { | 1655 bool ChunkDemuxer::IsSeekWaitingForData_Locked() const { |
1608 lock_.AssertAcquired(); | 1656 lock_.AssertAcquired(); |
1609 bool waiting_for_data = false; | 1657 for (SourceStateMap::const_iterator itr = source_state_map_.begin(); |
| 1658 itr != source_state_map_.end(); ++itr) { |
| 1659 if (itr->second->IsSeekWaitingForData()) |
| 1660 return true; |
| 1661 } |
1610 | 1662 |
1611 if (audio_) | 1663 return false; |
1612 waiting_for_data = audio_->IsSeekWaitingForData(); | |
1613 | |
1614 if (!waiting_for_data && video_) | |
1615 waiting_for_data = video_->IsSeekWaitingForData(); | |
1616 | |
1617 return waiting_for_data; | |
1618 } | 1664 } |
1619 | 1665 |
1620 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { | 1666 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { |
1621 DVLOG(1) << "OnSourceInitDone(" << success << ", " | 1667 DVLOG(1) << "OnSourceInitDone(" << success << ", " |
1622 << duration.InSecondsF() << ")"; | 1668 << duration.InSecondsF() << ")"; |
1623 lock_.AssertAcquired(); | 1669 lock_.AssertAcquired(); |
1624 DCHECK_EQ(state_, INITIALIZING); | 1670 DCHECK_EQ(state_, INITIALIZING); |
1625 if (!success || (!audio_ && !video_)) { | 1671 if (!success || (!audio_ && !video_)) { |
1626 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); | 1672 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
1627 return; | 1673 return; |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1766 } | 1812 } |
1767 } | 1813 } |
1768 | 1814 |
1769 void ChunkDemuxer::CompletePendingReadsIfPossible() { | 1815 void ChunkDemuxer::CompletePendingReadsIfPossible() { |
1770 for (SourceStateMap::iterator itr = source_state_map_.begin(); | 1816 for (SourceStateMap::iterator itr = source_state_map_.begin(); |
1771 itr != source_state_map_.end(); ++itr) { | 1817 itr != source_state_map_.end(); ++itr) { |
1772 itr->second->CompletePendingReadIfPossible(); | 1818 itr->second->CompletePendingReadIfPossible(); |
1773 } | 1819 } |
1774 } | 1820 } |
1775 | 1821 |
| 1822 void ChunkDemuxer::ShutdownAllStreams() { |
| 1823 for (SourceStateMap::iterator itr = source_state_map_.begin(); |
| 1824 itr != source_state_map_.end(); ++itr) { |
| 1825 itr->second->Shutdown(); |
| 1826 } |
| 1827 } |
| 1828 |
1776 } // namespace media | 1829 } // namespace media |
OLD | NEW |