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

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

Issue 10803019: Chrome-side implementation of media source timestamp offset (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase ToT Created 8 years, 4 months 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/filters/chunk_demuxer_unittest.cc » ('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) 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 "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback_helpers.h" 8 #include "base/callback_helpers.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/message_loop.h" 10 #include "base/message_loop.h"
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 // and |has_video| are undefined. 104 // and |has_video| are undefined.
105 static bool IsSupported(const std::string& type, 105 static bool IsSupported(const std::string& type,
106 std::vector<std::string>& codecs, 106 std::vector<std::string>& codecs,
107 ParserFactoryFunction* factory_function, 107 ParserFactoryFunction* factory_function,
108 bool* has_audio, 108 bool* has_audio,
109 bool* has_video) { 109 bool* has_video) {
110 *factory_function = NULL; 110 *factory_function = NULL;
111 *has_audio = false; 111 *has_audio = false;
112 *has_video = false; 112 *has_video = false;
113 113
114 // Search for the SupportedTypeInfo for |type| 114 // Search for the SupportedTypeInfo for |type|.
115 for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) { 115 for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) {
116 const SupportedTypeInfo& type_info = kSupportedTypeInfo[i]; 116 const SupportedTypeInfo& type_info = kSupportedTypeInfo[i];
117 if (type == type_info.type) { 117 if (type == type_info.type) {
118 // Make sure all the codecs specified in |codecs| are 118 // Make sure all the codecs specified in |codecs| are
119 // in the supported type info. 119 // in the supported type info.
120 for (size_t j = 0; j < codecs.size(); ++j) { 120 for (size_t j = 0; j < codecs.size(); ++j) {
121 // Search the type info for a match. 121 // Search the type info for a match.
122 bool found_codec = false; 122 bool found_codec = false;
123 DemuxerStream::Type codec_type = DemuxerStream::UNKNOWN; 123 DemuxerStream::Type codec_type = DemuxerStream::UNKNOWN;
124 124
(...skipping 505 matching lines...) Expand 10 before | Expand all | Expand 10 after
630 scoped_ptr<StreamParser> stream_parser(factory_function(codecs)); 630 scoped_ptr<StreamParser> stream_parser(factory_function(codecs));
631 CHECK(stream_parser.get()); 631 CHECK(stream_parser.get());
632 632
633 stream_parser->Init( 633 stream_parser->Init(
634 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, base::Unretained(this)), 634 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, base::Unretained(this)),
635 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), 635 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this),
636 has_audio, has_video), 636 has_audio, has_video),
637 audio_cb, 637 audio_cb,
638 video_cb, 638 video_cb,
639 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), 639 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)),
640 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id)); 640 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id),
641 base::Bind(&ChunkDemuxer::OnEndOfMediaSegment,
642 base::Unretained(this), id));
641 643
642 stream_parser_map_[id] = stream_parser.release(); 644 stream_parser_map_[id] = stream_parser.release();
645 SourceInfo info = { base::TimeDelta(), true };
646 source_info_map_[id] = info;
643 647
644 return kOk; 648 return kOk;
645 } 649 }
646 650
647 void ChunkDemuxer::RemoveId(const std::string& id) { 651 void ChunkDemuxer::RemoveId(const std::string& id) {
648 CHECK_GT(stream_parser_map_.count(id), 0u); 652 CHECK(IsValidId(id));
649 base::AutoLock auto_lock(lock_); 653 base::AutoLock auto_lock(lock_);
650 654
651 delete stream_parser_map_[id]; 655 delete stream_parser_map_[id];
652 stream_parser_map_.erase(id); 656 stream_parser_map_.erase(id);
657 source_info_map_.erase(id);
653 658
654 if (source_id_audio_ == id && audio_) 659 if (source_id_audio_ == id && audio_)
655 audio_->Shutdown(); 660 audio_->Shutdown();
656 661
657 if (source_id_video_ == id && video_) 662 if (source_id_video_ == id && video_)
658 video_->Shutdown(); 663 video_->Shutdown();
659 } 664 }
660 665
661 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { 666 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const {
662 DCHECK(!id.empty()); 667 DCHECK(!id.empty());
663 DCHECK_GT(stream_parser_map_.count(id), 0u); 668 DCHECK(IsValidId(id));
664 DCHECK(id == source_id_audio_ || id == source_id_video_); 669 DCHECK(id == source_id_audio_ || id == source_id_video_);
665 670
666 base::AutoLock auto_lock(lock_); 671 base::AutoLock auto_lock(lock_);
667 672
668 if (id == source_id_audio_ && id != source_id_video_) { 673 if (id == source_id_audio_ && id != source_id_video_) {
669 // Only include ranges that have been buffered in |audio_| 674 // Only include ranges that have been buffered in |audio_|
670 return audio_ ? audio_->GetBufferedRanges() : Ranges<TimeDelta>(); 675 return audio_ ? audio_->GetBufferedRanges() : Ranges<TimeDelta>();
671 } 676 }
672 677
673 if (id != source_id_audio_ && id == source_id_video_) { 678 if (id != source_id_audio_ && id == source_id_video_) {
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
723 PipelineStatusCB cb; 728 PipelineStatusCB cb;
724 { 729 {
725 base::AutoLock auto_lock(lock_); 730 base::AutoLock auto_lock(lock_);
726 731
727 // Capture if the SourceBuffer has a pending seek before we start parsing. 732 // Capture if the SourceBuffer has a pending seek before we start parsing.
728 bool old_seek_pending = IsSeekPending_Locked(); 733 bool old_seek_pending = IsSeekPending_Locked();
729 734
730 switch (state_) { 735 switch (state_) {
731 case INITIALIZING: 736 case INITIALIZING:
732 case WAITING_FOR_START_TIME: 737 case WAITING_FOR_START_TIME:
733 DCHECK_GT(stream_parser_map_.count(id), 0u); 738 DCHECK(IsValidId(id));
734 if (!stream_parser_map_[id]->Parse(data, length)) { 739 if (!stream_parser_map_[id]->Parse(data, length)) {
735 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 740 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
736 return true; 741 return true;
737 } 742 }
738 break; 743 break;
739 744
740 case INITIALIZED: { 745 case INITIALIZED: {
741 DCHECK_GT(stream_parser_map_.count(id), 0u); 746 DCHECK(IsValidId(id));
742 if (!stream_parser_map_[id]->Parse(data, length)) { 747 if (!stream_parser_map_[id]->Parse(data, length)) {
743 ReportError_Locked(PIPELINE_ERROR_DECODE); 748 ReportError_Locked(PIPELINE_ERROR_DECODE);
744 return true; 749 return true;
745 } 750 }
746 } break; 751 } break;
747 752
748 case WAITING_FOR_INIT: 753 case WAITING_FOR_INIT:
749 case ENDED: 754 case ENDED:
750 case PARSE_ERROR: 755 case PARSE_ERROR:
751 case SHUTDOWN: 756 case SHUTDOWN:
(...skipping 21 matching lines...) Expand all
773 778
774 if (!cb.is_null()) 779 if (!cb.is_null())
775 cb.Run(PIPELINE_OK); 780 cb.Run(PIPELINE_OK);
776 781
777 return true; 782 return true;
778 } 783 }
779 784
780 void ChunkDemuxer::Abort(const std::string& id) { 785 void ChunkDemuxer::Abort(const std::string& id) {
781 DVLOG(1) << "Abort(" << id << ")"; 786 DVLOG(1) << "Abort(" << id << ")";
782 DCHECK(!id.empty()); 787 DCHECK(!id.empty());
783 DCHECK_GT(stream_parser_map_.count(id), 0u); 788 CHECK(IsValidId(id));
784 789
785 stream_parser_map_[id]->Flush(); 790 stream_parser_map_[id]->Flush();
786 } 791 }
787 792
793 bool ChunkDemuxer::SetTimestampOffset(const std::string& id, double offset) {
794 DVLOG(1) << "SetTimestampOffset(" << id << ", " << offset << ")";
795 CHECK(IsValidId(id));
796
797 if (!source_info_map_[id].can_update_offset)
798 return false;
799
800 TimeDelta time_offset = TimeDelta::FromMicroseconds(
801 offset * base::Time::kMicrosecondsPerSecond);
802 source_info_map_[id].timestamp_offset = time_offset;
803 return true;
804 }
805
788 bool ChunkDemuxer::EndOfStream(PipelineStatus status) { 806 bool ChunkDemuxer::EndOfStream(PipelineStatus status) {
789 DVLOG(1) << "EndOfStream(" << status << ")"; 807 DVLOG(1) << "EndOfStream(" << status << ")";
790 base::AutoLock auto_lock(lock_); 808 base::AutoLock auto_lock(lock_);
791 DCHECK_NE(state_, WAITING_FOR_INIT); 809 DCHECK_NE(state_, WAITING_FOR_INIT);
792 DCHECK_NE(state_, ENDED); 810 DCHECK_NE(state_, ENDED);
793 811
794 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) 812 if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
795 return true; 813 return true;
796 814
797 if (state_ == INITIALIZING) { 815 if (state_ == INITIALIZING) {
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
976 return success; 994 return success;
977 } 995 }
978 996
979 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { 997 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) {
980 lock_.AssertAcquired(); 998 lock_.AssertAcquired();
981 DCHECK_NE(state_, SHUTDOWN); 999 DCHECK_NE(state_, SHUTDOWN);
982 1000
983 if (!audio_) 1001 if (!audio_)
984 return false; 1002 return false;
985 1003
1004 CHECK(IsValidId(source_id_audio_));
1005 AdjustBufferTimestamps(
1006 buffers, source_info_map_[source_id_audio_].timestamp_offset);
1007
986 return audio_->Append(buffers); 1008 return audio_->Append(buffers);
987 } 1009 }
988 1010
989 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { 1011 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) {
990 lock_.AssertAcquired(); 1012 lock_.AssertAcquired();
991 DCHECK_NE(state_, SHUTDOWN); 1013 DCHECK_NE(state_, SHUTDOWN);
992 1014
993 if (!video_) 1015 if (!video_)
994 return false; 1016 return false;
995 1017
1018 CHECK(IsValidId(source_id_video_));
1019 AdjustBufferTimestamps(
1020 buffers, source_info_map_[source_id_video_].timestamp_offset);
1021
996 return video_->Append(buffers); 1022 return video_->Append(buffers);
997 } 1023 }
998 1024
999 bool ChunkDemuxer::OnNeedKey(scoped_array<uint8> init_data, 1025 bool ChunkDemuxer::OnNeedKey(scoped_array<uint8> init_data,
1000 int init_data_size) { 1026 int init_data_size) {
1001 client_->DemuxerNeedKey(init_data.Pass(), init_data_size); 1027 client_->DemuxerNeedKey(init_data.Pass(), init_data_size);
1002 return true; 1028 return true;
1003 } 1029 }
1004 1030
1005 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, 1031 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id,
1006 TimeDelta start_timestamp) { 1032 TimeDelta timestamp) {
1007 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", " 1033 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", "
1008 << start_timestamp.InSecondsF() << ")"; 1034 << timestamp.InSecondsF() << ")";
1009 lock_.AssertAcquired(); 1035 lock_.AssertAcquired();
1010 1036
1037 CHECK(IsValidId(source_id));
1038 source_info_map_[source_id].can_update_offset = false;
1039 base::TimeDelta start_timestamp =
1040 timestamp + source_info_map_[source_id].timestamp_offset;
1041
1011 if (start_time_ == kNoTimestamp()) { 1042 if (start_time_ == kNoTimestamp()) {
1012 DCHECK(state_ == INITIALIZING || state_ == WAITING_FOR_START_TIME); 1043 DCHECK(state_ == INITIALIZING || state_ == WAITING_FOR_START_TIME);
1013 // Use the first reported media segment start time as the |start_time_| 1044 // Use the first reported media segment start time as the |start_time_|
1014 // for the demuxer. 1045 // for the demuxer.
1015 start_time_ = start_timestamp; 1046 start_time_ = start_timestamp;
1016 } 1047 }
1017 1048
1018 if (audio_ && source_id == source_id_audio_) 1049 if (audio_ && source_id == source_id_audio_)
1019 audio_->OnNewMediaSegment(start_timestamp); 1050 audio_->OnNewMediaSegment(start_timestamp);
1020 if (video_ && source_id == source_id_video_) 1051 if (video_ && source_id == source_id_video_)
1021 video_->OnNewMediaSegment(start_timestamp); 1052 video_->OnNewMediaSegment(start_timestamp);
1022 1053
1023 if (state_ != WAITING_FOR_START_TIME) 1054 if (state_ != WAITING_FOR_START_TIME)
1024 return; 1055 return;
1025 1056
1026 if (audio_) { 1057 if (audio_) {
1027 audio_->SetStartTime(start_time_); 1058 audio_->SetStartTime(start_time_);
1028 audio_->Seek(start_time_); 1059 audio_->Seek(start_time_);
1029 } 1060 }
1030 if (video_) { 1061 if (video_) {
1031 video_->SetStartTime(start_time_); 1062 video_->SetStartTime(start_time_);
1032 video_->Seek(start_time_); 1063 video_->Seek(start_time_);
1033 } 1064 }
1034 1065
1035 // The demuxer is now initialized after the |start_timestamp_| was set. 1066 // The demuxer is now initialized after the |start_timestamp_| was set.
1036 ChangeState_Locked(INITIALIZED); 1067 ChangeState_Locked(INITIALIZED);
1037 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); 1068 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
1038 } 1069 }
1039 1070
1071 void ChunkDemuxer::OnEndOfMediaSegment(const std::string& source_id) {
1072 DVLOG(2) << "OnEndOfMediaSegment(" << source_id << ")";
1073 CHECK(IsValidId(source_id));
1074 source_info_map_[source_id].can_update_offset = true;
1075 }
1076
1077 void ChunkDemuxer::AdjustBufferTimestamps(
1078 const StreamParser::BufferQueue& buffers,
1079 base::TimeDelta timestamp_offset) {
1080 if (timestamp_offset == base::TimeDelta())
1081 return;
1082
1083 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin();
1084 itr != buffers.end(); ++itr) {
1085 (*itr)->SetDecodeTimestamp(
1086 (*itr)->GetDecodeTimestamp() + timestamp_offset);
1087 (*itr)->SetTimestamp((*itr)->GetTimestamp() + timestamp_offset);
1088 }
1089 }
1090
1091 bool ChunkDemuxer::IsValidId(const std::string& source_id) const {
1092 return source_info_map_.count(source_id) > 0u &&
1093 stream_parser_map_.count(source_id) > 0u;
1094 }
1095
1040 } // namespace media 1096 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/filters/chunk_demuxer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698