OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 // Implements a Demuxer that can switch among different data sources mid-stream. | 5 // Implements a Demuxer that can switch among different data sources mid-stream. |
6 // Uses FFmpegDemuxer under the covers, so see the caveats at the top of | 6 // Uses FFmpegDemuxer under the covers, so see the caveats at the top of |
7 // ffmpeg_demuxer.h. | 7 // ffmpeg_demuxer.h. |
8 | 8 |
9 #include "media/filters/chunk_demuxer.h" | 9 #include "media/filters/chunk_demuxer.h" |
10 | 10 |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
316 | 316 |
317 Shutdown(); | 317 Shutdown(); |
318 | 318 |
319 callback->Run(); | 319 callback->Run(); |
320 delete callback; | 320 delete callback; |
321 } | 321 } |
322 | 322 |
323 void ChunkDemuxer::Seek(base::TimeDelta time, const FilterStatusCB& cb) { | 323 void ChunkDemuxer::Seek(base::TimeDelta time, const FilterStatusCB& cb) { |
324 VLOG(1) << "Seek(" << time.InSecondsF() << ")"; | 324 VLOG(1) << "Seek(" << time.InSecondsF() << ")"; |
325 | 325 |
326 PipelineStatus status = PIPELINE_ERROR_INVALID_STATE; | |
326 { | 327 { |
327 base::AutoLock auto_lock(lock_); | 328 base::AutoLock auto_lock(lock_); |
328 | 329 |
329 if (seek_waits_for_data_) { | 330 if (state_ == INITIALIZED || state_ == ENDED) { |
330 VLOG(1) << "Seek() : waiting for more data to arrive."; | 331 if (seek_waits_for_data_) { |
331 seek_cb_ = cb; | 332 VLOG(1) << "Seek() : waiting for more data to arrive."; |
332 return; | 333 seek_cb_ = cb; |
334 return; | |
335 } | |
336 | |
337 status = PIPELINE_OK; | |
333 } | 338 } |
334 } | 339 } |
335 | 340 |
336 cb.Run(PIPELINE_OK); | 341 cb.Run(status); |
337 } | 342 } |
338 | 343 |
339 void ChunkDemuxer::OnAudioRendererDisabled() { | 344 void ChunkDemuxer::OnAudioRendererDisabled() { |
340 base::AutoLock auto_lock(lock_); | 345 base::AutoLock auto_lock(lock_); |
341 audio_ = NULL; | 346 audio_ = NULL; |
342 } | 347 } |
343 | 348 |
344 void ChunkDemuxer::SetPreload(Preload preload) {} | 349 void ChunkDemuxer::SetPreload(Preload preload) {} |
345 | 350 |
346 // Demuxer implementation. | 351 // Demuxer implementation. |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
387 int64 buffered_bytes = 0; | 392 int64 buffered_bytes = 0; |
388 base::TimeDelta buffered_ts = base::TimeDelta::FromSeconds(-1); | 393 base::TimeDelta buffered_ts = base::TimeDelta::FromSeconds(-1); |
389 | 394 |
390 FilterStatusCB cb; | 395 FilterStatusCB cb; |
391 { | 396 { |
392 base::AutoLock auto_lock(lock_); | 397 base::AutoLock auto_lock(lock_); |
393 switch(state_) { | 398 switch(state_) { |
394 case INITIALIZING: | 399 case INITIALIZING: |
395 if (!ParseInfoAndTracks_Locked(data, length)) { | 400 if (!ParseInfoAndTracks_Locked(data, length)) { |
396 VLOG(1) << "AppendData(): parsing info & tracks failed"; | 401 VLOG(1) << "AppendData(): parsing info & tracks failed"; |
397 return false; | 402 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
398 } | 403 } |
399 return true; | 404 return true; |
400 break; | 405 break; |
401 | 406 |
402 case INITIALIZED: | 407 case INITIALIZED: |
403 if (!ParseAndAppendData_Locked(data, length)) { | 408 if (!ParseAndAppendData_Locked(data, length)) { |
404 VLOG(1) << "AppendData(): parsing data failed"; | 409 VLOG(1) << "AppendData(): parsing data failed"; |
405 return false; | 410 ReportError_Locked(PIPELINE_ERROR_DECODE); |
411 return true; | |
406 } | 412 } |
407 break; | 413 break; |
408 | 414 |
409 case WAITING_FOR_INIT: | 415 case WAITING_FOR_INIT: |
410 case ENDED: | 416 case ENDED: |
411 case INIT_ERROR: | 417 case PARSE_ERROR: |
412 case SHUTDOWN: | 418 case SHUTDOWN: |
413 VLOG(1) << "AppendData(): called in unexpected state " << state_; | 419 VLOG(1) << "AppendData(): called in unexpected state " << state_; |
414 return false; | 420 return false; |
415 break; | 421 break; |
Ami GONE FROM CHROMIUM
2011/08/03 21:06:02
This break; is necessary?
acolwell GONE FROM CHROMIUM
2011/08/03 22:08:11
No. Done.
| |
416 } | 422 } |
417 | 423 |
418 seek_waits_for_data_ = false; | 424 seek_waits_for_data_ = false; |
419 | 425 |
420 base::TimeDelta tmp; | 426 base::TimeDelta tmp; |
421 if (audio_.get() && audio_->GetLastBufferTimestamp(&tmp) && | 427 if (audio_.get() && audio_->GetLastBufferTimestamp(&tmp) && |
422 tmp > buffered_ts) { | 428 tmp > buffered_ts) { |
423 buffered_ts = tmp; | 429 buffered_ts = tmp; |
424 } | 430 } |
425 | 431 |
(...skipping 21 matching lines...) Expand all Loading... | |
447 | 453 |
448 if (!cb.is_null()) | 454 if (!cb.is_null()) |
449 cb.Run(PIPELINE_OK); | 455 cb.Run(PIPELINE_OK); |
450 | 456 |
451 return true; | 457 return true; |
452 } | 458 } |
453 | 459 |
454 void ChunkDemuxer::EndOfStream(PipelineStatus status) { | 460 void ChunkDemuxer::EndOfStream(PipelineStatus status) { |
455 VLOG(1) << "EndOfStream(" << status << ")"; | 461 VLOG(1) << "EndOfStream(" << status << ")"; |
456 base::AutoLock auto_lock(lock_); | 462 base::AutoLock auto_lock(lock_); |
457 DCHECK((state_ == INITIALIZING) || (state_ == INITIALIZED) || | 463 DCHECK_NE(state_, WAITING_FOR_INIT); |
458 (state_ == SHUTDOWN)); | 464 DCHECK_NE(state_, ENDED); |
459 | 465 |
460 if (state_ == SHUTDOWN) | 466 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) |
461 return; | 467 return; |
462 | 468 |
463 if (state_ == INITIALIZING) { | 469 if (state_ == INITIALIZING) { |
464 InitFailed_Locked(); | 470 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
465 return; | 471 return; |
466 } | 472 } |
467 | 473 |
468 ChangeState(ENDED); | 474 ChangeState(ENDED); |
469 | 475 |
470 if (status != PIPELINE_OK) { | 476 if (status != PIPELINE_OK) { |
471 host()->SetError(status); | 477 ReportError_Locked(status); |
472 return; | 478 return; |
473 } | 479 } |
474 | 480 |
475 // Create an end of stream buffer. | 481 // Create an end of stream buffer. |
476 ChunkDemuxerStream::BufferQueue buffers; | 482 ChunkDemuxerStream::BufferQueue buffers; |
477 buffers.push_back(CreateEOSBuffer()); | 483 buffers.push_back(CreateEOSBuffer()); |
478 | 484 |
479 if (audio_.get()) | 485 if (audio_.get()) |
480 audio_->AddBuffers(buffers); | 486 audio_->AddBuffers(buffers); |
481 | 487 |
482 if (video_.get()) | 488 if (video_.get()) |
483 video_->AddBuffers(buffers); | 489 video_->AddBuffers(buffers); |
484 } | 490 } |
485 | 491 |
486 bool ChunkDemuxer::HasEnded() { | 492 bool ChunkDemuxer::HasEnded() { |
487 base::AutoLock auto_lock(lock_); | 493 base::AutoLock auto_lock(lock_); |
488 return (state_ == ENDED); | 494 return (state_ == ENDED); |
489 } | 495 } |
490 | 496 |
491 | |
492 void ChunkDemuxer::Shutdown() { | 497 void ChunkDemuxer::Shutdown() { |
493 VLOG(1) << "Shutdown()"; | 498 VLOG(1) << "Shutdown()"; |
494 FilterStatusCB cb; | 499 FilterStatusCB cb; |
495 { | 500 { |
496 base::AutoLock auto_lock(lock_); | 501 base::AutoLock auto_lock(lock_); |
497 | 502 |
498 if (state_ == SHUTDOWN) | 503 if (state_ == SHUTDOWN) |
499 return; | 504 return; |
500 | 505 |
501 std::swap(cb, seek_cb_); | 506 std::swap(cb, seek_cb_); |
(...skipping 22 matching lines...) Expand all Loading... | |
524 DCHECK(data); | 529 DCHECK(data); |
525 DCHECK_GT(size, 0); | 530 DCHECK_GT(size, 0); |
526 | 531 |
527 DCHECK_EQ(state_, INITIALIZING); | 532 DCHECK_EQ(state_, INITIALIZING); |
528 | 533 |
529 const uint8* cur = data; | 534 const uint8* cur = data; |
530 int cur_size = size; | 535 int cur_size = size; |
531 WebMInfoParser info_parser; | 536 WebMInfoParser info_parser; |
532 int res = info_parser.Parse(cur, cur_size); | 537 int res = info_parser.Parse(cur, cur_size); |
533 | 538 |
534 if (res <= 0) { | 539 if (res <= 0) |
535 InitFailed_Locked(); | |
536 return false; | 540 return false; |
537 } | |
538 | 541 |
539 cur += res; | 542 cur += res; |
540 cur_size -= res; | 543 cur_size -= res; |
541 | 544 |
542 WebMTracksParser tracks_parser(info_parser.timecode_scale()); | 545 WebMTracksParser tracks_parser(info_parser.timecode_scale()); |
543 res = tracks_parser.Parse(cur, cur_size); | 546 res = tracks_parser.Parse(cur, cur_size); |
544 | 547 |
545 if (res <= 0) { | 548 if (res <= 0) |
546 InitFailed_Locked(); | |
547 return false; | 549 return false; |
548 } | |
549 | 550 |
550 double mult = info_parser.timecode_scale() / 1000.0; | 551 double mult = info_parser.timecode_scale() / 1000.0; |
551 duration_ = base::TimeDelta::FromMicroseconds(info_parser.duration() * mult); | 552 duration_ = base::TimeDelta::FromMicroseconds(info_parser.duration() * mult); |
552 | 553 |
553 cluster_parser_.reset(new WebMClusterParser( | 554 cluster_parser_.reset(new WebMClusterParser( |
554 info_parser.timecode_scale(), | 555 info_parser.timecode_scale(), |
555 tracks_parser.audio_track_num(), | 556 tracks_parser.audio_track_num(), |
556 tracks_parser.audio_default_duration(), | 557 tracks_parser.audio_default_duration(), |
557 tracks_parser.video_track_num(), | 558 tracks_parser.video_track_num(), |
558 tracks_parser.video_default_duration())); | 559 tracks_parser.video_default_duration())); |
559 | 560 |
560 format_context_ = CreateFormatContext(data, size); | 561 format_context_ = CreateFormatContext(data, size); |
561 | 562 |
562 if (!format_context_ || !SetupStreams()) { | 563 if (!format_context_ || !SetupStreams()) { |
563 InitFailed_Locked(); | |
564 return false; | 564 return false; |
565 } | 565 } |
566 | 566 |
567 ChangeState(INITIALIZED); | 567 ChangeState(INITIALIZED); |
568 init_cb_.Run(PIPELINE_OK); | 568 init_cb_.Run(PIPELINE_OK); |
569 init_cb_.Reset(); | 569 init_cb_.Reset(); |
570 return true; | 570 return true; |
571 } | 571 } |
572 | 572 |
573 AVFormatContext* ChunkDemuxer::CreateFormatContext(const uint8* data, | 573 AVFormatContext* ChunkDemuxer::CreateFormatContext(const uint8* data, |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
670 cur_size -= res; | 670 cur_size -= res; |
671 } | 671 } |
672 | 672 |
673 // TODO(acolwell) : make this more representative of what is actually | 673 // TODO(acolwell) : make this more representative of what is actually |
674 // buffered. | 674 // buffered. |
675 buffered_bytes_ += length; | 675 buffered_bytes_ += length; |
676 | 676 |
677 return true; | 677 return true; |
678 } | 678 } |
679 | 679 |
680 void ChunkDemuxer::InitFailed_Locked() { | 680 void ChunkDemuxer::ReportError_Locked(PipelineStatus status) { |
Ami GONE FROM CHROMIUM
2011/08/03 21:06:02
FWIW, when you know status is not OK, I prefer nam
acolwell GONE FROM CHROMIUM
2011/08/03 22:08:11
Done.
| |
681 ChangeState(INIT_ERROR); | 681 DCHECK_NE(status, PIPELINE_OK); |
682 | |
683 ChangeState(PARSE_ERROR); | |
684 MessageLoop::current()->PostTask( | |
685 FROM_HERE, | |
686 NewRunnableMethod(this, &ChunkDemuxer::ReportErrorTask, status)); | |
687 } | |
688 | |
689 void ChunkDemuxer::ReportErrorTask(PipelineStatus status) { | |
682 PipelineStatusCB cb; | 690 PipelineStatusCB cb; |
683 std::swap(cb, init_cb_); | 691 { |
684 cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN); | 692 base::AutoLock auto_lock(lock_); |
693 if (state_ != PARSE_ERROR) | |
Ami GONE FROM CHROMIUM
2011/08/03 21:06:02
When can this happen?
acolwell GONE FROM CHROMIUM
2011/08/03 22:08:11
This can happen if Stop() is called before this ta
Ami GONE FROM CHROMIUM
2011/08/03 23:41:35
Add a comment?
acolwell GONE FROM CHROMIUM
2011/08/04 00:22:16
No longer necessary now that we aren't posting a t
| |
694 return; | |
695 | |
696 if (!init_cb_.is_null()) { | |
697 std::swap(cb, init_cb_); | |
698 } else { | |
699 if (!seek_cb_.is_null()) | |
700 std::swap(cb, seek_cb_); | |
701 | |
702 if (audio_.get()) | |
703 audio_->Shutdown(); | |
704 | |
705 if (video_.get()) | |
706 video_->Shutdown(); | |
707 } | |
708 } | |
709 | |
710 if (cb.is_null()) { | |
711 host()->SetError(status); | |
712 return; | |
713 } | |
714 cb.Run(status); | |
Ami GONE FROM CHROMIUM
2011/08/03 21:06:02
Seems strange that in this case host()->SetError()
acolwell GONE FROM CHROMIUM
2011/08/03 22:08:11
SetError() is only used for error reporting when w
| |
685 } | 715 } |
686 | 716 |
687 } // namespace media | 717 } // namespace media |
OLD | NEW |