OLD | NEW |
---|---|
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 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
92 // and |has_video| are undefined. | 92 // and |has_video| are undefined. |
93 static bool IsSupported(const std::string& type, | 93 static bool IsSupported(const std::string& type, |
94 std::vector<std::string>& codecs, | 94 std::vector<std::string>& codecs, |
95 ParserFactoryFunction* factory_function, | 95 ParserFactoryFunction* factory_function, |
96 bool* has_audio, | 96 bool* has_audio, |
97 bool* has_video) { | 97 bool* has_video) { |
98 *factory_function = NULL; | 98 *factory_function = NULL; |
99 *has_audio = false; | 99 *has_audio = false; |
100 *has_video = false; | 100 *has_video = false; |
101 | 101 |
102 // Search for the SupportedTypeInfo for |type| | 102 // Search for the SupportedTypeInfo for |type|. |
103 for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) { | 103 for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) { |
104 const SupportedTypeInfo& type_info = kSupportedTypeInfo[i]; | 104 const SupportedTypeInfo& type_info = kSupportedTypeInfo[i]; |
105 if (type == type_info.type) { | 105 if (type == type_info.type) { |
106 // Make sure all the codecs specified in |codecs| are | 106 // Make sure all the codecs specified in |codecs| are |
107 // in the supported type info. | 107 // in the supported type info. |
108 for (size_t j = 0; j < codecs.size(); ++j) { | 108 for (size_t j = 0; j < codecs.size(); ++j) { |
109 // Search the type info for a match. | 109 // Search the type info for a match. |
110 bool found_codec = false; | 110 bool found_codec = false; |
111 DemuxerStream::Type codec_type = DemuxerStream::UNKNOWN; | 111 DemuxerStream::Type codec_type = DemuxerStream::UNKNOWN; |
112 | 112 |
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
458 | 458 |
459 scoped_refptr<StreamParserBuffer> buffer; | 459 scoped_refptr<StreamParserBuffer> buffer; |
460 while (!read_cbs_.empty()) { | 460 while (!read_cbs_.empty()) { |
461 if (!stream_->GetNextBuffer(&buffer)) | 461 if (!stream_->GetNextBuffer(&buffer)) |
462 return; | 462 return; |
463 closures->push_back(base::Bind(read_cbs_.front(), buffer)); | 463 closures->push_back(base::Bind(read_cbs_.front(), buffer)); |
464 read_cbs_.pop_front(); | 464 read_cbs_.pop_front(); |
465 } | 465 } |
466 } | 466 } |
467 | 467 |
468 void ChunkDemuxer::AdjustBufferTimestamps( | |
469 const StreamParser::BufferQueue& buffers, | |
470 base::TimeDelta timestamp_offset) { | |
471 if (timestamp_offset == base::TimeDelta()) | |
472 return; | |
473 | |
474 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); | |
475 itr != buffers.end(); ++itr) { | |
476 (*itr)->SetDecodeTimestamp( | |
477 (*itr)->GetDecodeTimestamp() + timestamp_offset); | |
478 (*itr)->SetTimestamp((*itr)->GetTimestamp() + timestamp_offset); | |
479 } | |
480 } | |
481 | |
468 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) | 482 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) |
469 : state_(WAITING_FOR_INIT), | 483 : state_(WAITING_FOR_INIT), |
470 host_(NULL), | 484 host_(NULL), |
471 client_(client), | 485 client_(client), |
472 start_time_(kNoTimestamp()) { | 486 start_time_(kNoTimestamp()) { |
473 DCHECK(client); | 487 DCHECK(client); |
474 } | 488 } |
475 | 489 |
476 void ChunkDemuxer::Initialize(DemuxerHost* host, | 490 void ChunkDemuxer::Initialize(DemuxerHost* host, |
477 const PipelineStatusCB& cb) { | 491 const PipelineStatusCB& cb) { |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
604 scoped_ptr<StreamParser> stream_parser(factory_function()); | 618 scoped_ptr<StreamParser> stream_parser(factory_function()); |
605 CHECK(stream_parser.get()); | 619 CHECK(stream_parser.get()); |
606 | 620 |
607 stream_parser->Init( | 621 stream_parser->Init( |
608 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, this), | 622 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, this), |
609 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), | 623 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), |
610 has_audio, has_video), | 624 has_audio, has_video), |
611 audio_cb, | 625 audio_cb, |
612 video_cb, | 626 video_cb, |
613 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), | 627 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), |
614 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id)); | 628 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id), |
629 base::Bind(&ChunkDemuxer::OnEndOfMediaSegment, | |
630 base::Unretained(this), id)); | |
615 | 631 |
616 stream_parser_map_[id] = stream_parser.release(); | 632 stream_parser_map_[id] = stream_parser.release(); |
633 StreamInfo info = { base::TimeDelta(), true }; | |
634 stream_info_map_[id] = info; | |
617 | 635 |
618 return kOk; | 636 return kOk; |
619 } | 637 } |
620 | 638 |
621 void ChunkDemuxer::RemoveId(const std::string& id) { | 639 void ChunkDemuxer::RemoveId(const std::string& id) { |
622 CHECK_GT(stream_parser_map_.count(id), 0u); | 640 CHECK_GT(stream_parser_map_.count(id), 0u); |
623 base::AutoLock auto_lock(lock_); | 641 base::AutoLock auto_lock(lock_); |
624 | 642 |
625 delete stream_parser_map_[id]; | 643 delete stream_parser_map_[id]; |
626 stream_parser_map_.erase(id); | 644 stream_parser_map_.erase(id); |
645 stream_info_map_.erase(id); | |
627 | 646 |
628 if (source_id_audio_ == id && audio_) | 647 if (source_id_audio_ == id && audio_) |
629 audio_->Shutdown(); | 648 audio_->Shutdown(); |
630 | 649 |
631 if (source_id_video_ == id && video_) | 650 if (source_id_video_ == id && video_) |
632 video_->Shutdown(); | 651 video_->Shutdown(); |
633 } | 652 } |
634 | 653 |
635 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { | 654 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { |
636 DCHECK(!id.empty()); | 655 DCHECK(!id.empty()); |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
752 } | 771 } |
753 | 772 |
754 void ChunkDemuxer::Abort(const std::string& id) { | 773 void ChunkDemuxer::Abort(const std::string& id) { |
755 DVLOG(1) << "Abort(" << id << ")"; | 774 DVLOG(1) << "Abort(" << id << ")"; |
756 DCHECK(!id.empty()); | 775 DCHECK(!id.empty()); |
757 DCHECK_GT(stream_parser_map_.count(id), 0u); | 776 DCHECK_GT(stream_parser_map_.count(id), 0u); |
758 | 777 |
759 stream_parser_map_[id]->Flush(); | 778 stream_parser_map_[id]->Flush(); |
760 } | 779 } |
761 | 780 |
781 bool ChunkDemuxer::TimestampOffset(const std::string& id, float offset) { | |
782 DVLOG(1) << "TimestampOffset(" << id << ", " << offset << ")"; | |
783 DCHECK_GT(stream_parser_map_.count(id), 0u); | |
784 | |
785 TimeDelta time_offset = TimeDelta::FromMicroseconds( | |
786 offset * base::Time::kMicrosecondsPerSecond); | |
787 | |
788 if (!stream_info_map_[id].can_update_offset) | |
789 return false; | |
790 | |
791 stream_info_map_[id].timestamp_offset = time_offset; | |
792 return true; | |
793 } | |
794 | |
762 bool ChunkDemuxer::EndOfStream(PipelineStatus status) { | 795 bool ChunkDemuxer::EndOfStream(PipelineStatus status) { |
763 DVLOG(1) << "EndOfStream(" << status << ")"; | 796 DVLOG(1) << "EndOfStream(" << status << ")"; |
764 base::AutoLock auto_lock(lock_); | 797 base::AutoLock auto_lock(lock_); |
765 DCHECK_NE(state_, WAITING_FOR_INIT); | 798 DCHECK_NE(state_, WAITING_FOR_INIT); |
766 DCHECK_NE(state_, ENDED); | 799 DCHECK_NE(state_, ENDED); |
767 | 800 |
768 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) | 801 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) |
769 return true; | 802 return true; |
770 | 803 |
771 if (state_ == INITIALIZING) { | 804 if (state_ == INITIALIZING) { |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
956 return success; | 989 return success; |
957 } | 990 } |
958 | 991 |
959 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { | 992 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { |
960 lock_.AssertAcquired(); | 993 lock_.AssertAcquired(); |
961 DCHECK_NE(state_, SHUTDOWN); | 994 DCHECK_NE(state_, SHUTDOWN); |
962 | 995 |
963 if (!audio_) | 996 if (!audio_) |
964 return false; | 997 return false; |
965 | 998 |
999 CHECK_GT(stream_info_map_.count(source_id_audio_), 0u); | |
1000 AdjustBufferTimestamps( | |
1001 buffers, stream_info_map_[source_id_audio_].timestamp_offset); | |
1002 stream_info_map_[source_id_video_].can_update_offset = false; | |
acolwell GONE FROM CHROMIUM
2012/07/20 18:21:01
did you mean source_id_audio_ here?
vrk (LEFT CHROMIUM)
2012/07/25 17:16:48
d'oh. Yes :) My test page only uses video, so I di
| |
1003 | |
966 return audio_->Append(buffers); | 1004 return audio_->Append(buffers); |
967 } | 1005 } |
968 | 1006 |
969 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { | 1007 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { |
970 lock_.AssertAcquired(); | 1008 lock_.AssertAcquired(); |
971 DCHECK_NE(state_, SHUTDOWN); | 1009 DCHECK_NE(state_, SHUTDOWN); |
972 | 1010 |
973 if (!video_) | 1011 if (!video_) |
974 return false; | 1012 return false; |
975 | 1013 |
1014 CHECK_GT(stream_info_map_.count(source_id_video_), 0u); | |
1015 AdjustBufferTimestamps( | |
1016 buffers, stream_info_map_[source_id_video_].timestamp_offset); | |
1017 stream_info_map_[source_id_video_].can_update_offset = false; | |
acolwell GONE FROM CHROMIUM
2012/07/20 18:21:01
Perhaps move this to OnNewMediaSegment()? That way
vrk (LEFT CHROMIUM)
2012/07/25 17:16:48
Done and removed from OnAudioBuffers() as well.
| |
1018 | |
976 return video_->Append(buffers); | 1019 return video_->Append(buffers); |
977 } | 1020 } |
978 | 1021 |
979 bool ChunkDemuxer::OnNeedKey(scoped_array<uint8> init_data, | 1022 bool ChunkDemuxer::OnNeedKey(scoped_array<uint8> init_data, |
980 int init_data_size) { | 1023 int init_data_size) { |
981 client_->DemuxerNeedKey(init_data.Pass(), init_data_size); | 1024 client_->DemuxerNeedKey(init_data.Pass(), init_data_size); |
982 return true; | 1025 return true; |
983 } | 1026 } |
984 | 1027 |
985 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, | 1028 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, |
986 TimeDelta start_timestamp) { | 1029 TimeDelta timestamp) { |
987 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", " | 1030 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", " |
988 << start_timestamp.InSecondsF() << ")"; | 1031 << timestamp.InSecondsF() << ")"; |
989 lock_.AssertAcquired(); | 1032 lock_.AssertAcquired(); |
990 | 1033 |
1034 CHECK_GT(stream_info_map_.count(source_id), 0u); | |
1035 base::TimeDelta start_timestamp = | |
1036 timestamp + stream_info_map_[source_id].timestamp_offset; | |
1037 | |
991 if (start_time_ == kNoTimestamp()) { | 1038 if (start_time_ == kNoTimestamp()) { |
992 DCHECK(state_ == INITIALIZING || state_ == WAITING_FOR_START_TIME); | 1039 DCHECK(state_ == INITIALIZING || state_ == WAITING_FOR_START_TIME); |
993 // Use the first reported media segment start time as the |start_time_| | 1040 // Use the first reported media segment start time as the |start_time_| |
994 // for the demuxer. | 1041 // for the demuxer. |
995 start_time_ = start_timestamp; | 1042 start_time_ = start_timestamp; |
996 } | 1043 } |
997 | 1044 |
998 if (audio_ && source_id == source_id_audio_) | 1045 if (audio_ && source_id == source_id_audio_) |
999 audio_->OnNewMediaSegment(start_timestamp); | 1046 audio_->OnNewMediaSegment(start_timestamp); |
1000 if (video_ && source_id == source_id_video_) | 1047 if (video_ && source_id == source_id_video_) |
1001 video_->OnNewMediaSegment(start_timestamp); | 1048 video_->OnNewMediaSegment(start_timestamp); |
1002 | 1049 |
1003 if (state_ != WAITING_FOR_START_TIME) | 1050 if (state_ != WAITING_FOR_START_TIME) |
1004 return; | 1051 return; |
1005 | 1052 |
1006 if (audio_) { | 1053 if (audio_) { |
1007 audio_->SetStartTime(start_time_); | 1054 audio_->SetStartTime(start_time_); |
1008 audio_->Seek(start_time_); | 1055 audio_->Seek(start_time_); |
1009 } | 1056 } |
1010 if (video_) { | 1057 if (video_) { |
1011 video_->SetStartTime(start_time_); | 1058 video_->SetStartTime(start_time_); |
1012 video_->Seek(start_time_); | 1059 video_->Seek(start_time_); |
1013 } | 1060 } |
1014 | 1061 |
1015 // The demuxer is now initialized after the |start_timestamp_| was set. | 1062 // The demuxer is now initialized after the |start_timestamp_| was set. |
1016 ChangeState_Locked(INITIALIZED); | 1063 ChangeState_Locked(INITIALIZED); |
1017 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 1064 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
1018 } | 1065 } |
1019 | 1066 |
1067 void ChunkDemuxer::OnEndOfMediaSegment(const std::string& source_id) { | |
1068 DVLOG(2) << "OnEndOfMediaSegment(" << source_id << ")"; | |
1069 CHECK_GT(stream_info_map_.count(source_id_video_), 0u); | |
1070 stream_info_map_[source_id_video_].can_update_offset = true; | |
1071 } | |
1072 | |
1020 } // namespace media | 1073 } // namespace media |
OLD | NEW |