| 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 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 private: | 84 private: |
| 85 static void RunCallback(ReadCallback cb, scoped_refptr<Buffer> buffer); | 85 static void RunCallback(ReadCallback cb, scoped_refptr<Buffer> buffer); |
| 86 | 86 |
| 87 Type type_; | 87 Type type_; |
| 88 AVStream* av_stream_; | 88 AVStream* av_stream_; |
| 89 | 89 |
| 90 mutable base::Lock lock_; | 90 mutable base::Lock lock_; |
| 91 ReadCBQueue read_cbs_; | 91 ReadCBQueue read_cbs_; |
| 92 BufferQueue buffers_; | 92 BufferQueue buffers_; |
| 93 bool shutdown_called_; | 93 bool shutdown_called_; |
| 94 bool received_end_of_stream_; |
| 94 | 95 |
| 95 // Keeps track of the timestamp of the last buffer we have | 96 // Keeps track of the timestamp of the last buffer we have |
| 96 // added to |buffers_|. This is used to enforce buffers with strictly | 97 // added to |buffers_|. This is used to enforce buffers with strictly |
| 97 // monotonically increasing timestamps. | 98 // monotonically increasing timestamps. |
| 98 base::TimeDelta last_buffer_timestamp_; | 99 base::TimeDelta last_buffer_timestamp_; |
| 99 | 100 |
| 100 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); | 101 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); |
| 101 }; | 102 }; |
| 102 | 103 |
| 103 ChunkDemuxerStream::ChunkDemuxerStream(Type type, AVStream* stream) | 104 ChunkDemuxerStream::ChunkDemuxerStream(Type type, AVStream* stream) |
| 104 : type_(type), | 105 : type_(type), |
| 105 av_stream_(stream), | 106 av_stream_(stream), |
| 106 shutdown_called_(false), | 107 shutdown_called_(false), |
| 108 received_end_of_stream_(false), |
| 107 last_buffer_timestamp_(kNoTimestamp) { | 109 last_buffer_timestamp_(kNoTimestamp) { |
| 108 } | 110 } |
| 109 | 111 |
| 110 ChunkDemuxerStream::~ChunkDemuxerStream() {} | 112 ChunkDemuxerStream::~ChunkDemuxerStream() {} |
| 111 | 113 |
| 112 void ChunkDemuxerStream::Flush() { | 114 void ChunkDemuxerStream::Flush() { |
| 113 VLOG(1) << "Flush()"; | 115 VLOG(1) << "Flush()"; |
| 114 base::AutoLock auto_lock(lock_); | 116 base::AutoLock auto_lock(lock_); |
| 115 buffers_.clear(); | 117 buffers_.clear(); |
| 118 received_end_of_stream_ = false; |
| 116 last_buffer_timestamp_ = kNoTimestamp; | 119 last_buffer_timestamp_ = kNoTimestamp; |
| 117 } | 120 } |
| 118 | 121 |
| 119 bool ChunkDemuxerStream::CanAddBuffers(const BufferQueue& buffers) const { | 122 bool ChunkDemuxerStream::CanAddBuffers(const BufferQueue& buffers) const { |
| 120 base::AutoLock auto_lock(lock_); | 123 base::AutoLock auto_lock(lock_); |
| 121 | 124 |
| 122 // If we haven't seen any buffers yet than anything can be added. | 125 // If we haven't seen any buffers yet than anything can be added. |
| 123 if (last_buffer_timestamp_ == kNoTimestamp) | 126 if (last_buffer_timestamp_ == kNoTimestamp) |
| 124 return true; | 127 return true; |
| 125 | 128 |
| 126 if (buffers.empty()) | 129 if (buffers.empty()) |
| 127 return true; | 130 return true; |
| 128 | 131 |
| 129 return (buffers.front()->GetTimestamp() > last_buffer_timestamp_); | 132 return (buffers.front()->GetTimestamp() > last_buffer_timestamp_); |
| 130 } | 133 } |
| 131 | 134 |
| 132 void ChunkDemuxerStream::AddBuffers(const BufferQueue& buffers) { | 135 void ChunkDemuxerStream::AddBuffers(const BufferQueue& buffers) { |
| 133 if (buffers.empty()) | 136 if (buffers.empty()) |
| 134 return; | 137 return; |
| 135 | 138 |
| 136 std::deque<base::Closure> callbacks; | 139 std::deque<base::Closure> callbacks; |
| 137 { | 140 { |
| 138 base::AutoLock auto_lock(lock_); | 141 base::AutoLock auto_lock(lock_); |
| 139 | 142 |
| 140 for (BufferQueue::const_iterator itr = buffers.begin(); | 143 for (BufferQueue::const_iterator itr = buffers.begin(); |
| 141 itr != buffers.end(); itr++) { | 144 itr != buffers.end(); itr++) { |
| 145 // Make sure we aren't trying to add a buffer after we have received and |
| 146 // "end of stream" buffer. |
| 147 DCHECK(!received_end_of_stream_); |
| 142 | 148 |
| 143 if (!(*itr)->IsEndOfStream()) { | 149 if ((*itr)->IsEndOfStream()) { |
| 150 received_end_of_stream_ = true; |
| 151 |
| 152 // Push enough EOS buffers to satisfy outstanding Read() requests. |
| 153 if (read_cbs_.size() > buffers_.size()) { |
| 154 size_t pending_read_without_data = read_cbs_.size() - buffers_.size(); |
| 155 for (size_t i = 0; i <= pending_read_without_data; ++i) { |
| 156 buffers_.push_back(*itr); |
| 157 } |
| 158 } |
| 159 } else { |
| 144 base::TimeDelta current_ts = (*itr)->GetTimestamp(); | 160 base::TimeDelta current_ts = (*itr)->GetTimestamp(); |
| 145 if (last_buffer_timestamp_ != kNoTimestamp) { | 161 if (last_buffer_timestamp_ != kNoTimestamp) { |
| 146 DCHECK_GT(current_ts.ToInternalValue(), | 162 DCHECK_GT(current_ts.ToInternalValue(), |
| 147 last_buffer_timestamp_.ToInternalValue()); | 163 last_buffer_timestamp_.ToInternalValue()); |
| 148 } | 164 } |
| 149 | 165 |
| 150 last_buffer_timestamp_ = current_ts; | 166 last_buffer_timestamp_ = current_ts; |
| 167 buffers_.push_back(*itr); |
| 151 } | 168 } |
| 152 | |
| 153 buffers_.push_back(*itr); | |
| 154 } | 169 } |
| 155 | 170 |
| 156 while (!buffers_.empty() && !read_cbs_.empty()) { | 171 while (!buffers_.empty() && !read_cbs_.empty()) { |
| 157 callbacks.push_back(base::Bind(&ChunkDemuxerStream::RunCallback, | 172 callbacks.push_back(base::Bind(&ChunkDemuxerStream::RunCallback, |
| 158 read_cbs_.front(), | 173 read_cbs_.front(), |
| 159 buffers_.front())); | 174 buffers_.front())); |
| 160 buffers_.pop_front(); | 175 buffers_.pop_front(); |
| 161 read_cbs_.pop_front(); | 176 read_cbs_.pop_front(); |
| 162 } | 177 } |
| 163 } | 178 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 read_callback.Run(buffer); | 238 read_callback.Run(buffer); |
| 224 } | 239 } |
| 225 | 240 |
| 226 // DemuxerStream methods. | 241 // DemuxerStream methods. |
| 227 void ChunkDemuxerStream::Read(const ReadCallback& read_callback) { | 242 void ChunkDemuxerStream::Read(const ReadCallback& read_callback) { |
| 228 scoped_refptr<Buffer> buffer; | 243 scoped_refptr<Buffer> buffer; |
| 229 | 244 |
| 230 { | 245 { |
| 231 base::AutoLock auto_lock(lock_); | 246 base::AutoLock auto_lock(lock_); |
| 232 | 247 |
| 233 if (shutdown_called_) { | 248 if (shutdown_called_ || (received_end_of_stream_ && buffers_.empty())) { |
| 234 buffer = CreateEOSBuffer(); | 249 buffer = CreateEOSBuffer(); |
| 235 } else { | 250 } else { |
| 236 if (buffers_.empty()) { | 251 if (buffers_.empty()) { |
| 237 // Wrap & store |read_callback| so that it will | 252 // Wrap & store |read_callback| so that it will |
| 238 // get called on the current MessageLoop. | 253 // get called on the current MessageLoop. |
| 239 read_cbs_.push_back(base::Bind(&RunOnMessageLoop, | 254 read_cbs_.push_back(base::Bind(&RunOnMessageLoop, |
| 240 read_callback, | 255 read_callback, |
| 241 MessageLoop::current())); | 256 MessageLoop::current())); |
| 242 return; | 257 return; |
| 243 } | 258 } |
| (...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 700 base::AutoUnlock auto_unlock(lock_); | 715 base::AutoUnlock auto_unlock(lock_); |
| 701 if (cb.is_null()) { | 716 if (cb.is_null()) { |
| 702 host()->SetError(error); | 717 host()->SetError(error); |
| 703 return; | 718 return; |
| 704 } | 719 } |
| 705 cb.Run(error); | 720 cb.Run(error); |
| 706 } | 721 } |
| 707 } | 722 } |
| 708 | 723 |
| 709 } // namespace media | 724 } // namespace media |
| OLD | NEW |