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 "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 185 virtual const VideoDecoderConfig& video_decoder_config() OVERRIDE; | 185 virtual const VideoDecoderConfig& video_decoder_config() OVERRIDE; |
| 186 virtual Ranges<TimeDelta> GetBufferedRanges() OVERRIDE; | 186 virtual Ranges<TimeDelta> GetBufferedRanges() OVERRIDE; |
| 187 | 187 |
| 188 protected: | 188 protected: |
| 189 virtual ~ChunkDemuxerStream(); | 189 virtual ~ChunkDemuxerStream(); |
| 190 | 190 |
| 191 private: | 191 private: |
| 192 enum State { | 192 enum State { |
| 193 RETURNING_DATA_FOR_READS, | 193 RETURNING_DATA_FOR_READS, |
| 194 WAITING_FOR_SEEK, | 194 WAITING_FOR_SEEK, |
| 195 CONFIG_CHANGE, | |
| 195 SHUTDOWN, | 196 SHUTDOWN, |
| 196 }; | 197 }; |
| 197 | 198 |
| 198 // Assigns |state_| to |state| | 199 // Assigns |state_| to |state| |
| 199 void ChangeState_Locked(State state); | 200 void ChangeState_Locked(State state); |
| 200 | 201 |
| 201 // Adds the callback to |read_cbs_| so it can be called later when we | 202 // Adds the callback to |read_cbs_| so it can be called later when we |
| 202 // have data. | 203 // have data. |
| 203 void DeferRead_Locked(const ReadCB& read_cb); | 204 void DeferRead_Locked(const ReadCB& read_cb); |
| 204 | 205 |
| 205 // Creates closures that bind ReadCBs in |read_cbs_| to data in | 206 // Creates closures that bind ReadCBs in |read_cbs_| to data in |
| 206 // |buffers_| and pops the callbacks & buffers from the respecive queues. | 207 // |buffers_| and pops the callbacks & buffers from the respecive queues. |
| 207 void CreateReadDoneClosures_Locked(ClosureQueue* closures); | 208 void CreateReadDoneClosures_Locked(ClosureQueue* closures); |
| 208 | 209 |
| 210 // Called when audio_decoder_config() or video_decoder_config() is called. | |
| 211 // This method handles transitioning from | |
| 212 // CONFIG_CHANGE to RETURNING_DATA_FOR_READS if necessary. | |
| 213 void OnConfigRequest(); | |
| 214 | |
| 209 // Specifies the type of the stream (must be AUDIO or VIDEO for now). | 215 // Specifies the type of the stream (must be AUDIO or VIDEO for now). |
| 210 Type type_; | 216 Type type_; |
| 211 | 217 |
| 212 scoped_ptr<SourceBufferStream> stream_; | 218 scoped_ptr<SourceBufferStream> stream_; |
| 213 | 219 |
| 214 mutable base::Lock lock_; | 220 mutable base::Lock lock_; |
| 215 State state_; | 221 State state_; |
| 216 ReadCBQueue read_cbs_; | 222 ReadCBQueue read_cbs_; |
| 217 | 223 |
| 218 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); | 224 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 287 } | 293 } |
| 288 | 294 |
| 289 Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedRanges() { | 295 Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedRanges() { |
| 290 base::AutoLock auto_lock(lock_); | 296 base::AutoLock auto_lock(lock_); |
| 291 return stream_->GetBufferedTime(); | 297 return stream_->GetBufferedTime(); |
| 292 } | 298 } |
| 293 | 299 |
| 294 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config) { | 300 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config) { |
| 295 DCHECK(config.IsValidConfig()); | 301 DCHECK(config.IsValidConfig()); |
| 296 DCHECK_EQ(type_, AUDIO); | 302 DCHECK_EQ(type_, AUDIO); |
| 297 | 303 return stream_->UpdateAudioConfig(config); |
| 298 const AudioDecoderConfig& current_config = | |
| 299 stream_->GetCurrentAudioDecoderConfig(); | |
| 300 | |
| 301 bool success = (current_config.codec() == config.codec()) && | |
| 302 (current_config.bits_per_channel() == config.bits_per_channel()) && | |
| 303 (current_config.channel_layout() == config.channel_layout()) && | |
| 304 (current_config.samples_per_second() == config.samples_per_second()) && | |
| 305 (current_config.extra_data_size() == config.extra_data_size()) && | |
| 306 (!current_config.extra_data() || | |
| 307 !memcmp(current_config.extra_data(), config.extra_data(), | |
| 308 current_config.extra_data_size())); | |
| 309 | |
| 310 if (!success) | |
| 311 DVLOG(1) << "UpdateAudioConfig() : Failed to update audio config."; | |
| 312 | |
| 313 return success; | |
| 314 } | 304 } |
| 315 | 305 |
| 316 bool ChunkDemuxerStream::UpdateVideoConfig(const VideoDecoderConfig& config) { | 306 bool ChunkDemuxerStream::UpdateVideoConfig(const VideoDecoderConfig& config) { |
| 317 DCHECK(config.IsValidConfig()); | 307 DCHECK(config.IsValidConfig()); |
| 318 DCHECK_EQ(type_, VIDEO); | 308 DCHECK_EQ(type_, VIDEO); |
| 319 const VideoDecoderConfig& current_config = | 309 return stream_->UpdateVideoConfig(config); |
| 320 stream_->GetCurrentVideoDecoderConfig(); | |
| 321 | |
| 322 bool success = (current_config.codec() == config.codec()) && | |
| 323 (current_config.format() == config.format()) && | |
| 324 (current_config.profile() == config.profile()) && | |
| 325 (current_config.coded_size() == config.coded_size()) && | |
| 326 (current_config.visible_rect() == config.visible_rect()) && | |
| 327 (current_config.natural_size() == config.natural_size()) && | |
| 328 (current_config.extra_data_size() == config.extra_data_size()) && | |
| 329 (!current_config.extra_data() || | |
| 330 !memcmp(current_config.extra_data(), config.extra_data(), | |
| 331 current_config.extra_data_size())); | |
| 332 | |
| 333 if (!success) | |
| 334 DVLOG(1) << "UpdateVideoConfig() : Failed to update video config."; | |
| 335 | |
| 336 return success; | |
| 337 } | 310 } |
| 338 | 311 |
| 339 void ChunkDemuxerStream::EndOfStream() { | 312 void ChunkDemuxerStream::EndOfStream() { |
| 340 ClosureQueue closures; | 313 ClosureQueue closures; |
| 341 { | 314 { |
| 342 base::AutoLock auto_lock(lock_); | 315 base::AutoLock auto_lock(lock_); |
| 343 stream_->EndOfStream(); | 316 stream_->EndOfStream(); |
| 344 CreateReadDoneClosures_Locked(&closures); | 317 CreateReadDoneClosures_Locked(&closures); |
| 345 } | 318 } |
| 346 | 319 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 385 void ChunkDemuxerStream::Read(const ReadCB& read_cb) { | 358 void ChunkDemuxerStream::Read(const ReadCB& read_cb) { |
| 386 DemuxerStream::Status status = kOk; | 359 DemuxerStream::Status status = kOk; |
| 387 scoped_refptr<StreamParserBuffer> buffer; | 360 scoped_refptr<StreamParserBuffer> buffer; |
| 388 { | 361 { |
| 389 base::AutoLock auto_lock(lock_); | 362 base::AutoLock auto_lock(lock_); |
| 390 | 363 |
| 391 switch (state_) { | 364 switch (state_) { |
| 392 case RETURNING_DATA_FOR_READS: | 365 case RETURNING_DATA_FOR_READS: |
| 393 // If we already have pending reads or we don't have any buffers ready, | 366 // If we already have pending reads or we don't have any buffers ready, |
| 394 // then defer this read. | 367 // then defer this read. |
| 395 if (!read_cbs_.empty() || !stream_->GetNextBuffer(&buffer)) { | 368 if (!read_cbs_.empty()) { |
| 396 DeferRead_Locked(read_cb); | 369 DeferRead_Locked(read_cb); |
| 397 return; | 370 return; |
| 398 } | 371 } |
| 372 | |
| 373 switch (stream_->GetNextBuffer(&buffer)) { | |
| 374 case SourceBufferStream::kSuccess: | |
| 375 // Do nothing and continue | |
|
vrk (LEFT CHROMIUM)
2012/07/12 19:37:55
nit: period at end
acolwell GONE FROM CHROMIUM
2012/07/12 23:07:58
Done.
| |
| 376 break; | |
| 377 case SourceBufferStream::kNeedBuffer: | |
| 378 DeferRead_Locked(read_cb); | |
| 379 return; | |
| 380 case SourceBufferStream::kConfigChange: | |
| 381 ChangeState_Locked(CONFIG_CHANGE); | |
| 382 status = kConfigChanged; | |
| 383 break; | |
| 384 } | |
| 399 break; | 385 break; |
| 400 case WAITING_FOR_SEEK: | 386 case WAITING_FOR_SEEK: |
| 401 // Null buffers should be returned in this state since we are waiting | 387 // Null buffers should be returned in this state since we are waiting |
| 402 // for a seek. Any buffers in the SourceBuffer should NOT be returned | 388 // for a seek. Any buffers in the SourceBuffer should NOT be returned |
| 403 // because they are associated with the seek. | 389 // because they are associated with the seek. |
| 404 DCHECK(read_cbs_.empty()); | 390 DCHECK(read_cbs_.empty()); |
| 405 status = kAborted; | 391 status = kAborted; |
| 406 break; | 392 break; |
| 393 case CONFIG_CHANGE: | |
| 394 DCHECK(read_cbs_.empty()); | |
| 395 status = kConfigChanged; | |
| 396 break; | |
| 407 case SHUTDOWN: | 397 case SHUTDOWN: |
| 408 DCHECK(read_cbs_.empty()); | 398 DCHECK(read_cbs_.empty()); |
| 409 buffer = StreamParserBuffer::CreateEOSBuffer(); | 399 buffer = StreamParserBuffer::CreateEOSBuffer(); |
| 410 } | 400 } |
| 411 } | 401 } |
| 412 | 402 |
| 413 read_cb.Run(status, buffer); | 403 read_cb.Run(status, buffer); |
| 414 } | 404 } |
| 415 | 405 |
| 416 DemuxerStream::Type ChunkDemuxerStream::type() { return type_; } | 406 DemuxerStream::Type ChunkDemuxerStream::type() { return type_; } |
| 417 | 407 |
| 418 void ChunkDemuxerStream::EnableBitstreamConverter() {} | 408 void ChunkDemuxerStream::EnableBitstreamConverter() {} |
| 419 | 409 |
| 420 const AudioDecoderConfig& ChunkDemuxerStream::audio_decoder_config() { | 410 const AudioDecoderConfig& ChunkDemuxerStream::audio_decoder_config() { |
|
vrk (LEFT CHROMIUM)
2012/07/12 19:37:55
nit: {audio,video}_decoder_config() does more than
| |
| 421 CHECK_EQ(type_, AUDIO); | 411 CHECK_EQ(type_, AUDIO); |
| 422 base::AutoLock auto_lock(lock_); | 412 base::AutoLock auto_lock(lock_); |
| 413 OnConfigRequest(); | |
| 423 return stream_->GetCurrentAudioDecoderConfig(); | 414 return stream_->GetCurrentAudioDecoderConfig(); |
| 424 } | 415 } |
| 425 | 416 |
| 426 const VideoDecoderConfig& ChunkDemuxerStream::video_decoder_config() { | 417 const VideoDecoderConfig& ChunkDemuxerStream::video_decoder_config() { |
| 427 CHECK_EQ(type_, VIDEO); | 418 CHECK_EQ(type_, VIDEO); |
| 428 base::AutoLock auto_lock(lock_); | 419 base::AutoLock auto_lock(lock_); |
| 420 OnConfigRequest(); | |
| 429 return stream_->GetCurrentVideoDecoderConfig(); | 421 return stream_->GetCurrentVideoDecoderConfig(); |
| 430 } | 422 } |
| 431 | 423 |
| 424 void ChunkDemuxerStream::OnConfigRequest() { | |
| 425 lock_.AssertAcquired(); | |
| 426 if (state_ == CONFIG_CHANGE) { | |
| 427 stream_->UpdateCurrentConfigIndex(); | |
|
vrk (LEFT CHROMIUM)
2012/07/12 19:37:55
Change method name to something like "CompleteConf
acolwell GONE FROM CHROMIUM
2012/07/12 23:07:58
Done.
| |
| 428 ChangeState_Locked(RETURNING_DATA_FOR_READS); | |
| 429 } | |
| 430 } | |
| 431 | |
| 432 void ChunkDemuxerStream::ChangeState_Locked(State state) { | 432 void ChunkDemuxerStream::ChangeState_Locked(State state) { |
| 433 lock_.AssertAcquired(); | 433 lock_.AssertAcquired(); |
| 434 DVLOG(1) << "ChunkDemuxerStream::ChangeState_Locked() : " | |
| 435 << "type " << type_ | |
| 436 << " - " << state_ << " -> " << state; | |
| 434 state_ = state; | 437 state_ = state; |
| 435 } | 438 } |
| 436 | 439 |
| 437 ChunkDemuxerStream::~ChunkDemuxerStream() {} | 440 ChunkDemuxerStream::~ChunkDemuxerStream() {} |
| 438 | 441 |
| 439 void ChunkDemuxerStream::DeferRead_Locked(const ReadCB& read_cb) { | 442 void ChunkDemuxerStream::DeferRead_Locked(const ReadCB& read_cb) { |
| 440 lock_.AssertAcquired(); | 443 lock_.AssertAcquired(); |
| 441 // Wrap & store |read_cb| so that it will | 444 // Wrap & store |read_cb| so that it will |
| 442 // get called on the current MessageLoop. | 445 // get called on the current MessageLoop. |
| 443 read_cbs_.push_back(base::Bind(&RunOnMessageLoop, read_cb, | 446 read_cbs_.push_back(base::Bind(&RunOnMessageLoop, read_cb, |
| 444 MessageLoop::current())); | 447 MessageLoop::current())); |
| 445 } | 448 } |
| 446 | 449 |
| 447 void ChunkDemuxerStream::CreateReadDoneClosures_Locked(ClosureQueue* closures) { | 450 void ChunkDemuxerStream::CreateReadDoneClosures_Locked(ClosureQueue* closures) { |
| 448 lock_.AssertAcquired(); | 451 lock_.AssertAcquired(); |
| 449 | 452 |
| 450 if (state_ != RETURNING_DATA_FOR_READS) | 453 if (state_ != RETURNING_DATA_FOR_READS) |
| 451 return; | 454 return; |
| 452 | 455 |
| 453 scoped_refptr<StreamParserBuffer> buffer; | 456 bool configChange = false; |
| 454 while (!read_cbs_.empty()) { | 457 while (!read_cbs_.empty()) { |
| 455 if (!stream_->GetNextBuffer(&buffer)) | 458 scoped_refptr<StreamParserBuffer> buffer; |
| 456 return; | 459 switch (stream_->GetNextBuffer(&buffer)) { |
| 457 closures->push_back(base::Bind(read_cbs_.front(), | 460 case SourceBufferStream::kSuccess: |
| 458 DemuxerStream::kOk, buffer)); | 461 closures->push_back(base::Bind(read_cbs_.front(), |
| 459 read_cbs_.pop_front(); | 462 DemuxerStream::kOk, buffer)); |
| 463 read_cbs_.pop_front(); | |
| 464 break; | |
| 465 case SourceBufferStream::kNeedBuffer: | |
| 466 return; | |
| 467 case SourceBufferStream::kConfigChange: | |
| 468 configChange = true; | |
| 469 closures->push_back(base::Bind(read_cbs_.front(), | |
| 470 DemuxerStream::kConfigChanged, | |
| 471 scoped_refptr<DecoderBuffer>())); | |
| 472 read_cbs_.pop_front(); | |
| 473 } | |
| 460 } | 474 } |
| 475 if (configChange) | |
| 476 ChangeState_Locked(CONFIG_CHANGE); | |
| 461 } | 477 } |
| 462 | 478 |
| 463 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) | 479 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) |
| 464 : state_(WAITING_FOR_INIT), | 480 : state_(WAITING_FOR_INIT), |
| 465 host_(NULL), | 481 host_(NULL), |
| 466 client_(client) { | 482 client_(client) { |
| 467 DCHECK(client); | 483 DCHECK(client); |
| 468 } | 484 } |
| 469 | 485 |
| 470 void ChunkDemuxer::Initialize(DemuxerHost* host, | 486 void ChunkDemuxer::Initialize(DemuxerHost* host, |
| (...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 982 // TODO(vrk): There should be a special case for the first appends where all | 998 // TODO(vrk): There should be a special case for the first appends where all |
| 983 // streams (for both demuxed and muxed case) begin at the earliest stream | 999 // streams (for both demuxed and muxed case) begin at the earliest stream |
| 984 // timestamp. (crbug.com/132815) | 1000 // timestamp. (crbug.com/132815) |
| 985 if (audio_ && source_id == source_id_audio_) | 1001 if (audio_ && source_id == source_id_audio_) |
| 986 audio_->OnNewMediaSegment(start_timestamp); | 1002 audio_->OnNewMediaSegment(start_timestamp); |
| 987 if (video_ && source_id == source_id_video_) | 1003 if (video_ && source_id == source_id_video_) |
| 988 video_->OnNewMediaSegment(start_timestamp); | 1004 video_->OnNewMediaSegment(start_timestamp); |
| 989 } | 1005 } |
| 990 | 1006 |
| 991 } // namespace media | 1007 } // namespace media |
| OLD | NEW |