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, then anything can be added. | 133 // If we haven't seen any buffers yet than 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 can_complete_seek = false; | 437 bool parsed_a_cluster = 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 bool buffers_added = false; | 453 result = ParseCluster_Locked(cur, cur_size); |
454 result = ParseCluster_Locked(cur, cur_size, &buffers_added); | |
455 if (result < 0) { | 454 if (result < 0) { |
456 VLOG(1) << "AppendData(): parsing data failed"; | 455 VLOG(1) << "AppendData(): parsing data failed"; |
457 ReportError_Locked(PIPELINE_ERROR_DECODE); | 456 ReportError_Locked(PIPELINE_ERROR_DECODE); |
458 return true; | 457 return true; |
459 } | 458 } |
460 | 459 |
461 // We can complete the seek if we have successfully parsed | 460 parsed_a_cluster = (result > 0); |
462 // some data and buffers were added to one of the DemuxerStreams. | 461 break; |
463 can_complete_seek |= (result > 0 && buffers_added); | |
464 } break; | |
465 | 462 |
466 case WAITING_FOR_INIT: | 463 case WAITING_FOR_INIT: |
467 case ENDED: | 464 case ENDED: |
468 case PARSE_ERROR: | 465 case PARSE_ERROR: |
469 case SHUTDOWN: | 466 case SHUTDOWN: |
470 VLOG(1) << "AppendData(): called in unexpected state " << state_; | 467 VLOG(1) << "AppendData(): called in unexpected state " << state_; |
471 return false; | 468 return false; |
472 } | 469 } |
473 | 470 |
474 if (result > 0) { | 471 if (result > 0) { |
475 cur += result; | 472 cur += result; |
476 cur_size -= result; | 473 cur_size -= result; |
477 bytes_parsed += result; | 474 bytes_parsed += result; |
478 } | 475 } |
479 } while (result > 0 && cur_size > 0); | 476 } while (result > 0 && cur_size > 0); |
480 | 477 |
481 byte_queue_.Pop(bytes_parsed); | 478 byte_queue_.Pop(bytes_parsed); |
482 | 479 |
483 if (can_complete_seek && seek_waits_for_data_) { | 480 if (parsed_a_cluster && seek_waits_for_data_) { |
484 seek_waits_for_data_ = false; | 481 seek_waits_for_data_ = false; |
485 | 482 |
486 if (!seek_cb_.is_null()) | 483 if (!seek_cb_.is_null()) |
487 std::swap(cb, seek_cb_); | 484 std::swap(cb, seek_cb_); |
488 } | 485 } |
489 | 486 |
490 base::TimeDelta tmp; | 487 base::TimeDelta tmp; |
491 if (audio_.get() && audio_->GetLastBufferTimestamp(&tmp) && | 488 if (audio_.get() && audio_->GetLastBufferTimestamp(&tmp) && |
492 tmp > buffered_ts) { | 489 tmp > buffered_ts) { |
493 buffered_ts = tmp; | 490 buffered_ts = tmp; |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
726 !video_.get()) { | 723 !video_.get()) { |
727 video_ = new ChunkDemuxerStream(DemuxerStream::VIDEO, stream); | 724 video_ = new ChunkDemuxerStream(DemuxerStream::VIDEO, stream); |
728 no_supported_streams = false; | 725 no_supported_streams = false; |
729 continue; | 726 continue; |
730 } | 727 } |
731 } | 728 } |
732 | 729 |
733 return !no_supported_streams; | 730 return !no_supported_streams; |
734 } | 731 } |
735 | 732 |
736 int ChunkDemuxer::ParseCluster_Locked(const uint8* data, int size, | 733 int ChunkDemuxer::ParseCluster_Locked(const uint8* data, int size) { |
737 bool* buffers_added) { | |
738 lock_.AssertAcquired(); | 734 lock_.AssertAcquired(); |
739 if (!cluster_parser_.get()) | 735 if (!cluster_parser_.get()) |
740 return -1; | 736 return -1; |
741 | 737 |
742 int id; | 738 int id; |
743 int64 element_size; | 739 int64 element_size; |
744 int result = WebMParseElementHeader(data, size, &id, &element_size); | 740 int result = WebMParseElementHeader(data, size, &id, &element_size); |
745 | 741 |
746 if (result <= 0) | 742 if (result <= 0) |
747 return result; | 743 return result; |
748 | 744 |
749 if (id == kWebMIdCues) { | 745 if (id == kWebMIdCues) { |
750 if (size < (result + element_size)) { | 746 if (size < (result + element_size)) { |
751 // We don't have the whole element yet. Signal we need more data. | 747 // We don't have the whole element yet. Signal we need more data. |
752 return 0; | 748 return 0; |
753 } | 749 } |
754 // Skip the element. | 750 // Skip the element. |
755 return result + element_size; | 751 return result + element_size; |
| 752 } else if (id != kWebMIdCluster) { |
| 753 VLOG(1) << "Unexpected ID 0x" << std::hex << id; |
| 754 return -1; |
756 } | 755 } |
757 | 756 |
758 int bytes_parsed = cluster_parser_->Parse(data, size); | 757 int bytes_parsed = cluster_parser_->Parse(data, size); |
759 | 758 |
760 if (bytes_parsed <= 0) | 759 if (bytes_parsed <= 0) |
761 return bytes_parsed; | 760 return bytes_parsed; |
762 | 761 |
763 if (!cluster_parser_->audio_buffers().empty() || | 762 // Make sure we can add the buffers to both streams before we actutally |
764 !cluster_parser_->video_buffers().empty()) { | 763 // add them. This allows us to accept all of the data or none of it. |
765 // Make sure we can add the buffers to both streams before we actually | 764 if ((audio_.get() && |
766 // add them. This allows us to accept all of the data or none of it. | 765 !audio_->CanAddBuffers(cluster_parser_->audio_buffers())) || |
767 if ((audio_.get() && | 766 (video_.get() && |
768 !audio_->CanAddBuffers(cluster_parser_->audio_buffers())) || | 767 !video_->CanAddBuffers(cluster_parser_->video_buffers()))) { |
769 (video_.get() && | 768 return -1; |
770 !video_->CanAddBuffers(cluster_parser_->video_buffers()))) { | 769 } |
771 return -1; | |
772 } | |
773 | 770 |
774 if (audio_.get()) | 771 if (audio_.get()) |
775 audio_->AddBuffers(cluster_parser_->audio_buffers()); | 772 audio_->AddBuffers(cluster_parser_->audio_buffers()); |
776 | 773 |
777 if (video_.get()) | 774 if (video_.get()) |
778 video_->AddBuffers(cluster_parser_->video_buffers()); | 775 video_->AddBuffers(cluster_parser_->video_buffers()); |
779 | |
780 *buffers_added = true; | |
781 } | |
782 | 776 |
783 // TODO(acolwell) : make this more representative of what is actually | 777 // TODO(acolwell) : make this more representative of what is actually |
784 // buffered. | 778 // buffered. |
785 buffered_bytes_ += bytes_parsed; | 779 buffered_bytes_ += bytes_parsed; |
786 | 780 |
787 return bytes_parsed; | 781 return bytes_parsed; |
788 } | 782 } |
789 | 783 |
790 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { | 784 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { |
791 lock_.AssertAcquired(); | 785 lock_.AssertAcquired(); |
(...skipping 20 matching lines...) Expand all Loading... |
812 base::AutoUnlock auto_unlock(lock_); | 806 base::AutoUnlock auto_unlock(lock_); |
813 if (cb.is_null()) { | 807 if (cb.is_null()) { |
814 host()->SetError(error); | 808 host()->SetError(error); |
815 return; | 809 return; |
816 } | 810 } |
817 cb.Run(error); | 811 cb.Run(error); |
818 } | 812 } |
819 } | 813 } |
820 | 814 |
821 } // namespace media | 815 } // namespace media |
OLD | NEW |