Chromium Code Reviews| 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 <algorithm> | 7 #include <algorithm> |
| 8 #include <deque> | 8 #include <deque> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 160 // |type| didn't match any of the supported types. | 160 // |type| didn't match any of the supported types. |
| 161 return false; | 161 return false; |
| 162 } | 162 } |
| 163 | 163 |
| 164 class ChunkDemuxerStream : public DemuxerStream { | 164 class ChunkDemuxerStream : public DemuxerStream { |
| 165 public: | 165 public: |
| 166 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; | 166 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; |
| 167 typedef std::deque<ReadCB> ReadCBQueue; | 167 typedef std::deque<ReadCB> ReadCBQueue; |
| 168 typedef std::deque<base::Closure> ClosureQueue; | 168 typedef std::deque<base::Closure> ClosureQueue; |
| 169 | 169 |
| 170 explicit ChunkDemuxerStream(const AudioDecoderConfig& audio_config); | 170 ChunkDemuxerStream(const AudioDecoderConfig& audio_config, bool is_encrypted); |
| 171 explicit ChunkDemuxerStream(const VideoDecoderConfig& video_config); | 171 ChunkDemuxerStream(const VideoDecoderConfig& video_config, bool is_encrypted); |
| 172 | 172 |
| 173 void StartWaitingForSeek(); | 173 void StartWaitingForSeek(); |
| 174 void Seek(TimeDelta time); | 174 void Seek(TimeDelta time); |
| 175 void CancelPendingSeek(); | 175 void CancelPendingSeek(); |
| 176 bool IsSeekPending() const; | 176 bool IsSeekPending() const; |
| 177 | 177 |
| 178 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, | 178 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, |
| 179 // which handle ordering and overlap resolution. | 179 // which handle ordering and overlap resolution. |
| 180 // Returns true if buffers were successfully added. | 180 // Returns true if buffers were successfully added. |
| 181 bool Append(const StreamParser::BufferQueue& buffers); | 181 bool Append(const StreamParser::BufferQueue& buffers); |
| 182 | 182 |
| 183 // Signal to the stream that duration has changed to |duration|. | 183 // Signal to the stream that duration has changed to |duration|. |
| 184 void OnSetDuration(base::TimeDelta duration); | 184 void OnSetDuration(base::TimeDelta duration); |
| 185 | 185 |
| 186 // Returns the range of buffered data in this stream, capped at |duration|. | 186 // Returns the range of buffered data in this stream, capped at |duration|. |
| 187 Ranges<TimeDelta> GetBufferedRanges(base::TimeDelta duration) const; | 187 Ranges<TimeDelta> GetBufferedRanges(base::TimeDelta duration) const; |
| 188 | 188 |
| 189 // Signal to the stream that buffers handed in through subsequent calls to | 189 // Signal to the stream that buffers handed in through subsequent calls to |
| 190 // Append() belong to a media segment that starts at |start_timestamp|. | 190 // Append() belong to a media segment that starts at |start_timestamp|. |
| 191 void OnNewMediaSegment(TimeDelta start_timestamp); | 191 void OnNewMediaSegment(TimeDelta start_timestamp); |
| 192 | 192 |
| 193 // Called when mid-stream config updates occur. | 193 // Called when mid-stream config updates occur. |
| 194 // Returns true if the new config is accepted. | 194 // Returns true if the new config is accepted. |
| 195 // Returns false if the new config should trigger an error. | 195 // Returns false if the new config should trigger an error. |
| 196 bool UpdateAudioConfig(const AudioDecoderConfig& config); | 196 bool UpdateAudioConfig(const AudioDecoderConfig& config, bool is_encrypted); |
| 197 bool UpdateVideoConfig(const VideoDecoderConfig& config); | 197 bool UpdateVideoConfig(const VideoDecoderConfig& config, bool is_encrypted); |
| 198 | 198 |
| 199 void EndOfStream(); | 199 void EndOfStream(); |
| 200 bool CanEndOfStream() const; | 200 bool CanEndOfStream() const; |
| 201 void Shutdown(); | 201 void Shutdown(); |
| 202 | 202 |
| 203 // DemuxerStream methods. | 203 // DemuxerStream methods. |
| 204 virtual void Read(const ReadCB& read_cb) OVERRIDE; | 204 virtual void Read(const ReadCB& read_cb) OVERRIDE; |
| 205 virtual Type type() OVERRIDE; | 205 virtual Type type() OVERRIDE; |
| 206 virtual void EnableBitstreamConverter() OVERRIDE; | 206 virtual void EnableBitstreamConverter() OVERRIDE; |
| 207 virtual const AudioDecoderConfig& audio_decoder_config() OVERRIDE; | 207 virtual const AudioDecoderConfig& audio_decoder_config() OVERRIDE; |
| 208 virtual const VideoDecoderConfig& video_decoder_config() OVERRIDE; | 208 virtual const VideoDecoderConfig& video_decoder_config() OVERRIDE; |
| 209 virtual bool is_encrypted() OVERRIDE; | |
| 209 | 210 |
| 210 protected: | 211 protected: |
| 211 virtual ~ChunkDemuxerStream(); | 212 virtual ~ChunkDemuxerStream(); |
| 212 | 213 |
| 213 private: | 214 private: |
| 214 enum State { | 215 enum State { |
| 215 RETURNING_DATA_FOR_READS, | 216 RETURNING_DATA_FOR_READS, |
| 216 WAITING_FOR_SEEK, | 217 WAITING_FOR_SEEK, |
| 217 CANCELED, | 218 CANCELED, |
| 218 SHUTDOWN, | 219 SHUTDOWN, |
| 219 }; | 220 }; |
| 220 | 221 |
| 221 // Assigns |state_| to |state| | 222 // Assigns |state_| to |state| |
| 222 void ChangeState_Locked(State state); | 223 void ChangeState_Locked(State state); |
| 223 | 224 |
| 224 // Adds the callback to |read_cbs_| so it can be called later when we | 225 // Adds the callback to |read_cbs_| so it can be called later when we |
| 225 // have data. | 226 // have data. |
| 226 void DeferRead_Locked(const ReadCB& read_cb); | 227 void DeferRead_Locked(const ReadCB& read_cb); |
| 227 | 228 |
| 228 // Creates closures that bind ReadCBs in |read_cbs_| to data in | 229 // Creates closures that bind ReadCBs in |read_cbs_| to data in |
| 229 // |buffers_| and pops the callbacks & buffers from the respecive queues. | 230 // |buffers_| and pops the callbacks & buffers from the respective queues. |
| 230 void CreateReadDoneClosures_Locked(ClosureQueue* closures); | 231 void CreateReadDoneClosures_Locked(ClosureQueue* closures); |
| 231 | 232 |
| 232 // Gets the value to pass to the next Read() callback. Returns true if | 233 // Gets the value to pass to the next Read() callback. Returns true if |
| 233 // |status| and |buffer| should be passed to the callback. False indicates | 234 // |status| and |buffer| should be passed to the callback. False indicates |
| 234 // that |status| and |buffer| were not set and more data is needed. | 235 // that |status| and |buffer| were not set and more data is needed. |
| 235 bool GetNextBuffer_Locked(DemuxerStream::Status* status, | 236 bool GetNextBuffer_Locked(DemuxerStream::Status* status, |
| 236 scoped_refptr<StreamParserBuffer>* buffer); | 237 scoped_refptr<StreamParserBuffer>* buffer); |
| 237 | 238 |
| 238 // Specifies the type of the stream (must be AUDIO or VIDEO for now). | 239 // Specifies the type of the stream (must be AUDIO or VIDEO for now). |
| 239 Type type_; | 240 Type type_; |
| 240 | 241 |
| 241 scoped_ptr<SourceBufferStream> stream_; | 242 scoped_ptr<SourceBufferStream> stream_; |
| 242 | 243 |
| 243 mutable base::Lock lock_; | 244 mutable base::Lock lock_; |
| 244 State state_; | 245 State state_; |
| 245 ReadCBQueue read_cbs_; | 246 ReadCBQueue read_cbs_; |
| 246 bool end_of_stream_; | 247 bool end_of_stream_; |
| 248 bool is_encrypted_; | |
| 247 | 249 |
| 248 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); | 250 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); |
| 249 }; | 251 }; |
| 250 | 252 |
| 251 ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config) | 253 ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config, |
| 254 bool is_encrypted) | |
| 252 : type_(AUDIO), | 255 : type_(AUDIO), |
| 253 state_(RETURNING_DATA_FOR_READS), | 256 state_(RETURNING_DATA_FOR_READS), |
| 254 end_of_stream_(false) { | 257 end_of_stream_(false), |
| 258 is_encrypted_(is_encrypted) { | |
| 255 stream_.reset(new SourceBufferStream(audio_config)); | 259 stream_.reset(new SourceBufferStream(audio_config)); |
| 256 } | 260 } |
| 257 | 261 |
| 258 ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config) | 262 ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config, |
| 263 bool is_encrypted) | |
| 259 : type_(VIDEO), | 264 : type_(VIDEO), |
| 260 state_(RETURNING_DATA_FOR_READS), | 265 state_(RETURNING_DATA_FOR_READS), |
| 261 end_of_stream_(false) { | 266 end_of_stream_(false), |
| 267 is_encrypted_(is_encrypted) { | |
| 262 stream_.reset(new SourceBufferStream(video_config)); | 268 stream_.reset(new SourceBufferStream(video_config)); |
| 263 } | 269 } |
| 264 | 270 |
| 265 void ChunkDemuxerStream::StartWaitingForSeek() { | 271 void ChunkDemuxerStream::StartWaitingForSeek() { |
| 266 DVLOG(1) << "StartWaitingForSeek()"; | 272 DVLOG(1) << "StartWaitingForSeek()"; |
| 267 ReadCBQueue read_cbs; | 273 ReadCBQueue read_cbs; |
| 268 { | 274 { |
| 269 base::AutoLock auto_lock(lock_); | 275 base::AutoLock auto_lock(lock_); |
| 270 ChangeState_Locked(WAITING_FOR_SEEK); | 276 ChangeState_Locked(WAITING_FOR_SEEK); |
| 271 end_of_stream_ = false; | 277 end_of_stream_ = false; |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 351 return range; | 357 return range; |
| 352 | 358 |
| 353 // Clamp the end of the stream's buffered ranges to fit within the duration. | 359 // Clamp the end of the stream's buffered ranges to fit within the duration. |
| 354 // This can be done by intersecting the stream's range with the valid time | 360 // This can be done by intersecting the stream's range with the valid time |
| 355 // range. | 361 // range. |
| 356 Ranges<TimeDelta> valid_time_range; | 362 Ranges<TimeDelta> valid_time_range; |
| 357 valid_time_range.Add(range.start(0), duration); | 363 valid_time_range.Add(range.start(0), duration); |
| 358 return range.IntersectionWith(valid_time_range); | 364 return range.IntersectionWith(valid_time_range); |
| 359 } | 365 } |
| 360 | 366 |
| 361 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config) { | 367 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config, |
| 368 bool is_encrypted) { | |
| 362 DCHECK(config.IsValidConfig()); | 369 DCHECK(config.IsValidConfig()); |
| 363 DCHECK_EQ(type_, AUDIO); | 370 DCHECK_EQ(type_, AUDIO); |
| 371 is_encrypted_ = is_encrypted; | |
|
acolwell GONE FROM CHROMIUM
2012/09/15 00:25:24
This is not correct. It will cause the is_encrypte
| |
| 364 return stream_->UpdateAudioConfig(config); | 372 return stream_->UpdateAudioConfig(config); |
| 365 } | 373 } |
| 366 | 374 |
| 367 bool ChunkDemuxerStream::UpdateVideoConfig(const VideoDecoderConfig& config) { | 375 bool ChunkDemuxerStream::UpdateVideoConfig(const VideoDecoderConfig& config, |
| 376 bool is_encrypted) { | |
| 368 DCHECK(config.IsValidConfig()); | 377 DCHECK(config.IsValidConfig()); |
| 369 DCHECK_EQ(type_, VIDEO); | 378 DCHECK_EQ(type_, VIDEO); |
| 379 is_encrypted_ = is_encrypted; | |
|
acolwell GONE FROM CHROMIUM
2012/09/15 00:25:24
ditto
| |
| 370 return stream_->UpdateVideoConfig(config); | 380 return stream_->UpdateVideoConfig(config); |
| 371 } | 381 } |
| 372 | 382 |
| 373 void ChunkDemuxerStream::EndOfStream() { | 383 void ChunkDemuxerStream::EndOfStream() { |
| 374 ClosureQueue closures; | 384 ClosureQueue closures; |
| 375 { | 385 { |
| 376 base::AutoLock auto_lock(lock_); | 386 base::AutoLock auto_lock(lock_); |
| 377 DCHECK(!end_of_stream_); | 387 DCHECK(!end_of_stream_); |
| 378 DCHECK(stream_->IsEndSelected()); | 388 DCHECK(stream_->IsEndSelected()); |
| 379 end_of_stream_ = true; | 389 end_of_stream_ = true; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 450 } | 460 } |
| 451 | 461 |
| 452 void ChunkDemuxerStream::ChangeState_Locked(State state) { | 462 void ChunkDemuxerStream::ChangeState_Locked(State state) { |
| 453 lock_.AssertAcquired(); | 463 lock_.AssertAcquired(); |
| 454 DVLOG(1) << "ChunkDemuxerStream::ChangeState_Locked() : " | 464 DVLOG(1) << "ChunkDemuxerStream::ChangeState_Locked() : " |
| 455 << "type " << type_ | 465 << "type " << type_ |
| 456 << " - " << state_ << " -> " << state; | 466 << " - " << state_ << " -> " << state; |
| 457 state_ = state; | 467 state_ = state; |
| 458 } | 468 } |
| 459 | 469 |
| 470 bool ChunkDemuxerStream::is_encrypted() { | |
| 471 base::AutoLock auto_lock(lock_); | |
| 472 return is_encrypted_; | |
| 473 } | |
| 474 | |
| 460 ChunkDemuxerStream::~ChunkDemuxerStream() {} | 475 ChunkDemuxerStream::~ChunkDemuxerStream() {} |
| 461 | 476 |
| 462 void ChunkDemuxerStream::DeferRead_Locked(const ReadCB& read_cb) { | 477 void ChunkDemuxerStream::DeferRead_Locked(const ReadCB& read_cb) { |
| 463 lock_.AssertAcquired(); | 478 lock_.AssertAcquired(); |
| 464 // Wrap & store |read_cb| so that it will | 479 // Wrap & store |read_cb| so that it will |
| 465 // get called on the current MessageLoop. | 480 // get called on the current MessageLoop. |
| 466 read_cbs_.push_back(base::Bind(&RunOnMessageLoop, read_cb, | 481 read_cbs_.push_back(base::Bind(&RunOnMessageLoop, read_cb, |
| 467 base::MessageLoopProxy::current())); | 482 base::MessageLoopProxy::current())); |
| 468 } | 483 } |
| 469 | 484 |
| (...skipping 542 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1012 duration_ = kInfiniteDuration(); | 1027 duration_ = kInfiniteDuration(); |
| 1013 | 1028 |
| 1014 // The demuxer is now initialized after the |start_timestamp_| was set. | 1029 // The demuxer is now initialized after the |start_timestamp_| was set. |
| 1015 ChangeState_Locked(INITIALIZED); | 1030 ChangeState_Locked(INITIALIZED); |
| 1016 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 1031 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
| 1017 | 1032 |
| 1018 } | 1033 } |
| 1019 | 1034 |
| 1020 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video, | 1035 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video, |
| 1021 const AudioDecoderConfig& audio_config, | 1036 const AudioDecoderConfig& audio_config, |
| 1022 const VideoDecoderConfig& video_config) { | 1037 const VideoDecoderConfig& video_config, |
| 1038 bool is_audio_encrypted, | |
| 1039 bool is_video_encrypted) { | |
| 1023 DVLOG(1) << "OnNewConfigs(" << has_audio << ", " << has_video | 1040 DVLOG(1) << "OnNewConfigs(" << has_audio << ", " << has_video |
| 1024 << ", " << audio_config.IsValidConfig() | 1041 << ", " << audio_config.IsValidConfig() |
| 1025 << ", " << video_config.IsValidConfig() << ")"; | 1042 << ", " << video_config.IsValidConfig() << ")"; |
| 1026 lock_.AssertAcquired(); | 1043 lock_.AssertAcquired(); |
| 1027 | 1044 |
| 1028 if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { | 1045 if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { |
| 1029 DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; | 1046 DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; |
| 1030 return false; | 1047 return false; |
| 1031 } | 1048 } |
| 1032 | 1049 |
| 1033 // Signal an error if we get configuration info for stream types that weren't | 1050 // Signal an error if we get configuration info for stream types that weren't |
| 1034 // specified in AddId() or more configs after a stream is initialized. | 1051 // specified in AddId() or more configs after a stream is initialized. |
| 1035 // Only allow a single audio config for now. | 1052 // Only allow a single audio config for now. |
| 1036 if (has_audio != audio_config.IsValidConfig()) { | 1053 if (has_audio != audio_config.IsValidConfig()) { |
| 1037 DVLOG(1) << "OnNewConfigs() : Got unexpected audio config."; | 1054 DVLOG(1) << "OnNewConfigs() : Got unexpected audio config."; |
| 1038 return false; | 1055 return false; |
| 1039 } | 1056 } |
| 1040 | 1057 |
| 1041 // Only allow a single video config for now. | 1058 // Only allow a single video config for now. |
| 1042 if (has_video != video_config.IsValidConfig()) { | 1059 if (has_video != video_config.IsValidConfig()) { |
| 1043 DVLOG(1) << "OnNewConfigs() : Got unexpected video config."; | 1060 DVLOG(1) << "OnNewConfigs() : Got unexpected video config."; |
| 1044 return false; | 1061 return false; |
| 1045 } | 1062 } |
| 1046 | 1063 |
| 1047 bool success = true; | 1064 bool success = true; |
| 1048 if (audio_config.IsValidConfig()) { | 1065 if (audio_config.IsValidConfig()) { |
| 1049 if (audio_) { | 1066 if (audio_) { |
| 1050 success &= audio_->UpdateAudioConfig(audio_config); | 1067 success &= audio_->UpdateAudioConfig(audio_config, is_audio_encrypted); |
| 1051 } else { | 1068 } else { |
| 1052 audio_ = new ChunkDemuxerStream(audio_config); | 1069 audio_ = new ChunkDemuxerStream(audio_config, is_audio_encrypted); |
| 1053 } | 1070 } |
| 1054 } | 1071 } |
| 1055 | 1072 |
| 1056 if (video_config.IsValidConfig()) { | 1073 if (video_config.IsValidConfig()) { |
| 1057 if (video_) { | 1074 if (video_) { |
| 1058 success &= video_->UpdateVideoConfig(video_config); | 1075 success &= video_->UpdateVideoConfig(video_config, is_video_encrypted); |
| 1059 } else { | 1076 } else { |
| 1060 video_ = new ChunkDemuxerStream(video_config); | 1077 video_ = new ChunkDemuxerStream(video_config, is_video_encrypted); |
| 1061 } | 1078 } |
| 1062 } | 1079 } |
| 1063 | 1080 |
| 1064 DVLOG(1) << "OnNewConfigs() : success " << success; | 1081 DVLOG(1) << "OnNewConfigs() : success " << success; |
| 1065 return success; | 1082 return success; |
| 1066 } | 1083 } |
| 1067 | 1084 |
| 1068 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { | 1085 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { |
| 1069 lock_.AssertAcquired(); | 1086 lock_.AssertAcquired(); |
| 1070 DCHECK_NE(state_, SHUTDOWN); | 1087 DCHECK_NE(state_, SHUTDOWN); |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1187 | 1204 |
| 1188 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { | 1205 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { |
| 1189 if (audio_ && !video_) | 1206 if (audio_ && !video_) |
| 1190 return audio_->GetBufferedRanges(duration_); | 1207 return audio_->GetBufferedRanges(duration_); |
| 1191 else if (!audio_ && video_) | 1208 else if (!audio_ && video_) |
| 1192 return video_->GetBufferedRanges(duration_); | 1209 return video_->GetBufferedRanges(duration_); |
| 1193 return ComputeIntersection(); | 1210 return ComputeIntersection(); |
| 1194 } | 1211 } |
| 1195 | 1212 |
| 1196 } // namespace media | 1213 } // namespace media |
| OLD | NEW |