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/ffmpeg_demuxer.h" | 5 #include "media/filters/ffmpeg_demuxer.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
326 | 326 |
327 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream( | 327 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream( |
328 DemuxerStream::Type type) { | 328 DemuxerStream::Type type) { |
329 return GetFFmpegStream(type); | 329 return GetFFmpegStream(type); |
330 } | 330 } |
331 | 331 |
332 scoped_refptr<FFmpegDemuxerStream> FFmpegDemuxer::GetFFmpegStream( | 332 scoped_refptr<FFmpegDemuxerStream> FFmpegDemuxer::GetFFmpegStream( |
333 DemuxerStream::Type type) const { | 333 DemuxerStream::Type type) const { |
334 StreamVector::const_iterator iter; | 334 StreamVector::const_iterator iter; |
335 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 335 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
336 if (*iter && (*iter)->type() == type) { | 336 if (*iter.get() && (*iter)->type() == type) { |
337 return *iter; | 337 return *iter; |
338 } | 338 } |
339 } | 339 } |
340 return NULL; | 340 return NULL; |
341 } | 341 } |
342 | 342 |
343 base::TimeDelta FFmpegDemuxer::GetStartTime() const { | 343 base::TimeDelta FFmpegDemuxer::GetStartTime() const { |
344 return start_time_; | 344 return start_time_; |
345 } | 345 } |
346 | 346 |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
570 | 570 |
571 status_cb.Run(PIPELINE_OK); | 571 status_cb.Run(PIPELINE_OK); |
572 } | 572 } |
573 | 573 |
574 void FFmpegDemuxer::SeekTask(base::TimeDelta time, const PipelineStatusCB& cb) { | 574 void FFmpegDemuxer::SeekTask(base::TimeDelta time, const PipelineStatusCB& cb) { |
575 DCHECK(message_loop_->BelongsToCurrentThread()); | 575 DCHECK(message_loop_->BelongsToCurrentThread()); |
576 | 576 |
577 // Tell streams to flush buffers due to seeking. | 577 // Tell streams to flush buffers due to seeking. |
578 StreamVector::iterator iter; | 578 StreamVector::iterator iter; |
579 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 579 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
580 if (*iter) | 580 if (*iter.get()) |
581 (*iter)->FlushBuffers(); | 581 (*iter)->FlushBuffers(); |
582 } | 582 } |
583 | 583 |
584 // Always seek to a timestamp less than or equal to the desired timestamp. | 584 // Always seek to a timestamp less than or equal to the desired timestamp. |
585 int flags = AVSEEK_FLAG_BACKWARD; | 585 int flags = AVSEEK_FLAG_BACKWARD; |
586 | 586 |
587 // Passing -1 as our stream index lets FFmpeg pick a default stream. FFmpeg | 587 // Passing -1 as our stream index lets FFmpeg pick a default stream. FFmpeg |
588 // will attempt to use the lowest-index video stream, if present, followed by | 588 // will attempt to use the lowest-index video stream, if present, followed by |
589 // the lowest-index audio stream. | 589 // the lowest-index audio stream. |
590 if (av_seek_frame(format_context_, -1, time.InMicroseconds(), flags) < 0) { | 590 if (av_seek_frame(format_context_, -1, time.InMicroseconds(), flags) < 0) { |
(...skipping 19 matching lines...) Expand all Loading... |
610 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket> packet(new AVPacket()); | 610 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket> packet(new AVPacket()); |
611 int result = av_read_frame(format_context_, packet.get()); | 611 int result = av_read_frame(format_context_, packet.get()); |
612 if (result < 0) { | 612 if (result < 0) { |
613 // Update the duration based on the audio stream if | 613 // Update the duration based on the audio stream if |
614 // it was previously unknown http://crbug.com/86830 | 614 // it was previously unknown http://crbug.com/86830 |
615 if (!duration_known_) { | 615 if (!duration_known_) { |
616 // Search streams for AUDIO one. | 616 // Search streams for AUDIO one. |
617 for (StreamVector::iterator iter = streams_.begin(); | 617 for (StreamVector::iterator iter = streams_.begin(); |
618 iter != streams_.end(); | 618 iter != streams_.end(); |
619 ++iter) { | 619 ++iter) { |
620 if (*iter && (*iter)->type() == DemuxerStream::AUDIO) { | 620 if (*iter.get() && (*iter)->type() == DemuxerStream::AUDIO) { |
621 base::TimeDelta duration = (*iter)->GetElapsedTime(); | 621 base::TimeDelta duration = (*iter)->GetElapsedTime(); |
622 if (duration != kNoTimestamp() && duration > base::TimeDelta()) { | 622 if (duration != kNoTimestamp() && duration > base::TimeDelta()) { |
623 host_->SetDuration(duration); | 623 host_->SetDuration(duration); |
624 duration_known_ = true; | 624 duration_known_ = true; |
625 } | 625 } |
626 break; | 626 break; |
627 } | 627 } |
628 } | 628 } |
629 } | 629 } |
630 // If we have reached the end of stream, tell the downstream filters about | 630 // If we have reached the end of stream, tell the downstream filters about |
631 // the event. | 631 // the event. |
632 StreamHasEnded(); | 632 StreamHasEnded(); |
633 return; | 633 return; |
634 } | 634 } |
635 | 635 |
636 // Queue the packet with the appropriate stream. | 636 // Queue the packet with the appropriate stream. |
637 // TODO(scherkus): should we post this back to the pipeline thread? I'm | 637 // TODO(scherkus): should we post this back to the pipeline thread? I'm |
638 // worried about downstream filters (i.e., decoders) executing on this | 638 // worried about downstream filters (i.e., decoders) executing on this |
639 // thread. | 639 // thread. |
640 DCHECK_GE(packet->stream_index, 0); | 640 DCHECK_GE(packet->stream_index, 0); |
641 DCHECK_LT(packet->stream_index, static_cast<int>(streams_.size())); | 641 DCHECK_LT(packet->stream_index, static_cast<int>(streams_.size())); |
642 | 642 |
643 // Defend against ffmpeg giving us a bad stream index. | 643 // Defend against ffmpeg giving us a bad stream index. |
644 if (packet->stream_index >= 0 && | 644 if (packet->stream_index >= 0 && |
645 packet->stream_index < static_cast<int>(streams_.size()) && | 645 packet->stream_index < static_cast<int>(streams_.size()) && |
646 streams_[packet->stream_index] && | 646 streams_[packet->stream_index].get() && |
647 (!audio_disabled_ || | 647 (!audio_disabled_ || |
648 streams_[packet->stream_index]->type() != DemuxerStream::AUDIO)) { | 648 streams_[packet->stream_index]->type() != DemuxerStream::AUDIO)) { |
649 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index]; | 649 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index].get(); |
650 demuxer_stream->EnqueuePacket(packet.Pass()); | 650 demuxer_stream->EnqueuePacket(packet.Pass()); |
651 } | 651 } |
652 | 652 |
653 // Create a loop by posting another task. This allows seek and message loop | 653 // Create a loop by posting another task. This allows seek and message loop |
654 // quit tasks to get processed. | 654 // quit tasks to get processed. |
655 if (StreamsHavePendingReads()) { | 655 if (StreamsHavePendingReads()) { |
656 PostDemuxTask(); | 656 PostDemuxTask(); |
657 } | 657 } |
658 } | 658 } |
659 | 659 |
660 void FFmpegDemuxer::StopTask(const base::Closure& callback) { | 660 void FFmpegDemuxer::StopTask(const base::Closure& callback) { |
661 DCHECK(message_loop_->BelongsToCurrentThread()); | 661 DCHECK(message_loop_->BelongsToCurrentThread()); |
662 StreamVector::iterator iter; | 662 StreamVector::iterator iter; |
663 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 663 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
664 if (*iter) | 664 if (*iter.get()) |
665 (*iter)->Stop(); | 665 (*iter)->Stop(); |
666 } | 666 } |
667 if (data_source_) { | 667 if (data_source_.get()) { |
668 data_source_->Stop(callback); | 668 data_source_->Stop(callback); |
669 } else { | 669 } else { |
670 callback.Run(); | 670 callback.Run(); |
671 } | 671 } |
672 } | 672 } |
673 | 673 |
674 void FFmpegDemuxer::DisableAudioStreamTask() { | 674 void FFmpegDemuxer::DisableAudioStreamTask() { |
675 DCHECK(message_loop_->BelongsToCurrentThread()); | 675 DCHECK(message_loop_->BelongsToCurrentThread()); |
676 audio_disabled_ = true; | 676 audio_disabled_ = true; |
677 StreamVector::iterator iter; | 677 StreamVector::iterator iter; |
678 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 678 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
679 if (*iter && (*iter)->type() == DemuxerStream::AUDIO) { | 679 if (*iter.get() && (*iter)->type() == DemuxerStream::AUDIO) { |
680 (*iter)->Stop(); | 680 (*iter)->Stop(); |
681 } | 681 } |
682 } | 682 } |
683 } | 683 } |
684 | 684 |
685 bool FFmpegDemuxer::StreamsHavePendingReads() { | 685 bool FFmpegDemuxer::StreamsHavePendingReads() { |
686 DCHECK(message_loop_->BelongsToCurrentThread()); | 686 DCHECK(message_loop_->BelongsToCurrentThread()); |
687 StreamVector::iterator iter; | 687 StreamVector::iterator iter; |
688 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 688 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
689 if (*iter && (*iter)->HasPendingReads()) { | 689 if (*iter.get() && (*iter)->HasPendingReads()) { |
690 return true; | 690 return true; |
691 } | 691 } |
692 } | 692 } |
693 return false; | 693 return false; |
694 } | 694 } |
695 | 695 |
696 void FFmpegDemuxer::StreamHasEnded() { | 696 void FFmpegDemuxer::StreamHasEnded() { |
697 DCHECK(message_loop_->BelongsToCurrentThread()); | 697 DCHECK(message_loop_->BelongsToCurrentThread()); |
698 StreamVector::iterator iter; | 698 StreamVector::iterator iter; |
699 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 699 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
700 if (!*iter || | 700 if (!*iter.get() || |
701 (audio_disabled_ && (*iter)->type() == DemuxerStream::AUDIO)) { | 701 (audio_disabled_ && (*iter)->type() == DemuxerStream::AUDIO)) { |
702 continue; | 702 continue; |
703 } | 703 } |
704 (*iter)->EnqueuePacket( | 704 (*iter)->EnqueuePacket( |
705 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket>()); | 705 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket>()); |
706 } | 706 } |
707 } | 707 } |
708 | 708 |
709 int FFmpegDemuxer::WaitForRead() { | 709 int FFmpegDemuxer::WaitForRead() { |
710 read_event_.Wait(); | 710 read_event_.Wait(); |
711 return last_read_bytes_; | 711 return last_read_bytes_; |
712 } | 712 } |
713 | 713 |
714 void FFmpegDemuxer::SignalReadCompleted(int size) { | 714 void FFmpegDemuxer::SignalReadCompleted(int size) { |
715 last_read_bytes_ = size; | 715 last_read_bytes_ = size; |
716 read_event_.Signal(); | 716 read_event_.Signal(); |
717 } | 717 } |
718 | 718 |
719 void FFmpegDemuxer::NotifyBufferingChanged() { | 719 void FFmpegDemuxer::NotifyBufferingChanged() { |
720 DCHECK(message_loop_->BelongsToCurrentThread()); | 720 DCHECK(message_loop_->BelongsToCurrentThread()); |
721 Ranges<base::TimeDelta> buffered; | 721 Ranges<base::TimeDelta> buffered; |
722 scoped_refptr<FFmpegDemuxerStream> audio = | 722 scoped_refptr<FFmpegDemuxerStream> audio = |
723 audio_disabled_ ? NULL : GetFFmpegStream(DemuxerStream::AUDIO); | 723 audio_disabled_ ? NULL : GetFFmpegStream(DemuxerStream::AUDIO); |
724 scoped_refptr<FFmpegDemuxerStream> video = | 724 scoped_refptr<FFmpegDemuxerStream> video = |
725 GetFFmpegStream(DemuxerStream::VIDEO); | 725 GetFFmpegStream(DemuxerStream::VIDEO); |
726 if (audio && video) { | 726 if (audio.get() && video.get()) { |
727 buffered = audio->GetBufferedRanges().IntersectionWith( | 727 buffered = audio->GetBufferedRanges().IntersectionWith( |
728 video->GetBufferedRanges()); | 728 video->GetBufferedRanges()); |
729 } else if (audio) { | 729 } else if (audio.get()) { |
730 buffered = audio->GetBufferedRanges(); | 730 buffered = audio->GetBufferedRanges(); |
731 } else if (video) { | 731 } else if (video.get()) { |
732 buffered = video->GetBufferedRanges(); | 732 buffered = video->GetBufferedRanges(); |
733 } | 733 } |
734 for (size_t i = 0; i < buffered.size(); ++i) | 734 for (size_t i = 0; i < buffered.size(); ++i) |
735 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i)); | 735 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i)); |
736 } | 736 } |
737 | 737 |
738 } // namespace media | 738 } // namespace media |
OLD | NEW |