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 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
492 } | 492 } |
493 | 493 |
494 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) | 494 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) |
495 : state_(WAITING_FOR_INIT), | 495 : state_(WAITING_FOR_INIT), |
496 host_(NULL), | 496 host_(NULL), |
497 client_(client), | 497 client_(client), |
498 start_time_(kNoTimestamp()) { | 498 start_time_(kNoTimestamp()) { |
499 DCHECK(client); | 499 DCHECK(client); |
500 } | 500 } |
501 | 501 |
502 void ChunkDemuxer::Initialize(DemuxerHost* host, | 502 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) { |
503 const PipelineStatusCB& cb) { | |
504 DVLOG(1) << "Init()"; | 503 DVLOG(1) << "Init()"; |
505 { | 504 { |
506 base::AutoLock auto_lock(lock_); | 505 base::AutoLock auto_lock(lock_); |
507 DCHECK_EQ(state_, WAITING_FOR_INIT); | 506 DCHECK_EQ(state_, WAITING_FOR_INIT); |
508 host_ = host; | 507 host_ = host; |
509 | 508 |
510 ChangeState_Locked(INITIALIZING); | 509 ChangeState_Locked(INITIALIZING); |
511 init_cb_ = cb; | 510 init_cb_ = cb; |
512 } | 511 } |
513 | 512 |
(...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
930 void ChunkDemuxer::OnStreamParserInitDone(bool success, TimeDelta duration) { | 929 void ChunkDemuxer::OnStreamParserInitDone(bool success, TimeDelta duration) { |
931 DVLOG(1) << "OnStreamParserInitDone(" << success << ", " | 930 DVLOG(1) << "OnStreamParserInitDone(" << success << ", " |
932 << duration.InSecondsF() << ")"; | 931 << duration.InSecondsF() << ")"; |
933 lock_.AssertAcquired(); | 932 lock_.AssertAcquired(); |
934 DCHECK_EQ(state_, INITIALIZING); | 933 DCHECK_EQ(state_, INITIALIZING); |
935 if (!success || (!audio_ && !video_)) { | 934 if (!success || (!audio_ && !video_)) { |
936 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); | 935 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
937 return; | 936 return; |
938 } | 937 } |
939 | 938 |
940 if (duration > duration_) | 939 if (duration != base::TimeDelta() && duration_ == base::TimeDelta()) |
941 duration_ = duration; | 940 UpdateDuration(duration); |
942 | 941 |
943 // Wait until all streams have initialized. | 942 // Wait until all streams have initialized. |
944 if ((!source_id_audio_.empty() && !audio_) || | 943 if ((!source_id_audio_.empty() && !audio_) || |
945 (!source_id_video_.empty() && !video_)) | 944 (!source_id_video_.empty() && !video_)) |
946 return; | 945 return; |
947 | 946 |
948 host_->SetDuration(duration_); | |
949 | |
950 ChangeState_Locked(WAITING_FOR_START_TIME); | 947 ChangeState_Locked(WAITING_FOR_START_TIME); |
951 } | 948 } |
952 | 949 |
953 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video, | 950 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video, |
954 const AudioDecoderConfig& audio_config, | 951 const AudioDecoderConfig& audio_config, |
955 const VideoDecoderConfig& video_config) { | 952 const VideoDecoderConfig& video_config) { |
956 DVLOG(1) << "OnNewConfigs(" << has_audio << ", " << has_video | 953 DVLOG(1) << "OnNewConfigs(" << has_audio << ", " << has_video |
957 << ", " << audio_config.IsValidConfig() | 954 << ", " << audio_config.IsValidConfig() |
958 << ", " << video_config.IsValidConfig() << ")"; | 955 << ", " << video_config.IsValidConfig() << ")"; |
959 CHECK(audio_config.IsValidConfig() || video_config.IsValidConfig()); | 956 CHECK(audio_config.IsValidConfig() || video_config.IsValidConfig()); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
998 lock_.AssertAcquired(); | 995 lock_.AssertAcquired(); |
999 DCHECK_NE(state_, SHUTDOWN); | 996 DCHECK_NE(state_, SHUTDOWN); |
1000 | 997 |
1001 if (!audio_) | 998 if (!audio_) |
1002 return false; | 999 return false; |
1003 | 1000 |
1004 CHECK(IsValidId(source_id_audio_)); | 1001 CHECK(IsValidId(source_id_audio_)); |
1005 AdjustBufferTimestamps( | 1002 AdjustBufferTimestamps( |
1006 buffers, source_info_map_[source_id_audio_].timestamp_offset); | 1003 buffers, source_info_map_[source_id_audio_].timestamp_offset); |
1007 | 1004 |
1008 return audio_->Append(buffers); | 1005 if (!audio_->Append(buffers)) |
| 1006 return false; |
| 1007 |
| 1008 IncreaseDurationIfNecessary(buffers, audio_); |
| 1009 return true; |
1009 } | 1010 } |
1010 | 1011 |
1011 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { | 1012 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { |
1012 lock_.AssertAcquired(); | 1013 lock_.AssertAcquired(); |
1013 DCHECK_NE(state_, SHUTDOWN); | 1014 DCHECK_NE(state_, SHUTDOWN); |
1014 | 1015 |
1015 if (!video_) | 1016 if (!video_) |
1016 return false; | 1017 return false; |
1017 | 1018 |
1018 CHECK(IsValidId(source_id_video_)); | 1019 CHECK(IsValidId(source_id_video_)); |
1019 AdjustBufferTimestamps( | 1020 AdjustBufferTimestamps( |
1020 buffers, source_info_map_[source_id_video_].timestamp_offset); | 1021 buffers, source_info_map_[source_id_video_].timestamp_offset); |
1021 | 1022 |
1022 return video_->Append(buffers); | 1023 if (!video_->Append(buffers)) |
| 1024 return false; |
| 1025 |
| 1026 IncreaseDurationIfNecessary(buffers, video_); |
| 1027 return true; |
1023 } | 1028 } |
1024 | 1029 |
1025 bool ChunkDemuxer::OnNeedKey(scoped_array<uint8> init_data, | 1030 bool ChunkDemuxer::OnNeedKey(scoped_array<uint8> init_data, |
1026 int init_data_size) { | 1031 int init_data_size) { |
1027 client_->DemuxerNeedKey(init_data.Pass(), init_data_size); | 1032 client_->DemuxerNeedKey(init_data.Pass(), init_data_size); |
1028 return true; | 1033 return true; |
1029 } | 1034 } |
1030 | 1035 |
1031 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, | 1036 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, |
1032 TimeDelta timestamp) { | 1037 TimeDelta timestamp) { |
1033 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", " | 1038 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", " |
1034 << timestamp.InSecondsF() << ")"; | 1039 << timestamp.InSecondsF() << ")"; |
1035 lock_.AssertAcquired(); | 1040 lock_.AssertAcquired(); |
1036 | 1041 |
1037 CHECK(IsValidId(source_id)); | 1042 CHECK(IsValidId(source_id)); |
1038 source_info_map_[source_id].can_update_offset = false; | 1043 source_info_map_[source_id].can_update_offset = false; |
1039 base::TimeDelta start_timestamp = | 1044 base::TimeDelta start_timestamp = |
1040 timestamp + source_info_map_[source_id].timestamp_offset; | 1045 timestamp + source_info_map_[source_id].timestamp_offset; |
1041 | 1046 |
1042 if (start_time_ == kNoTimestamp()) { | 1047 if (start_time_ == kNoTimestamp()) { |
1043 DCHECK(state_ == INITIALIZING || state_ == WAITING_FOR_START_TIME); | 1048 DCHECK(state_ == INITIALIZING || state_ == WAITING_FOR_START_TIME); |
1044 // Use the first reported media segment start time as the |start_time_| | 1049 // Use the first reported media segment start time as the |start_time_| |
1045 // for the demuxer. | 1050 // for the demuxer. |
1046 start_time_ = start_timestamp; | 1051 start_time_ = start_timestamp; |
| 1052 |
| 1053 // Ensure |duration_| is never before |start_time_|. |
| 1054 // TODO(vrk): We have to do this because there are places in the code that |
| 1055 // assumes the media duration is the same as the end time of the media |
| 1056 // stream. Fix this once crbug.com/137275 is addressed. |
| 1057 if (start_time_ > duration_) |
| 1058 UpdateDuration(start_time_); |
1047 } | 1059 } |
1048 | 1060 |
1049 if (audio_ && source_id == source_id_audio_) | 1061 if (audio_ && source_id == source_id_audio_) |
1050 audio_->OnNewMediaSegment(start_timestamp); | 1062 audio_->OnNewMediaSegment(start_timestamp); |
1051 if (video_ && source_id == source_id_video_) | 1063 if (video_ && source_id == source_id_video_) |
1052 video_->OnNewMediaSegment(start_timestamp); | 1064 video_->OnNewMediaSegment(start_timestamp); |
1053 | 1065 |
1054 if (state_ != WAITING_FOR_START_TIME) | 1066 if (state_ != WAITING_FOR_START_TIME) |
1055 return; | 1067 return; |
1056 | 1068 |
1057 if (audio_) { | 1069 if (audio_) { |
1058 audio_->SetStartTime(start_time_); | 1070 audio_->SetStartTime(start_time_); |
1059 audio_->Seek(start_time_); | 1071 audio_->Seek(start_time_); |
1060 } | 1072 } |
1061 if (video_) { | 1073 if (video_) { |
1062 video_->SetStartTime(start_time_); | 1074 video_->SetStartTime(start_time_); |
1063 video_->Seek(start_time_); | 1075 video_->Seek(start_time_); |
1064 } | 1076 } |
1065 | 1077 |
| 1078 if (duration_ == base::TimeDelta()) |
| 1079 duration_ = kInfiniteDuration(); |
| 1080 |
1066 // The demuxer is now initialized after the |start_timestamp_| was set. | 1081 // The demuxer is now initialized after the |start_timestamp_| was set. |
1067 ChangeState_Locked(INITIALIZED); | 1082 ChangeState_Locked(INITIALIZED); |
1068 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 1083 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
1069 } | 1084 } |
1070 | 1085 |
1071 void ChunkDemuxer::OnEndOfMediaSegment(const std::string& source_id) { | 1086 void ChunkDemuxer::OnEndOfMediaSegment(const std::string& source_id) { |
1072 DVLOG(2) << "OnEndOfMediaSegment(" << source_id << ")"; | 1087 DVLOG(2) << "OnEndOfMediaSegment(" << source_id << ")"; |
1073 CHECK(IsValidId(source_id)); | 1088 CHECK(IsValidId(source_id)); |
1074 source_info_map_[source_id].can_update_offset = true; | 1089 source_info_map_[source_id].can_update_offset = true; |
1075 } | 1090 } |
(...skipping 10 matching lines...) Expand all Loading... |
1086 (*itr)->GetDecodeTimestamp() + timestamp_offset); | 1101 (*itr)->GetDecodeTimestamp() + timestamp_offset); |
1087 (*itr)->SetTimestamp((*itr)->GetTimestamp() + timestamp_offset); | 1102 (*itr)->SetTimestamp((*itr)->GetTimestamp() + timestamp_offset); |
1088 } | 1103 } |
1089 } | 1104 } |
1090 | 1105 |
1091 bool ChunkDemuxer::IsValidId(const std::string& source_id) const { | 1106 bool ChunkDemuxer::IsValidId(const std::string& source_id) const { |
1092 return source_info_map_.count(source_id) > 0u && | 1107 return source_info_map_.count(source_id) > 0u && |
1093 stream_parser_map_.count(source_id) > 0u; | 1108 stream_parser_map_.count(source_id) > 0u; |
1094 } | 1109 } |
1095 | 1110 |
| 1111 void ChunkDemuxer::UpdateDuration(base::TimeDelta new_duration) { |
| 1112 DCHECK(duration_ != new_duration); |
| 1113 duration_ = new_duration; |
| 1114 host_->SetDuration(new_duration); |
| 1115 } |
| 1116 |
| 1117 void ChunkDemuxer::IncreaseDurationIfNecessary( |
| 1118 const StreamParser::BufferQueue& buffers, |
| 1119 const scoped_refptr<ChunkDemuxerStream>& stream) { |
| 1120 DCHECK(!buffers.empty()); |
| 1121 if (buffers.back()->GetTimestamp() <= duration_) |
| 1122 return; |
| 1123 |
| 1124 Ranges<TimeDelta> ranges = stream->GetBufferedRanges(); |
| 1125 DCHECK_GT(ranges.size(), 0u); |
| 1126 |
| 1127 base::TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1); |
| 1128 if (last_timestamp_buffered > duration_) |
| 1129 UpdateDuration(last_timestamp_buffered); |
| 1130 } |
| 1131 |
1096 } // namespace media | 1132 } // namespace media |
OLD | NEW |