| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 // Implements a Demuxer that can switch among different data sources mid-stream. | 5 // Implements a Demuxer that can switch among different data sources mid-stream. |
| 6 // Uses FFmpegDemuxer under the covers, so see the caveats at the top of | 6 // Uses FFmpegDemuxer under the covers, so see the caveats at the top of |
| 7 // ffmpeg_demuxer.h. | 7 // ffmpeg_demuxer.h. |
| 8 | 8 |
| 9 #include "media/filters/chunk_demuxer.h" | 9 #include "media/filters/chunk_demuxer.h" |
| 10 | 10 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 VLOG(1) << "Flush()"; | 123 VLOG(1) << "Flush()"; |
| 124 base::AutoLock auto_lock(lock_); | 124 base::AutoLock auto_lock(lock_); |
| 125 buffers_.clear(); | 125 buffers_.clear(); |
| 126 received_end_of_stream_ = false; | 126 received_end_of_stream_ = false; |
| 127 last_buffer_timestamp_ = kNoTimestamp; | 127 last_buffer_timestamp_ = kNoTimestamp; |
| 128 } | 128 } |
| 129 | 129 |
| 130 bool ChunkDemuxerStream::CanAddBuffers(const BufferQueue& buffers) const { | 130 bool ChunkDemuxerStream::CanAddBuffers(const BufferQueue& buffers) const { |
| 131 base::AutoLock auto_lock(lock_); | 131 base::AutoLock auto_lock(lock_); |
| 132 | 132 |
| 133 // If we haven't seen any buffers yet than anything can be added. | 133 // If we haven't seen any buffers yet, then anything can be added. |
| 134 if (last_buffer_timestamp_ == kNoTimestamp) | 134 if (last_buffer_timestamp_ == kNoTimestamp) |
| 135 return true; | 135 return true; |
| 136 | 136 |
| 137 if (buffers.empty()) | 137 if (buffers.empty()) |
| 138 return true; | 138 return true; |
| 139 | 139 |
| 140 return (buffers.front()->GetTimestamp() > last_buffer_timestamp_); | 140 return (buffers.front()->GetTimestamp() > last_buffer_timestamp_); |
| 141 } | 141 } |
| 142 | 142 |
| 143 void ChunkDemuxerStream::AddBuffers(const BufferQueue& buffers) { | 143 void ChunkDemuxerStream::AddBuffers(const BufferQueue& buffers) { |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 427 PipelineStatusCB cb; | 427 PipelineStatusCB cb; |
| 428 { | 428 { |
| 429 base::AutoLock auto_lock(lock_); | 429 base::AutoLock auto_lock(lock_); |
| 430 | 430 |
| 431 byte_queue_.Push(data, length); | 431 byte_queue_.Push(data, length); |
| 432 | 432 |
| 433 const uint8* cur = NULL; | 433 const uint8* cur = NULL; |
| 434 int cur_size = 0; | 434 int cur_size = 0; |
| 435 int bytes_parsed = 0; | 435 int bytes_parsed = 0; |
| 436 int result = -1; | 436 int result = -1; |
| 437 bool parsed_a_cluster = false; | 437 bool can_complete_seek = false; |
| 438 | 438 |
| 439 byte_queue_.Peek(&cur, &cur_size); | 439 byte_queue_.Peek(&cur, &cur_size); |
| 440 | 440 |
| 441 do { | 441 do { |
| 442 switch(state_) { | 442 switch(state_) { |
| 443 case INITIALIZING: | 443 case INITIALIZING: |
| 444 result = ParseInfoAndTracks_Locked(cur, cur_size); | 444 result = ParseInfoAndTracks_Locked(cur, cur_size); |
| 445 if (result < 0) { | 445 if (result < 0) { |
| 446 VLOG(1) << "AppendData(): parsing info & tracks failed"; | 446 VLOG(1) << "AppendData(): parsing info & tracks failed"; |
| 447 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); | 447 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
| 448 return true; | 448 return true; |
| 449 } | 449 } |
| 450 break; | 450 break; |
| 451 | 451 |
| 452 case INITIALIZED: | 452 case INITIALIZED: { |
| 453 result = ParseCluster_Locked(cur, cur_size); | 453 bool buffers_added = false; |
| 454 result = ParseCluster_Locked(cur, cur_size, &buffers_added); |
| 454 if (result < 0) { | 455 if (result < 0) { |
| 455 VLOG(1) << "AppendData(): parsing data failed"; | 456 VLOG(1) << "AppendData(): parsing data failed"; |
| 456 ReportError_Locked(PIPELINE_ERROR_DECODE); | 457 ReportError_Locked(PIPELINE_ERROR_DECODE); |
| 457 return true; | 458 return true; |
| 458 } | 459 } |
| 459 | 460 |
| 460 parsed_a_cluster = (result > 0); | 461 // We can complete the seek if we have successfully parsed |
| 461 break; | 462 // some data and buffers were added to one of the DemuxerStreams. |
| 463 can_complete_seek |= (result > 0 && buffers_added); |
| 464 } break; |
| 462 | 465 |
| 463 case WAITING_FOR_INIT: | 466 case WAITING_FOR_INIT: |
| 464 case ENDED: | 467 case ENDED: |
| 465 case PARSE_ERROR: | 468 case PARSE_ERROR: |
| 466 case SHUTDOWN: | 469 case SHUTDOWN: |
| 467 VLOG(1) << "AppendData(): called in unexpected state " << state_; | 470 VLOG(1) << "AppendData(): called in unexpected state " << state_; |
| 468 return false; | 471 return false; |
| 469 } | 472 } |
| 470 | 473 |
| 471 if (result > 0) { | 474 if (result > 0) { |
| 472 cur += result; | 475 cur += result; |
| 473 cur_size -= result; | 476 cur_size -= result; |
| 474 bytes_parsed += result; | 477 bytes_parsed += result; |
| 475 } | 478 } |
| 476 } while (result > 0 && cur_size > 0); | 479 } while (result > 0 && cur_size > 0); |
| 477 | 480 |
| 478 byte_queue_.Pop(bytes_parsed); | 481 byte_queue_.Pop(bytes_parsed); |
| 479 | 482 |
| 480 if (parsed_a_cluster && seek_waits_for_data_) { | 483 if (can_complete_seek && seek_waits_for_data_) { |
| 481 seek_waits_for_data_ = false; | 484 seek_waits_for_data_ = false; |
| 482 | 485 |
| 483 if (!seek_cb_.is_null()) | 486 if (!seek_cb_.is_null()) |
| 484 std::swap(cb, seek_cb_); | 487 std::swap(cb, seek_cb_); |
| 485 } | 488 } |
| 486 | 489 |
| 487 base::TimeDelta tmp; | 490 base::TimeDelta tmp; |
| 488 if (audio_.get() && audio_->GetLastBufferTimestamp(&tmp) && | 491 if (audio_.get() && audio_->GetLastBufferTimestamp(&tmp) && |
| 489 tmp > buffered_ts) { | 492 tmp > buffered_ts) { |
| 490 buffered_ts = tmp; | 493 buffered_ts = tmp; |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 723 !video_.get()) { | 726 !video_.get()) { |
| 724 video_ = new ChunkDemuxerStream(DemuxerStream::VIDEO, stream); | 727 video_ = new ChunkDemuxerStream(DemuxerStream::VIDEO, stream); |
| 725 no_supported_streams = false; | 728 no_supported_streams = false; |
| 726 continue; | 729 continue; |
| 727 } | 730 } |
| 728 } | 731 } |
| 729 | 732 |
| 730 return !no_supported_streams; | 733 return !no_supported_streams; |
| 731 } | 734 } |
| 732 | 735 |
| 733 int ChunkDemuxer::ParseCluster_Locked(const uint8* data, int size) { | 736 int ChunkDemuxer::ParseCluster_Locked(const uint8* data, int size, |
| 737 bool* buffers_added) { |
| 734 lock_.AssertAcquired(); | 738 lock_.AssertAcquired(); |
| 735 if (!cluster_parser_.get()) | 739 if (!cluster_parser_.get()) |
| 736 return -1; | 740 return -1; |
| 737 | 741 |
| 738 int id; | 742 int id; |
| 739 int64 element_size; | 743 int64 element_size; |
| 740 int result = WebMParseElementHeader(data, size, &id, &element_size); | 744 int result = WebMParseElementHeader(data, size, &id, &element_size); |
| 741 | 745 |
| 742 if (result <= 0) | 746 if (result <= 0) |
| 743 return result; | 747 return result; |
| 744 | 748 |
| 745 if (id == kWebMIdCues) { | 749 if (id == kWebMIdCues) { |
| 746 if (size < (result + element_size)) { | 750 if (size < (result + element_size)) { |
| 747 // We don't have the whole element yet. Signal we need more data. | 751 // We don't have the whole element yet. Signal we need more data. |
| 748 return 0; | 752 return 0; |
| 749 } | 753 } |
| 750 // Skip the element. | 754 // Skip the element. |
| 751 return result + element_size; | 755 return result + element_size; |
| 752 } else if (id != kWebMIdCluster) { | |
| 753 VLOG(1) << "Unexpected ID 0x" << std::hex << id; | |
| 754 return -1; | |
| 755 } | 756 } |
| 756 | 757 |
| 757 int bytes_parsed = cluster_parser_->Parse(data, size); | 758 int bytes_parsed = cluster_parser_->Parse(data, size); |
| 758 | 759 |
| 759 if (bytes_parsed <= 0) | 760 if (bytes_parsed <= 0) |
| 760 return bytes_parsed; | 761 return bytes_parsed; |
| 761 | 762 |
| 762 // Make sure we can add the buffers to both streams before we actutally | 763 if (!cluster_parser_->audio_buffers().empty() || |
| 763 // add them. This allows us to accept all of the data or none of it. | 764 !cluster_parser_->video_buffers().empty()) { |
| 764 if ((audio_.get() && | 765 // Make sure we can add the buffers to both streams before we actually |
| 765 !audio_->CanAddBuffers(cluster_parser_->audio_buffers())) || | 766 // add them. This allows us to accept all of the data or none of it. |
| 766 (video_.get() && | 767 if ((audio_.get() && |
| 767 !video_->CanAddBuffers(cluster_parser_->video_buffers()))) { | 768 !audio_->CanAddBuffers(cluster_parser_->audio_buffers())) || |
| 768 return -1; | 769 (video_.get() && |
| 770 !video_->CanAddBuffers(cluster_parser_->video_buffers()))) { |
| 771 return -1; |
| 772 } |
| 773 |
| 774 if (audio_.get()) |
| 775 audio_->AddBuffers(cluster_parser_->audio_buffers()); |
| 776 |
| 777 if (video_.get()) |
| 778 video_->AddBuffers(cluster_parser_->video_buffers()); |
| 779 |
| 780 *buffers_added = true; |
| 769 } | 781 } |
| 770 | 782 |
| 771 if (audio_.get()) | |
| 772 audio_->AddBuffers(cluster_parser_->audio_buffers()); | |
| 773 | |
| 774 if (video_.get()) | |
| 775 video_->AddBuffers(cluster_parser_->video_buffers()); | |
| 776 | |
| 777 // TODO(acolwell) : make this more representative of what is actually | 783 // TODO(acolwell) : make this more representative of what is actually |
| 778 // buffered. | 784 // buffered. |
| 779 buffered_bytes_ += bytes_parsed; | 785 buffered_bytes_ += bytes_parsed; |
| 780 | 786 |
| 781 return bytes_parsed; | 787 return bytes_parsed; |
| 782 } | 788 } |
| 783 | 789 |
| 784 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { | 790 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { |
| 785 lock_.AssertAcquired(); | 791 lock_.AssertAcquired(); |
| 786 DCHECK_NE(error, PIPELINE_OK); | 792 DCHECK_NE(error, PIPELINE_OK); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 806 base::AutoUnlock auto_unlock(lock_); | 812 base::AutoUnlock auto_unlock(lock_); |
| 807 if (cb.is_null()) { | 813 if (cb.is_null()) { |
| 808 host()->SetError(error); | 814 host()->SetError(error); |
| 809 return; | 815 return; |
| 810 } | 816 } |
| 811 cb.Run(error); | 817 cb.Run(error); |
| 812 } | 818 } |
| 813 } | 819 } |
| 814 | 820 |
| 815 } // namespace media | 821 } // namespace media |
| OLD | NEW |