Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(471)

Side by Side Diff: media/filters/chunk_demuxer.cc

Issue 8775035: Add support for incremental cluster parsing. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: _ Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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 can_complete_seek |= (result > 0 && buffers_added);
461 break; 462 } break;
462 463
463 case WAITING_FOR_INIT: 464 case WAITING_FOR_INIT:
464 case ENDED: 465 case ENDED:
465 case PARSE_ERROR: 466 case PARSE_ERROR:
466 case SHUTDOWN: 467 case SHUTDOWN:
467 VLOG(1) << "AppendData(): called in unexpected state " << state_; 468 VLOG(1) << "AppendData(): called in unexpected state " << state_;
468 return false; 469 return false;
469 } 470 }
470 471
471 if (result > 0) { 472 if (result > 0) {
472 cur += result; 473 cur += result;
473 cur_size -= result; 474 cur_size -= result;
474 bytes_parsed += result; 475 bytes_parsed += result;
475 } 476 }
476 } while (result > 0 && cur_size > 0); 477 } while (result > 0 && cur_size > 0);
477 478
478 byte_queue_.Pop(bytes_parsed); 479 byte_queue_.Pop(bytes_parsed);
479 480
480 if (parsed_a_cluster && seek_waits_for_data_) { 481 if (can_complete_seek && seek_waits_for_data_) {
481 seek_waits_for_data_ = false; 482 seek_waits_for_data_ = false;
482 483
483 if (!seek_cb_.is_null()) 484 if (!seek_cb_.is_null())
484 std::swap(cb, seek_cb_); 485 std::swap(cb, seek_cb_);
485 } 486 }
486 487
487 base::TimeDelta tmp; 488 base::TimeDelta tmp;
488 if (audio_.get() && audio_->GetLastBufferTimestamp(&tmp) && 489 if (audio_.get() && audio_->GetLastBufferTimestamp(&tmp) &&
489 tmp > buffered_ts) { 490 tmp > buffered_ts) {
490 buffered_ts = tmp; 491 buffered_ts = tmp;
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after
723 !video_.get()) { 724 !video_.get()) {
724 video_ = new ChunkDemuxerStream(DemuxerStream::VIDEO, stream); 725 video_ = new ChunkDemuxerStream(DemuxerStream::VIDEO, stream);
725 no_supported_streams = false; 726 no_supported_streams = false;
726 continue; 727 continue;
727 } 728 }
728 } 729 }
729 730
730 return !no_supported_streams; 731 return !no_supported_streams;
731 } 732 }
732 733
733 int ChunkDemuxer::ParseCluster_Locked(const uint8* data, int size) { 734 int ChunkDemuxer::ParseCluster_Locked(const uint8* data, int size,
735 bool* buffers_added) {
734 lock_.AssertAcquired(); 736 lock_.AssertAcquired();
735 if (!cluster_parser_.get()) 737 if (!cluster_parser_.get())
736 return -1; 738 return -1;
737 739
738 int id;
739 int64 element_size;
740 int result = WebMParseElementHeader(data, size, &id, &element_size);
741
742 if (result <= 0)
743 return result;
744
745 if (id == kWebMIdCues) {
746 if (size < (result + element_size)) {
747 // We don't have the whole element yet. Signal we need more data.
748 return 0;
749 }
750 // Skip the element.
751 return result + element_size;
752 } else if (id != kWebMIdCluster) {
753 VLOG(1) << "Unexpected ID 0x" << std::hex << id;
754 return -1;
755 }
756
757 int bytes_parsed = cluster_parser_->Parse(data, size); 740 int bytes_parsed = cluster_parser_->Parse(data, size);
758 741
759 if (bytes_parsed <= 0) 742 if (bytes_parsed <= 0)
760 return bytes_parsed; 743 return bytes_parsed;
761 744
762 // Make sure we can add the buffers to both streams before we actutally 745 if (!cluster_parser_->audio_buffers().empty() ||
763 // add them. This allows us to accept all of the data or none of it. 746 !cluster_parser_->video_buffers().empty()) {
764 if ((audio_.get() && 747 // Make sure we can add the buffers to both streams before we actually
765 !audio_->CanAddBuffers(cluster_parser_->audio_buffers())) || 748 // add them. This allows us to accept all of the data or none of it.
766 (video_.get() && 749 if ((audio_.get() &&
767 !video_->CanAddBuffers(cluster_parser_->video_buffers()))) { 750 !audio_->CanAddBuffers(cluster_parser_->audio_buffers())) ||
768 return -1; 751 (video_.get() &&
752 !video_->CanAddBuffers(cluster_parser_->video_buffers()))) {
753 return -1;
754 }
755
756 if (audio_.get())
757 audio_->AddBuffers(cluster_parser_->audio_buffers());
758
759 if (video_.get())
760 video_->AddBuffers(cluster_parser_->video_buffers());
761
762 *buffers_added = true;
769 } 763 }
770 764
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 765 // TODO(acolwell) : make this more representative of what is actually
778 // buffered. 766 // buffered.
779 buffered_bytes_ += bytes_parsed; 767 buffered_bytes_ += bytes_parsed;
780 768
781 return bytes_parsed; 769 return bytes_parsed;
782 } 770 }
783 771
784 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { 772 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) {
785 lock_.AssertAcquired(); 773 lock_.AssertAcquired();
786 DCHECK_NE(error, PIPELINE_OK); 774 DCHECK_NE(error, PIPELINE_OK);
(...skipping 19 matching lines...) Expand all
806 base::AutoUnlock auto_unlock(lock_); 794 base::AutoUnlock auto_unlock(lock_);
807 if (cb.is_null()) { 795 if (cb.is_null()) {
808 host()->SetError(error); 796 host()->SetError(error);
809 return; 797 return;
810 } 798 }
811 cb.Run(error); 799 cb.Run(error);
812 } 800 }
813 } 801 }
814 802
815 } // namespace media 803 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698