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

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: Remove static initializer 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
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/media.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // 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
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
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
OLDNEW
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/media.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698