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 #include <limits> | 9 #include <limits> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/callback_helpers.h" | 12 #include "base/callback_helpers.h" |
13 #include "base/location.h" | 13 #include "base/location.h" |
14 #include "base/message_loop_proxy.h" | 14 #include "base/message_loop_proxy.h" |
15 #include "media/base/audio_decoder_config.h" | 15 #include "media/base/audio_decoder_config.h" |
16 #include "media/base/stream_parser_buffer.h" | 16 #include "media/base/stream_parser_buffer.h" |
17 #include "media/base/video_decoder_config.h" | 17 #include "media/base/video_decoder_config.h" |
18 #include "media/filters/stream_parser_factory.h" | 18 #include "media/filters/stream_parser_factory.h" |
19 | 19 |
20 using base::TimeDelta; | 20 using base::TimeDelta; |
21 | 21 |
22 namespace media { | 22 namespace media { |
23 | 23 |
24 // Contains state belonging to a source id. | |
25 class SourceState { | |
scherkus (not reviewing)
2013/04/05 18:58:26
does it make any sense to split this class out + u
acolwell GONE FROM CHROMIUM
2013/04/05 19:14:37
I'm not sure it quite makes sense yet. I think Chu
| |
26 public: | |
27 explicit SourceState(scoped_ptr<StreamParser> stream_parser); | |
28 | |
29 void Init(const StreamParser::InitCB& init_cb, | |
30 const StreamParser::NewConfigCB& config_cb, | |
31 const StreamParser::NewBuffersCB& audio_cb, | |
32 const StreamParser::NewBuffersCB& video_cb, | |
33 const StreamParser::NeedKeyCB& need_key_cb, | |
34 const StreamParser::NewMediaSegmentCB& new_segment_cb, | |
35 const LogCB& log_cb); | |
36 | |
37 // Appends new data to the StreamParser. | |
38 // Returns true if the data was successfully appended. Returns false if an | |
39 // error occurred. | |
40 bool Append(const uint8* data, size_t length); | |
41 | |
42 // Aborts the current append sequence and resets the parser. | |
43 void Abort(); | |
44 | |
45 // Sets |timestamp_offset_| if possible. | |
46 // Returns if the offset was set. Returns false if the offset could not be | |
47 // updated at this time. | |
48 bool SetTimestampOffset(TimeDelta timestamp_offset); | |
49 | |
50 TimeDelta timestamp_offset() const { return timestamp_offset_; } | |
51 | |
52 private: | |
53 // Called by the |stream_parser_| at the beginning of a new media segment. | |
54 // |timestamp| is the timestamp on the first buffer in the segment. | |
55 // It modifies the state of this object and then calls |new_segment_cb| with | |
56 // modified version of |timestamp|. | |
57 void OnNewMediaSegment(const StreamParser::NewMediaSegmentCB& new_segment_cb, | |
58 TimeDelta timestamp); | |
59 | |
60 // Called by the |stream_parser_| at the end of a media segment. | |
61 void OnEndOfMediaSegment(); | |
62 | |
63 // Called by the |stream_parser_| when new buffers have been parsed. It | |
64 // applies |timestamp_offset_| to all buffers in |buffers| and then calls | |
65 // |new_buffers_cb| with the modified buffers. | |
66 // Returns true on a successful call. Returns false if an error occured while | |
67 // processing the buffers. | |
68 bool OnBuffers(const StreamParser::NewBuffersCB& new_buffers_cb, | |
69 const StreamParser::BufferQueue& buffers); | |
70 | |
71 // Helper function that adds |timestamp_offset_| to each buffer in |buffers|. | |
72 void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers); | |
73 | |
74 // The offset to apply to media segment timestamps. | |
75 TimeDelta timestamp_offset_; | |
76 | |
77 // Keeps track of whether |timestamp_offset_| can be modified. | |
78 bool can_update_offset_; | |
79 | |
80 // The object used to parse appended data. | |
81 scoped_ptr<StreamParser> stream_parser_; | |
82 | |
83 DISALLOW_COPY_AND_ASSIGN(SourceState); | |
84 }; | |
85 | |
86 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser) | |
87 : can_update_offset_(true), | |
88 stream_parser_(stream_parser.release()) { | |
89 } | |
90 | |
91 void SourceState::Init(const StreamParser::InitCB& init_cb, | |
92 const StreamParser::NewConfigCB& config_cb, | |
93 const StreamParser::NewBuffersCB& audio_cb, | |
94 const StreamParser::NewBuffersCB& video_cb, | |
95 const StreamParser::NeedKeyCB& need_key_cb, | |
96 const StreamParser::NewMediaSegmentCB& new_segment_cb, | |
97 const LogCB& log_cb) { | |
98 stream_parser_->Init(init_cb, config_cb, | |
99 base::Bind(&SourceState::OnBuffers, | |
100 base::Unretained(this), audio_cb), | |
101 base::Bind(&SourceState::OnBuffers, | |
102 base::Unretained(this), video_cb), | |
103 need_key_cb, | |
104 base::Bind(&SourceState::OnNewMediaSegment, | |
105 base::Unretained(this), new_segment_cb), | |
106 base::Bind(&SourceState::OnEndOfMediaSegment, | |
107 base::Unretained(this)), | |
108 log_cb); | |
109 } | |
110 | |
111 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) { | |
112 if (!can_update_offset_) | |
113 return false; | |
114 | |
115 timestamp_offset_ = timestamp_offset; | |
116 return true; | |
117 } | |
118 | |
119 bool SourceState::Append(const uint8* data, size_t length) { | |
120 return stream_parser_->Parse(data, length); | |
121 } | |
122 | |
123 void SourceState::Abort() { | |
124 stream_parser_->Flush(); | |
125 can_update_offset_ = true; | |
126 } | |
127 | |
128 void SourceState::AdjustBufferTimestamps( | |
129 const StreamParser::BufferQueue& buffers) { | |
130 if (timestamp_offset_ == TimeDelta()) | |
131 return; | |
132 | |
133 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); | |
134 itr != buffers.end(); ++itr) { | |
135 (*itr)->SetDecodeTimestamp( | |
136 (*itr)->GetDecodeTimestamp() + timestamp_offset_); | |
137 (*itr)->SetTimestamp((*itr)->GetTimestamp() + timestamp_offset_); | |
138 } | |
139 } | |
140 | |
141 void SourceState::OnNewMediaSegment( | |
142 const StreamParser::NewMediaSegmentCB& new_segment_cb, | |
143 TimeDelta timestamp) { | |
144 DCHECK(timestamp != kNoTimestamp()); | |
145 DVLOG(2) << "OnNewMediaSegment(" << timestamp.InSecondsF() << ")"; | |
146 | |
147 can_update_offset_ = false; | |
148 new_segment_cb.Run(timestamp + timestamp_offset_); | |
149 } | |
150 | |
151 void SourceState::OnEndOfMediaSegment() { | |
152 DVLOG(2) << "OnEndOfMediaSegment()"; | |
153 can_update_offset_ = true; | |
154 } | |
155 | |
156 bool SourceState::OnBuffers(const StreamParser::NewBuffersCB& new_buffers_cb, | |
157 const StreamParser::BufferQueue& buffers) { | |
158 if (new_buffers_cb.is_null()) | |
159 return false; | |
160 | |
161 AdjustBufferTimestamps(buffers); | |
162 | |
163 return new_buffers_cb.Run(buffers); | |
164 } | |
24 | 165 |
25 class ChunkDemuxerStream : public DemuxerStream { | 166 class ChunkDemuxerStream : public DemuxerStream { |
26 public: | 167 public: |
27 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; | 168 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; |
28 typedef std::deque<ReadCB> ReadCBQueue; | 169 typedef std::deque<ReadCB> ReadCBQueue; |
29 typedef std::deque<base::Closure> ClosureQueue; | 170 typedef std::deque<base::Closure> ClosureQueue; |
30 | 171 |
31 ChunkDemuxerStream(const AudioDecoderConfig& audio_config, | 172 ChunkDemuxerStream(const AudioDecoderConfig& audio_config, |
32 const LogCB& log_cb); | 173 const LogCB& log_cb); |
33 ChunkDemuxerStream(const VideoDecoderConfig& video_config, | 174 ChunkDemuxerStream(const VideoDecoderConfig& video_config, |
(...skipping 492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
526 if (!cb.is_null()) | 667 if (!cb.is_null()) |
527 cb.Run(PIPELINE_OK); | 668 cb.Run(PIPELINE_OK); |
528 } | 669 } |
529 | 670 |
530 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, | 671 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, |
531 const std::string& type, | 672 const std::string& type, |
532 std::vector<std::string>& codecs) { | 673 std::vector<std::string>& codecs) { |
533 DCHECK_GT(codecs.size(), 0u); | 674 DCHECK_GT(codecs.size(), 0u); |
534 base::AutoLock auto_lock(lock_); | 675 base::AutoLock auto_lock(lock_); |
535 | 676 |
536 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || | 677 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id)) |
537 stream_parser_map_.count(id) > 0u) | |
538 return kReachedIdLimit; | 678 return kReachedIdLimit; |
539 | 679 |
540 bool has_audio = false; | 680 bool has_audio = false; |
541 bool has_video = false; | 681 bool has_video = false; |
542 scoped_ptr<media::StreamParser> stream_parser( | 682 scoped_ptr<media::StreamParser> stream_parser( |
543 StreamParserFactory::Create(type, codecs, log_cb_, | 683 StreamParserFactory::Create(type, codecs, log_cb_, |
544 &has_audio, &has_video)); | 684 &has_audio, &has_video)); |
545 | 685 |
546 if (!stream_parser) | 686 if (!stream_parser) |
547 return ChunkDemuxer::kNotSupported; | 687 return ChunkDemuxer::kNotSupported; |
(...skipping 10 matching lines...) Expand all Loading... | |
558 audio_cb = base::Bind(&ChunkDemuxer::OnAudioBuffers, | 698 audio_cb = base::Bind(&ChunkDemuxer::OnAudioBuffers, |
559 base::Unretained(this)); | 699 base::Unretained(this)); |
560 } | 700 } |
561 | 701 |
562 if (has_video) { | 702 if (has_video) { |
563 source_id_video_ = id; | 703 source_id_video_ = id; |
564 video_cb = base::Bind(&ChunkDemuxer::OnVideoBuffers, | 704 video_cb = base::Bind(&ChunkDemuxer::OnVideoBuffers, |
565 base::Unretained(this)); | 705 base::Unretained(this)); |
566 } | 706 } |
567 | 707 |
568 stream_parser->Init( | 708 scoped_ptr<SourceState> source_state(new SourceState(stream_parser.Pass())); |
569 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, base::Unretained(this)), | 709 source_state->Init( |
710 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), | |
570 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), | 711 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), |
571 has_audio, has_video), | 712 has_audio, has_video), |
572 audio_cb, | 713 audio_cb, |
573 video_cb, | 714 video_cb, |
574 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), | 715 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), |
575 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id), | 716 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id), |
576 base::Bind(&ChunkDemuxer::OnEndOfMediaSegment, | |
577 base::Unretained(this), id), | |
578 log_cb_); | 717 log_cb_); |
579 | 718 |
580 stream_parser_map_[id] = stream_parser.release(); | 719 source_state_map_[id] = source_state.release(); |
581 SourceInfo info = { base::TimeDelta(), true }; | |
582 source_info_map_[id] = info; | |
583 | |
584 return kOk; | 720 return kOk; |
585 } | 721 } |
586 | 722 |
587 void ChunkDemuxer::RemoveId(const std::string& id) { | 723 void ChunkDemuxer::RemoveId(const std::string& id) { |
588 base::AutoLock auto_lock(lock_); | 724 base::AutoLock auto_lock(lock_); |
589 CHECK(IsValidId(id)); | 725 CHECK(IsValidId(id)); |
590 | 726 |
591 delete stream_parser_map_[id]; | 727 delete source_state_map_[id]; |
592 stream_parser_map_.erase(id); | 728 source_state_map_.erase(id); |
593 source_info_map_.erase(id); | |
594 | 729 |
595 if (source_id_audio_ == id) { | 730 if (source_id_audio_ == id) { |
596 if (audio_) | 731 if (audio_) |
597 audio_->Shutdown(); | 732 audio_->Shutdown(); |
598 source_id_audio_.clear(); | 733 source_id_audio_.clear(); |
599 } | 734 } |
600 | 735 |
601 if (source_id_video_ == id) { | 736 if (source_id_video_ == id) { |
602 if (video_) | 737 if (video_) |
603 video_->Shutdown(); | 738 video_->Shutdown(); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
682 } | 817 } |
683 | 818 |
684 if (length == 0u) | 819 if (length == 0u) |
685 return; | 820 return; |
686 | 821 |
687 DCHECK(data); | 822 DCHECK(data); |
688 | 823 |
689 switch (state_) { | 824 switch (state_) { |
690 case INITIALIZING: | 825 case INITIALIZING: |
691 DCHECK(IsValidId(id)); | 826 DCHECK(IsValidId(id)); |
692 if (!stream_parser_map_[id]->Parse(data, length)) { | 827 if (!source_state_map_[id]->Append(data, length)) { |
693 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); | 828 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
694 return; | 829 return; |
695 } | 830 } |
696 break; | 831 break; |
697 | 832 |
698 case INITIALIZED: { | 833 case INITIALIZED: { |
699 DCHECK(IsValidId(id)); | 834 DCHECK(IsValidId(id)); |
700 if (!stream_parser_map_[id]->Parse(data, length)) { | 835 if (!source_state_map_[id]->Append(data, length)) { |
701 ReportError_Locked(PIPELINE_ERROR_DECODE); | 836 ReportError_Locked(PIPELINE_ERROR_DECODE); |
702 return; | 837 return; |
703 } | 838 } |
704 } break; | 839 } break; |
705 | 840 |
706 case PARSE_ERROR: | 841 case PARSE_ERROR: |
707 DVLOG(1) << "AppendData(): Ignoring data after a parse error."; | 842 DVLOG(1) << "AppendData(): Ignoring data after a parse error."; |
708 return; | 843 return; |
709 | 844 |
710 case WAITING_FOR_INIT: | 845 case WAITING_FOR_INIT: |
(...skipping 17 matching lines...) Expand all Loading... | |
728 | 863 |
729 if (!cb.is_null()) | 864 if (!cb.is_null()) |
730 cb.Run(PIPELINE_OK); | 865 cb.Run(PIPELINE_OK); |
731 } | 866 } |
732 | 867 |
733 void ChunkDemuxer::Abort(const std::string& id) { | 868 void ChunkDemuxer::Abort(const std::string& id) { |
734 DVLOG(1) << "Abort(" << id << ")"; | 869 DVLOG(1) << "Abort(" << id << ")"; |
735 base::AutoLock auto_lock(lock_); | 870 base::AutoLock auto_lock(lock_); |
736 DCHECK(!id.empty()); | 871 DCHECK(!id.empty()); |
737 CHECK(IsValidId(id)); | 872 CHECK(IsValidId(id)); |
738 stream_parser_map_[id]->Flush(); | 873 source_state_map_[id]->Abort(); |
739 source_info_map_[id].can_update_offset = true; | |
740 } | 874 } |
741 | 875 |
742 double ChunkDemuxer::GetDuration() { | 876 double ChunkDemuxer::GetDuration() { |
743 base::AutoLock auto_lock(lock_); | 877 base::AutoLock auto_lock(lock_); |
744 return GetDuration_Locked(); | 878 return GetDuration_Locked(); |
745 } | 879 } |
746 | 880 |
747 double ChunkDemuxer::GetDuration_Locked() { | 881 double ChunkDemuxer::GetDuration_Locked() { |
748 lock_.AssertAcquired(); | 882 lock_.AssertAcquired(); |
749 if (duration_ == kNoTimestamp()) | 883 if (duration_ == kNoTimestamp()) |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
800 | 934 |
801 if (video_) | 935 if (video_) |
802 video_->OnSetDuration(duration_); | 936 video_->OnSetDuration(duration_); |
803 } | 937 } |
804 | 938 |
805 bool ChunkDemuxer::SetTimestampOffset(const std::string& id, TimeDelta offset) { | 939 bool ChunkDemuxer::SetTimestampOffset(const std::string& id, TimeDelta offset) { |
806 base::AutoLock auto_lock(lock_); | 940 base::AutoLock auto_lock(lock_); |
807 DVLOG(1) << "SetTimestampOffset(" << id << ", " << offset.InSecondsF() << ")"; | 941 DVLOG(1) << "SetTimestampOffset(" << id << ", " << offset.InSecondsF() << ")"; |
808 CHECK(IsValidId(id)); | 942 CHECK(IsValidId(id)); |
809 | 943 |
810 if (!source_info_map_[id].can_update_offset) | 944 return source_state_map_[id]->SetTimestampOffset(offset); |
811 return false; | |
812 | |
813 source_info_map_[id].timestamp_offset = offset; | |
814 return true; | |
815 } | 945 } |
816 | 946 |
817 bool ChunkDemuxer::EndOfStream(PipelineStatus status) { | 947 bool ChunkDemuxer::EndOfStream(PipelineStatus status) { |
818 DVLOG(1) << "EndOfStream(" << status << ")"; | 948 DVLOG(1) << "EndOfStream(" << status << ")"; |
819 base::AutoLock auto_lock(lock_); | 949 base::AutoLock auto_lock(lock_); |
820 DCHECK_NE(state_, WAITING_FOR_INIT); | 950 DCHECK_NE(state_, WAITING_FOR_INIT); |
821 DCHECK_NE(state_, ENDED); | 951 DCHECK_NE(state_, ENDED); |
822 | 952 |
823 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) | 953 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) |
824 return true; | 954 return true; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
873 | 1003 |
874 void ChunkDemuxer::ChangeState_Locked(State new_state) { | 1004 void ChunkDemuxer::ChangeState_Locked(State new_state) { |
875 lock_.AssertAcquired(); | 1005 lock_.AssertAcquired(); |
876 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : " | 1006 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : " |
877 << state_ << " -> " << new_state; | 1007 << state_ << " -> " << new_state; |
878 state_ = new_state; | 1008 state_ = new_state; |
879 } | 1009 } |
880 | 1010 |
881 ChunkDemuxer::~ChunkDemuxer() { | 1011 ChunkDemuxer::~ChunkDemuxer() { |
882 DCHECK_NE(state_, INITIALIZED); | 1012 DCHECK_NE(state_, INITIALIZED); |
883 for (StreamParserMap::iterator it = stream_parser_map_.begin(); | 1013 for (SourceStateMap::iterator it = source_state_map_.begin(); |
884 it != stream_parser_map_.end(); ++it) { | 1014 it != source_state_map_.end(); ++it) { |
885 delete it->second; | 1015 delete it->second; |
886 } | 1016 } |
887 stream_parser_map_.clear(); | 1017 source_state_map_.clear(); |
888 } | 1018 } |
889 | 1019 |
890 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { | 1020 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { |
891 DVLOG(1) << "ReportError_Locked(" << error << ")"; | 1021 DVLOG(1) << "ReportError_Locked(" << error << ")"; |
892 lock_.AssertAcquired(); | 1022 lock_.AssertAcquired(); |
893 DCHECK_NE(error, PIPELINE_OK); | 1023 DCHECK_NE(error, PIPELINE_OK); |
894 | 1024 |
895 ChangeState_Locked(PARSE_ERROR); | 1025 ChangeState_Locked(PARSE_ERROR); |
896 | 1026 |
897 PipelineStatusCB cb; | 1027 PipelineStatusCB cb; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
931 | 1061 |
932 return seek_pending; | 1062 return seek_pending; |
933 } | 1063 } |
934 | 1064 |
935 bool ChunkDemuxer::CanEndOfStream_Locked() const { | 1065 bool ChunkDemuxer::CanEndOfStream_Locked() const { |
936 lock_.AssertAcquired(); | 1066 lock_.AssertAcquired(); |
937 return (!audio_ || audio_->CanEndOfStream()) && | 1067 return (!audio_ || audio_->CanEndOfStream()) && |
938 (!video_ || video_->CanEndOfStream()); | 1068 (!video_ || video_->CanEndOfStream()); |
939 } | 1069 } |
940 | 1070 |
941 void ChunkDemuxer::OnStreamParserInitDone(bool success, TimeDelta duration) { | 1071 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { |
942 DVLOG(1) << "OnStreamParserInitDone(" << success << ", " | 1072 DVLOG(1) << "OnSourceInitDone(" << success << ", " |
943 << duration.InSecondsF() << ")"; | 1073 << duration.InSecondsF() << ")"; |
944 lock_.AssertAcquired(); | 1074 lock_.AssertAcquired(); |
945 DCHECK_EQ(state_, INITIALIZING); | 1075 DCHECK_EQ(state_, INITIALIZING); |
946 if (!success || (!audio_ && !video_)) { | 1076 if (!success || (!audio_ && !video_)) { |
947 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); | 1077 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
948 return; | 1078 return; |
949 } | 1079 } |
950 | 1080 |
951 if (duration != base::TimeDelta() && duration_ == kNoTimestamp()) | 1081 if (duration != base::TimeDelta() && duration_ == kNoTimestamp()) |
952 UpdateDuration(duration); | 1082 UpdateDuration(duration); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1029 } | 1159 } |
1030 | 1160 |
1031 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { | 1161 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { |
1032 lock_.AssertAcquired(); | 1162 lock_.AssertAcquired(); |
1033 DCHECK_NE(state_, SHUTDOWN); | 1163 DCHECK_NE(state_, SHUTDOWN); |
1034 | 1164 |
1035 if (!audio_) | 1165 if (!audio_) |
1036 return false; | 1166 return false; |
1037 | 1167 |
1038 CHECK(IsValidId(source_id_audio_)); | 1168 CHECK(IsValidId(source_id_audio_)); |
1039 AdjustBufferTimestamps( | |
1040 buffers, source_info_map_[source_id_audio_].timestamp_offset); | |
1041 | |
1042 if (!audio_->Append(buffers)) | 1169 if (!audio_->Append(buffers)) |
1043 return false; | 1170 return false; |
1044 | 1171 |
1045 IncreaseDurationIfNecessary(buffers, audio_); | 1172 IncreaseDurationIfNecessary(buffers, audio_); |
1046 return true; | 1173 return true; |
1047 } | 1174 } |
1048 | 1175 |
1049 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { | 1176 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { |
1050 lock_.AssertAcquired(); | 1177 lock_.AssertAcquired(); |
1051 DCHECK_NE(state_, SHUTDOWN); | 1178 DCHECK_NE(state_, SHUTDOWN); |
1052 | 1179 |
1053 if (!video_) | 1180 if (!video_) |
1054 return false; | 1181 return false; |
1055 | 1182 |
1056 CHECK(IsValidId(source_id_video_)); | 1183 CHECK(IsValidId(source_id_video_)); |
1057 AdjustBufferTimestamps( | |
1058 buffers, source_info_map_[source_id_video_].timestamp_offset); | |
1059 | |
1060 if (!video_->Append(buffers)) | 1184 if (!video_->Append(buffers)) |
1061 return false; | 1185 return false; |
1062 | 1186 |
1063 IncreaseDurationIfNecessary(buffers, video_); | 1187 IncreaseDurationIfNecessary(buffers, video_); |
1064 return true; | 1188 return true; |
1065 } | 1189 } |
1066 | 1190 |
1067 // TODO(acolwell): Remove bool from StreamParser::NeedKeyCB so that | 1191 // TODO(acolwell): Remove bool from StreamParser::NeedKeyCB so that |
1068 // this method can be removed and need_key_cb_ can be passed directly | 1192 // this method can be removed and need_key_cb_ can be passed directly |
1069 // to the parser. | 1193 // to the parser. |
1070 bool ChunkDemuxer::OnNeedKey(const std::string& type, | 1194 bool ChunkDemuxer::OnNeedKey(const std::string& type, |
1071 scoped_array<uint8> init_data, | 1195 scoped_array<uint8> init_data, |
1072 int init_data_size) { | 1196 int init_data_size) { |
1073 lock_.AssertAcquired(); | 1197 lock_.AssertAcquired(); |
1074 need_key_cb_.Run(type, init_data.Pass(), init_data_size); | 1198 need_key_cb_.Run(type, init_data.Pass(), init_data_size); |
1075 return true; | 1199 return true; |
1076 } | 1200 } |
1077 | 1201 |
1078 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, | 1202 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, |
1079 TimeDelta timestamp) { | 1203 TimeDelta timestamp) { |
1080 DCHECK(timestamp != kNoTimestamp()); | 1204 DCHECK(timestamp != kNoTimestamp()); |
1081 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", " | 1205 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", " |
1082 << timestamp.InSecondsF() << ")"; | 1206 << timestamp.InSecondsF() << ")"; |
1083 lock_.AssertAcquired(); | 1207 lock_.AssertAcquired(); |
1084 | 1208 |
1085 CHECK(IsValidId(source_id)); | 1209 CHECK(IsValidId(source_id)); |
1086 source_info_map_[source_id].can_update_offset = false; | |
1087 base::TimeDelta start_timestamp = | |
1088 timestamp + source_info_map_[source_id].timestamp_offset; | |
1089 | |
1090 if (audio_ && source_id == source_id_audio_) | 1210 if (audio_ && source_id == source_id_audio_) |
1091 audio_->OnNewMediaSegment(start_timestamp); | 1211 audio_->OnNewMediaSegment(timestamp); |
1092 if (video_ && source_id == source_id_video_) | 1212 if (video_ && source_id == source_id_video_) |
1093 video_->OnNewMediaSegment(start_timestamp); | 1213 video_->OnNewMediaSegment(timestamp); |
1094 } | |
1095 | |
1096 void ChunkDemuxer::OnEndOfMediaSegment(const std::string& source_id) { | |
1097 DVLOG(2) << "OnEndOfMediaSegment(" << source_id << ")"; | |
1098 CHECK(IsValidId(source_id)); | |
1099 source_info_map_[source_id].can_update_offset = true; | |
1100 } | |
1101 | |
1102 void ChunkDemuxer::AdjustBufferTimestamps( | |
1103 const StreamParser::BufferQueue& buffers, | |
1104 base::TimeDelta timestamp_offset) { | |
1105 if (timestamp_offset == base::TimeDelta()) | |
1106 return; | |
1107 | |
1108 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); | |
1109 itr != buffers.end(); ++itr) { | |
1110 (*itr)->SetDecodeTimestamp( | |
1111 (*itr)->GetDecodeTimestamp() + timestamp_offset); | |
1112 (*itr)->SetTimestamp((*itr)->GetTimestamp() + timestamp_offset); | |
1113 } | |
1114 } | 1214 } |
1115 | 1215 |
1116 bool ChunkDemuxer::IsValidId(const std::string& source_id) const { | 1216 bool ChunkDemuxer::IsValidId(const std::string& source_id) const { |
1117 lock_.AssertAcquired(); | 1217 lock_.AssertAcquired(); |
1118 return source_info_map_.count(source_id) > 0u && | 1218 return source_state_map_.count(source_id) > 0u; |
1119 stream_parser_map_.count(source_id) > 0u; | |
1120 } | 1219 } |
1121 | 1220 |
1122 void ChunkDemuxer::UpdateDuration(base::TimeDelta new_duration) { | 1221 void ChunkDemuxer::UpdateDuration(base::TimeDelta new_duration) { |
1123 DCHECK(duration_ != new_duration); | 1222 DCHECK(duration_ != new_duration); |
1124 user_specified_duration_ = -1; | 1223 user_specified_duration_ = -1; |
1125 duration_ = new_duration; | 1224 duration_ = new_duration; |
1126 host_->SetDuration(new_duration); | 1225 host_->SetDuration(new_duration); |
1127 } | 1226 } |
1128 | 1227 |
1129 void ChunkDemuxer::IncreaseDurationIfNecessary( | 1228 void ChunkDemuxer::IncreaseDurationIfNecessary( |
(...skipping 23 matching lines...) Expand all Loading... | |
1153 | 1252 |
1154 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { | 1253 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { |
1155 if (audio_ && !video_) | 1254 if (audio_ && !video_) |
1156 return audio_->GetBufferedRanges(duration_); | 1255 return audio_->GetBufferedRanges(duration_); |
1157 else if (!audio_ && video_) | 1256 else if (!audio_ && video_) |
1158 return video_->GetBufferedRanges(duration_); | 1257 return video_->GetBufferedRanges(duration_); |
1159 return ComputeIntersection(); | 1258 return ComputeIntersection(); |
1160 } | 1259 } |
1161 | 1260 |
1162 } // namespace media | 1261 } // namespace media |
OLD | NEW |