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 #include "base/bind.h" | 5 #include "base/bind.h" |
6 #include "base/callback.h" | 6 #include "base/callback.h" |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
146 it->Run(scoped_refptr<Buffer>(new DataBuffer(0))); | 146 it->Run(scoped_refptr<Buffer>(new DataBuffer(0))); |
147 } | 147 } |
148 read_queue_.clear(); | 148 read_queue_.clear(); |
149 stopped_ = true; | 149 stopped_ = true; |
150 } | 150 } |
151 | 151 |
152 base::TimeDelta FFmpegDemuxerStream::duration() { | 152 base::TimeDelta FFmpegDemuxerStream::duration() { |
153 return duration_; | 153 return duration_; |
154 } | 154 } |
155 | 155 |
156 int FFmpegDemuxerStream::stream_index() { | |
157 return stream_->index; | |
158 } | |
159 | |
156 DemuxerStream::Type FFmpegDemuxerStream::type() { | 160 DemuxerStream::Type FFmpegDemuxerStream::type() { |
157 return type_; | 161 return type_; |
158 } | 162 } |
159 | 163 |
160 void FFmpegDemuxerStream::Read(const ReadCallback& read_callback) { | 164 void FFmpegDemuxerStream::Read(const ReadCallback& read_callback) { |
161 DCHECK(!read_callback.is_null()); | 165 DCHECK(!read_callback.is_null()); |
162 | 166 |
163 base::AutoLock auto_lock(lock_); | 167 base::AutoLock auto_lock(lock_); |
164 // Don't accept any additional reads if we've been told to stop. | 168 // Don't accept any additional reads if we've been told to stop. |
165 // The demuxer_ may have been destroyed in the pipleine thread. | 169 // The demuxer_ may have been destroyed in the pipleine thread. |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
483 streams_.resize(DemuxerStream::NUM_TYPES); | 487 streams_.resize(DemuxerStream::NUM_TYPES); |
484 base::TimeDelta max_duration; | 488 base::TimeDelta max_duration; |
485 bool no_supported_streams = true; | 489 bool no_supported_streams = true; |
486 for (size_t i = 0; i < format_context_->nb_streams; ++i) { | 490 for (size_t i = 0; i < format_context_->nb_streams; ++i) { |
487 AVCodecContext* codec_context = format_context_->streams[i]->codec; | 491 AVCodecContext* codec_context = format_context_->streams[i]->codec; |
488 AVMediaType codec_type = codec_context->codec_type; | 492 AVMediaType codec_type = codec_context->codec_type; |
489 if (codec_type == AVMEDIA_TYPE_AUDIO || codec_type == AVMEDIA_TYPE_VIDEO) { | 493 if (codec_type == AVMEDIA_TYPE_AUDIO || codec_type == AVMEDIA_TYPE_VIDEO) { |
490 AVStream* stream = format_context_->streams[i]; | 494 AVStream* stream = format_context_->streams[i]; |
491 scoped_refptr<FFmpegDemuxerStream> demuxer_stream( | 495 scoped_refptr<FFmpegDemuxerStream> demuxer_stream( |
492 new FFmpegDemuxerStream(this, stream)); | 496 new FFmpegDemuxerStream(this, stream)); |
497 | |
493 if (!streams_[demuxer_stream->type()]) { | 498 if (!streams_[demuxer_stream->type()]) { |
494 no_supported_streams = false; | 499 no_supported_streams = false; |
495 streams_[demuxer_stream->type()] = demuxer_stream; | 500 streams_[demuxer_stream->type()] = demuxer_stream; |
496 max_duration = std::max(max_duration, demuxer_stream->duration()); | 501 max_duration = std::max(max_duration, demuxer_stream->duration()); |
497 | 502 |
498 if (stream->first_dts != static_cast<int64_t>(AV_NOPTS_VALUE)) { | 503 if (stream->first_dts != static_cast<int64_t>(AV_NOPTS_VALUE)) { |
499 const base::TimeDelta first_dts = ConvertFromTimeBase( | 504 const base::TimeDelta first_dts = ConvertFromTimeBase( |
500 stream->time_base, stream->first_dts); | 505 stream->time_base, stream->first_dts); |
501 if (start_time_ == kNoTimestamp || first_dts < start_time_) | 506 if (start_time_ == kNoTimestamp || first_dts < start_time_) |
502 start_time_ = first_dts; | 507 start_time_ = first_dts; |
503 } | 508 } |
504 } | 509 } |
505 packet_streams_.push_back(demuxer_stream); | |
506 } else { | |
507 packet_streams_.push_back(NULL); | |
508 } | 510 } |
509 } | 511 } |
510 if (no_supported_streams) { | 512 if (no_supported_streams) { |
511 callback.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); | 513 callback.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); |
512 return; | 514 return; |
513 } | 515 } |
514 if (format_context_->duration != static_cast<int64_t>(AV_NOPTS_VALUE)) { | 516 if (format_context_->duration != static_cast<int64_t>(AV_NOPTS_VALUE)) { |
515 // If there is a duration value in the container use that to find the | 517 // If there is a duration value in the container use that to find the |
516 // maximum between it and the duration from A/V streams. | 518 // maximum between it and the duration from A/V streams. |
517 const AVRational av_time_base = {1, AV_TIME_BASE}; | 519 const AVRational av_time_base = {1, AV_TIME_BASE}; |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
634 // If we have reached the end of stream, tell the downstream filters about | 636 // If we have reached the end of stream, tell the downstream filters about |
635 // the event. | 637 // the event. |
636 StreamHasEnded(); | 638 StreamHasEnded(); |
637 return; | 639 return; |
638 } | 640 } |
639 | 641 |
640 // Queue the packet with the appropriate stream. | 642 // Queue the packet with the appropriate stream. |
641 // TODO(scherkus): should we post this back to the pipeline thread? I'm | 643 // TODO(scherkus): should we post this back to the pipeline thread? I'm |
642 // worried about downstream filters (i.e., decoders) executing on this | 644 // worried about downstream filters (i.e., decoders) executing on this |
643 // thread. | 645 // thread. |
644 DCHECK_GE(packet->stream_index, 0); | 646 for (StreamVector::iterator iter = streams_.begin(); |
acolwell GONE FROM CHROMIUM
2011/12/13 16:45:44
I don't feel good about this iteration happening o
scherkus (not reviewing)
2011/12/13 17:24:56
This loop unrolls to checking streams_[AUDIO]->str
| |
645 DCHECK_LT(packet->stream_index, static_cast<int>(packet_streams_.size())); | 647 iter != streams_.end(); |
646 FFmpegDemuxerStream* demuxer_stream = NULL; | 648 ++iter) { |
647 size_t i = packet->stream_index; | 649 if ((*iter) && (*iter)->stream_index() == packet->stream_index) { |
648 // Defend against ffmpeg giving us a bad stream index. | |
649 if (i < packet_streams_.size()) { | |
650 demuxer_stream = packet_streams_[i]; | |
651 } | |
652 if (demuxer_stream) { | |
653 // Queue the packet with the appropriate stream. The stream takes | |
654 // ownership of the AVPacket. | |
655 if (packet.get()) { | |
656 // If a packet is returned by FFmpeg's av_parser_parse2() | 650 // If a packet is returned by FFmpeg's av_parser_parse2() |
657 // the packet will reference an inner memory of FFmpeg. | 651 // the packet will reference an inner memory of FFmpeg. |
658 // In this case, the packet's "destruct" member is NULL, | 652 // In this case, the packet's "destruct" member is NULL, |
659 // and it MUST be duplicated. This fixes issue with MP3 and possibly | 653 // and it MUST be duplicated. This fixes issue with MP3 and possibly |
660 // other codecs. It is safe to call this function even if the packet does | 654 // other codecs. It is safe to call this function even if the packet does |
661 // not refer to inner memory from FFmpeg. | 655 // not refer to inner memory from FFmpeg. |
662 av_dup_packet(packet.get()); | 656 av_dup_packet(packet.get()); |
663 demuxer_stream->EnqueuePacket(packet.release()); | 657 |
658 // Queue the packet with the appropriate stream. The stream takes | |
659 // ownership of the AVPacket. | |
660 (*iter)->EnqueuePacket(packet.release()); | |
661 break; | |
664 } | 662 } |
665 } | 663 } |
666 | 664 |
667 // Create a loop by posting another task. This allows seek and message loop | 665 // Create a loop by posting another task. This allows seek and message loop |
668 // quit tasks to get processed. | 666 // quit tasks to get processed. |
669 if (StreamsHavePendingReads()) { | 667 if (StreamsHavePendingReads()) { |
670 PostDemuxTask(); | 668 PostDemuxTask(); |
671 } | 669 } |
672 } | 670 } |
673 | 671 |
674 void FFmpegDemuxer::StopTask(const base::Closure& callback) { | 672 void FFmpegDemuxer::StopTask(const base::Closure& callback) { |
675 DCHECK_EQ(MessageLoop::current(), message_loop_); | 673 DCHECK_EQ(MessageLoop::current(), message_loop_); |
676 StreamVector::iterator iter; | 674 StreamVector::iterator iter; |
677 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 675 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
678 if (*iter) | 676 if (*iter) |
679 (*iter)->Stop(); | 677 (*iter)->Stop(); |
680 } | 678 } |
681 if (data_source_) { | 679 if (data_source_) { |
682 data_source_->Stop(callback); | 680 data_source_->Stop(callback); |
683 } else { | 681 } else { |
684 callback.Run(); | 682 callback.Run(); |
685 } | 683 } |
686 } | 684 } |
687 | 685 |
688 void FFmpegDemuxer::DisableAudioStreamTask() { | 686 void FFmpegDemuxer::DisableAudioStreamTask() { |
689 DCHECK_EQ(MessageLoop::current(), message_loop_); | 687 DCHECK_EQ(MessageLoop::current(), message_loop_); |
690 | 688 |
691 StreamVector::iterator iter; | 689 if (streams_[DemuxerStream::AUDIO]) { |
692 for (size_t i = 0; i < packet_streams_.size(); ++i) { | 690 streams_[DemuxerStream::AUDIO]->Stop(); |
693 if (!packet_streams_[i]) | |
694 continue; | |
695 | |
696 // If the codec type is audio, remove the reference. DemuxTask() will | |
697 // look for such reference, and this will result in deleting the | |
698 // audio packets after they are demuxed. | |
699 if (packet_streams_[i]->type() == DemuxerStream::AUDIO) { | |
700 packet_streams_[i] = NULL; | |
701 } | |
702 } | 691 } |
703 } | 692 } |
704 | 693 |
705 bool FFmpegDemuxer::StreamsHavePendingReads() { | 694 bool FFmpegDemuxer::StreamsHavePendingReads() { |
706 DCHECK_EQ(MessageLoop::current(), message_loop_); | 695 DCHECK_EQ(MessageLoop::current(), message_loop_); |
707 StreamVector::iterator iter; | 696 StreamVector::iterator iter; |
708 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 697 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
709 if (*iter && (*iter)->HasPendingReads()) { | 698 if (*iter && (*iter)->HasPendingReads()) { |
710 return true; | 699 return true; |
711 } | 700 } |
(...skipping 21 matching lines...) Expand all Loading... | |
733 read_event_.Wait(); | 722 read_event_.Wait(); |
734 return last_read_bytes_; | 723 return last_read_bytes_; |
735 } | 724 } |
736 | 725 |
737 void FFmpegDemuxer::SignalReadCompleted(size_t size) { | 726 void FFmpegDemuxer::SignalReadCompleted(size_t size) { |
738 last_read_bytes_ = size; | 727 last_read_bytes_ = size; |
739 read_event_.Signal(); | 728 read_event_.Signal(); |
740 } | 729 } |
741 | 730 |
742 } // namespace media | 731 } // namespace media |
OLD | NEW |