| 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 "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "media/base/audio_decoder_config.h" | 10 #include "media/base/audio_decoder_config.h" |
| 11 #include "media/base/data_buffer.h" | 11 #include "media/base/data_buffer.h" |
| 12 #include "media/base/video_decoder_config.h" | 12 #include "media/base/video_decoder_config.h" |
| 13 #include "media/filters/chunk_demuxer_client.h" | 13 #include "media/filters/chunk_demuxer_client.h" |
| 14 #include "media/webm/webm_stream_parser.h" | 14 #include "media/webm/webm_stream_parser.h" |
| 15 | 15 |
| 16 namespace media { | 16 namespace media { |
| 17 | 17 |
| 18 // Create an "end of stream" buffer. | 18 // Create an "end of stream" buffer. |
| 19 static Buffer* CreateEOSBuffer() { | 19 static Buffer* CreateEOSBuffer() { |
| 20 return new DataBuffer(0); | 20 return new DataBuffer(0); |
| 21 } | 21 } |
| 22 | 22 |
| 23 class ChunkDemuxerStream : public DemuxerStream { | 23 class ChunkDemuxerStream : public DemuxerStream { |
| 24 public: | 24 public: |
| 25 typedef std::deque<scoped_refptr<Buffer> > BufferQueue; | 25 typedef std::deque<scoped_refptr<Buffer> > BufferQueue; |
| 26 typedef std::deque<ReadCallback> ReadCBQueue; | 26 typedef std::deque<ReadCallback> ReadCBQueue; |
| 27 typedef std::deque<base::Closure> ClosureQueue; |
| 27 | 28 |
| 28 explicit ChunkDemuxerStream(const AudioDecoderConfig& audio_config); | 29 explicit ChunkDemuxerStream(const AudioDecoderConfig& audio_config); |
| 29 explicit ChunkDemuxerStream(const VideoDecoderConfig& video_config); | 30 explicit ChunkDemuxerStream(const VideoDecoderConfig& video_config); |
| 30 virtual ~ChunkDemuxerStream(); | 31 virtual ~ChunkDemuxerStream(); |
| 31 | 32 |
| 32 void Flush(); | 33 void Flush(); |
| 34 void Seek(base::TimeDelta time); |
| 33 | 35 |
| 34 // Checks if it is ok to add the |buffers| to the stream. | 36 // Checks if it is ok to add the |buffers| to the stream. |
| 35 bool CanAddBuffers(const BufferQueue& buffers) const; | 37 bool CanAddBuffers(const BufferQueue& buffers) const; |
| 36 | 38 |
| 37 void AddBuffers(const BufferQueue& buffers); | 39 void AddBuffers(const BufferQueue& buffers); |
| 38 void Shutdown(); | 40 void Shutdown(); |
| 39 | 41 |
| 40 bool GetLastBufferTimestamp(base::TimeDelta* timestamp) const; | 42 bool GetLastBufferTimestamp(base::TimeDelta* timestamp) const; |
| 41 | 43 |
| 42 // DemuxerStream methods. | 44 // DemuxerStream methods. |
| 43 virtual void Read(const ReadCallback& read_callback); | 45 virtual void Read(const ReadCallback& read_callback) OVERRIDE; |
| 44 virtual Type type(); | 46 virtual Type type() OVERRIDE; |
| 45 virtual void EnableBitstreamConverter(); | 47 virtual void EnableBitstreamConverter() OVERRIDE; |
| 46 virtual const AudioDecoderConfig& audio_decoder_config(); | 48 virtual const AudioDecoderConfig& audio_decoder_config() OVERRIDE; |
| 47 virtual const VideoDecoderConfig& video_decoder_config(); | 49 virtual const VideoDecoderConfig& video_decoder_config() OVERRIDE; |
| 48 | 50 |
| 49 private: | 51 private: |
| 52 enum State { |
| 53 RETURNING_DATA_FOR_READS, |
| 54 WAITING_FOR_SEEK, |
| 55 RECEIVED_EOS_WHILE_WAITING_FOR_SEEK, // EOS = End of stream. |
| 56 RECEIVED_EOS, |
| 57 RETURNING_EOS_FOR_READS, |
| 58 SHUTDOWN, |
| 59 }; |
| 60 |
| 61 // Assigns |state_| to |state| |
| 62 void ChangeState_Locked(State state); |
| 63 |
| 64 // Adds the callback to |read_cbs_| so it can be called later when we |
| 65 // have data. |
| 66 void DeferRead_Locked(const ReadCallback& read_cb); |
| 67 |
| 68 // Creates closures that bind ReadCallbacks in |read_cbs_| to data in |
| 69 // |buffers_| and pops the callbacks & buffers from the respecive queues. |
| 70 void CreateReadDoneClosures_Locked(ClosureQueue* closures); |
| 71 |
| 50 Type type_; | 72 Type type_; |
| 51 AudioDecoderConfig audio_config_; | 73 AudioDecoderConfig audio_config_; |
| 52 VideoDecoderConfig video_config_; | 74 VideoDecoderConfig video_config_; |
| 53 | 75 |
| 54 mutable base::Lock lock_; | 76 mutable base::Lock lock_; |
| 77 State state_; |
| 55 ReadCBQueue read_cbs_; | 78 ReadCBQueue read_cbs_; |
| 56 BufferQueue buffers_; | 79 BufferQueue buffers_; |
| 57 bool shutdown_called_; | |
| 58 bool received_end_of_stream_; | |
| 59 | 80 |
| 60 // Keeps track of the timestamp of the last buffer we have | 81 // Keeps track of the timestamp of the last buffer we have |
| 61 // added to |buffers_|. This is used to enforce buffers with strictly | 82 // added to |buffers_|. This is used to enforce buffers with strictly |
| 62 // monotonically increasing timestamps. | 83 // monotonically increasing timestamps. |
| 63 base::TimeDelta last_buffer_timestamp_; | 84 base::TimeDelta last_buffer_timestamp_; |
| 64 | 85 |
| 65 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); | 86 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); |
| 66 }; | 87 }; |
| 67 | 88 |
| 68 ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config) | 89 ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config) |
| 69 : type_(AUDIO), | 90 : type_(AUDIO), |
| 70 shutdown_called_(false), | 91 state_(RETURNING_DATA_FOR_READS), |
| 71 received_end_of_stream_(false), | |
| 72 last_buffer_timestamp_(kNoTimestamp()) { | 92 last_buffer_timestamp_(kNoTimestamp()) { |
| 73 audio_config_.CopyFrom(audio_config); | 93 audio_config_.CopyFrom(audio_config); |
| 74 } | 94 } |
| 75 | 95 |
| 76 | 96 |
| 77 ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config) | 97 ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config) |
| 78 : type_(VIDEO), | 98 : type_(VIDEO), |
| 79 shutdown_called_(false), | 99 state_(RETURNING_DATA_FOR_READS), |
| 80 received_end_of_stream_(false), | |
| 81 last_buffer_timestamp_(kNoTimestamp()) { | 100 last_buffer_timestamp_(kNoTimestamp()) { |
| 82 video_config_.CopyFrom(video_config); | 101 video_config_.CopyFrom(video_config); |
| 83 } | 102 } |
| 84 | 103 |
| 85 ChunkDemuxerStream::~ChunkDemuxerStream() {} | 104 ChunkDemuxerStream::~ChunkDemuxerStream() {} |
| 86 | 105 |
| 87 void ChunkDemuxerStream::Flush() { | 106 void ChunkDemuxerStream::Flush() { |
| 88 DVLOG(1) << "Flush()"; | 107 DVLOG(1) << "Flush()"; |
| 108 ReadCBQueue read_cbs; |
| 109 { |
| 110 base::AutoLock auto_lock(lock_); |
| 111 buffers_.clear(); |
| 112 ChangeState_Locked(WAITING_FOR_SEEK); |
| 113 last_buffer_timestamp_ = kNoTimestamp(); |
| 114 |
| 115 std::swap(read_cbs_, read_cbs); |
| 116 } |
| 117 |
| 118 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it) |
| 119 it->Run(scoped_refptr<Buffer>()); |
| 120 } |
| 121 |
| 122 void ChunkDemuxerStream::Seek(base::TimeDelta time) { |
| 89 base::AutoLock auto_lock(lock_); | 123 base::AutoLock auto_lock(lock_); |
| 90 buffers_.clear(); | 124 |
| 91 received_end_of_stream_ = false; | 125 DCHECK(read_cbs_.empty()); |
| 92 last_buffer_timestamp_ = kNoTimestamp(); | 126 |
| 127 if (state_ == WAITING_FOR_SEEK) { |
| 128 ChangeState_Locked(RETURNING_DATA_FOR_READS); |
| 129 return; |
| 130 } |
| 131 |
| 132 if (state_ == RECEIVED_EOS_WHILE_WAITING_FOR_SEEK) { |
| 133 ChangeState_Locked(RECEIVED_EOS); |
| 134 return; |
| 135 } |
| 93 } | 136 } |
| 94 | 137 |
| 95 bool ChunkDemuxerStream::CanAddBuffers(const BufferQueue& buffers) const { | 138 bool ChunkDemuxerStream::CanAddBuffers(const BufferQueue& buffers) const { |
| 96 base::AutoLock auto_lock(lock_); | 139 base::AutoLock auto_lock(lock_); |
| 97 | 140 |
| 98 // If we haven't seen any buffers yet, then anything can be added. | 141 // If we haven't seen any buffers yet, then anything can be added. |
| 99 if (last_buffer_timestamp_ == kNoTimestamp()) | 142 if (last_buffer_timestamp_ == kNoTimestamp()) |
| 100 return true; | 143 return true; |
| 101 | 144 |
| 102 if (buffers.empty()) | 145 if (buffers.empty()) |
| 103 return true; | 146 return true; |
| 104 | 147 |
| 105 return (buffers.front()->GetTimestamp() > last_buffer_timestamp_); | 148 return (buffers.front()->GetTimestamp() > last_buffer_timestamp_); |
| 106 } | 149 } |
| 107 | 150 |
| 108 void ChunkDemuxerStream::AddBuffers(const BufferQueue& buffers) { | 151 void ChunkDemuxerStream::AddBuffers(const BufferQueue& buffers) { |
| 109 if (buffers.empty()) | 152 if (buffers.empty()) |
| 110 return; | 153 return; |
| 111 | 154 |
| 112 std::deque<base::Closure> callbacks; | 155 ClosureQueue closures; |
| 113 { | 156 { |
| 114 base::AutoLock auto_lock(lock_); | 157 base::AutoLock auto_lock(lock_); |
| 115 | 158 |
| 116 for (BufferQueue::const_iterator itr = buffers.begin(); | 159 for (BufferQueue::const_iterator itr = buffers.begin(); |
| 117 itr != buffers.end(); itr++) { | 160 itr != buffers.end(); itr++) { |
| 118 // Make sure we aren't trying to add a buffer after we have received and | 161 // Make sure we aren't trying to add a buffer after we have received and |
| 119 // "end of stream" buffer. | 162 // "end of stream" buffer. |
| 120 DCHECK(!received_end_of_stream_); | 163 DCHECK_NE(state_, RECEIVED_EOS_WHILE_WAITING_FOR_SEEK); |
| 164 DCHECK_NE(state_, RECEIVED_EOS); |
| 165 DCHECK_NE(state_, RETURNING_EOS_FOR_READS); |
| 121 | 166 |
| 122 if ((*itr)->IsEndOfStream()) { | 167 if ((*itr)->IsEndOfStream()) { |
| 123 received_end_of_stream_ = true; | 168 if (state_ == WAITING_FOR_SEEK) { |
| 124 | 169 ChangeState_Locked(RECEIVED_EOS_WHILE_WAITING_FOR_SEEK); |
| 125 // Push enough EOS buffers to satisfy outstanding Read() requests. | 170 } else { |
| 126 if (read_cbs_.size() > buffers_.size()) { | 171 ChangeState_Locked(RECEIVED_EOS); |
| 127 size_t pending_read_without_data = read_cbs_.size() - buffers_.size(); | |
| 128 for (size_t i = 0; i <= pending_read_without_data; ++i) { | |
| 129 buffers_.push_back(*itr); | |
| 130 } | |
| 131 } | 172 } |
| 132 } else { | 173 } else { |
| 133 base::TimeDelta current_ts = (*itr)->GetTimestamp(); | 174 base::TimeDelta current_ts = (*itr)->GetTimestamp(); |
| 134 if (last_buffer_timestamp_ != kNoTimestamp()) { | 175 if (last_buffer_timestamp_ != kNoTimestamp()) { |
| 135 DCHECK_GT(current_ts.ToInternalValue(), | 176 DCHECK_GT(current_ts.ToInternalValue(), |
| 136 last_buffer_timestamp_.ToInternalValue()); | 177 last_buffer_timestamp_.ToInternalValue()); |
| 137 } | 178 } |
| 138 | 179 |
| 139 last_buffer_timestamp_ = current_ts; | 180 last_buffer_timestamp_ = current_ts; |
| 140 buffers_.push_back(*itr); | 181 buffers_.push_back(*itr); |
| 141 } | 182 } |
| 142 } | 183 } |
| 143 | 184 |
| 144 while (!buffers_.empty() && !read_cbs_.empty()) { | 185 CreateReadDoneClosures_Locked(&closures); |
| 145 callbacks.push_back(base::Bind(read_cbs_.front(), buffers_.front())); | |
| 146 buffers_.pop_front(); | |
| 147 read_cbs_.pop_front(); | |
| 148 } | |
| 149 } | 186 } |
| 150 | 187 |
| 151 while (!callbacks.empty()) { | 188 for (ClosureQueue::iterator it = closures.begin(); it != closures.end(); ++it) |
| 152 callbacks.front().Run(); | 189 it->Run(); |
| 153 callbacks.pop_front(); | |
| 154 } | |
| 155 } | 190 } |
| 156 | 191 |
| 157 void ChunkDemuxerStream::Shutdown() { | 192 void ChunkDemuxerStream::Shutdown() { |
| 158 std::deque<ReadCallback> callbacks; | 193 ReadCBQueue read_cbs; |
| 159 { | 194 { |
| 160 base::AutoLock auto_lock(lock_); | 195 base::AutoLock auto_lock(lock_); |
| 161 shutdown_called_ = true; | 196 ChangeState_Locked(SHUTDOWN); |
| 162 | 197 |
| 163 // Collect all the pending Read() callbacks. | 198 std::swap(read_cbs_, read_cbs); |
| 164 while (!read_cbs_.empty()) { | 199 buffers_.clear(); |
| 165 callbacks.push_back(read_cbs_.front()); | |
| 166 read_cbs_.pop_front(); | |
| 167 } | |
| 168 } | 200 } |
| 169 | 201 |
| 170 // Pass end of stream buffers to all callbacks to signal that no more data | 202 // Pass end of stream buffers to all callbacks to signal that no more data |
| 171 // will be sent. | 203 // will be sent. |
| 172 while (!callbacks.empty()) { | 204 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it) |
| 173 callbacks.front().Run(CreateEOSBuffer()); | 205 it->Run(CreateEOSBuffer()); |
| 174 callbacks.pop_front(); | |
| 175 } | |
| 176 } | 206 } |
| 177 | 207 |
| 178 bool ChunkDemuxerStream::GetLastBufferTimestamp( | 208 bool ChunkDemuxerStream::GetLastBufferTimestamp( |
| 179 base::TimeDelta* timestamp) const { | 209 base::TimeDelta* timestamp) const { |
| 180 base::AutoLock auto_lock(lock_); | 210 base::AutoLock auto_lock(lock_); |
| 181 | 211 |
| 182 if (buffers_.empty()) | 212 if (buffers_.empty()) |
| 183 return false; | 213 return false; |
| 184 | 214 |
| 185 *timestamp = buffers_.back()->GetTimestamp(); | 215 *timestamp = buffers_.back()->GetTimestamp(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 199 read_callback.Run(buffer); | 229 read_callback.Run(buffer); |
| 200 } | 230 } |
| 201 | 231 |
| 202 // DemuxerStream methods. | 232 // DemuxerStream methods. |
| 203 void ChunkDemuxerStream::Read(const ReadCallback& read_callback) { | 233 void ChunkDemuxerStream::Read(const ReadCallback& read_callback) { |
| 204 scoped_refptr<Buffer> buffer; | 234 scoped_refptr<Buffer> buffer; |
| 205 | 235 |
| 206 { | 236 { |
| 207 base::AutoLock auto_lock(lock_); | 237 base::AutoLock auto_lock(lock_); |
| 208 | 238 |
| 209 if (shutdown_called_ || (received_end_of_stream_ && buffers_.empty())) { | 239 switch(state_) { |
| 210 buffer = CreateEOSBuffer(); | 240 case RETURNING_DATA_FOR_READS: |
| 211 } else { | 241 // If we don't have any buffers ready or already have |
| 212 if (buffers_.empty()) { | 242 // pending reads, then defer this read. |
| 213 // Wrap & store |read_callback| so that it will | 243 if (buffers_.empty() || !read_cbs_.empty()) { |
| 214 // get called on the current MessageLoop. | 244 DeferRead_Locked(read_callback); |
| 215 read_cbs_.push_back(base::Bind(&RunOnMessageLoop, | 245 return; |
| 216 read_callback, | 246 } |
| 217 MessageLoop::current())); | |
| 218 return; | |
| 219 } | |
| 220 | 247 |
| 221 if (!read_cbs_.empty()) { | 248 buffer = buffers_.front(); |
| 222 // Wrap & store |read_callback| so that it will | 249 buffers_.pop_front(); |
| 223 // get called on the current MessageLoop. | 250 break; |
| 224 read_cbs_.push_back(base::Bind(&RunOnMessageLoop, | |
| 225 read_callback, | |
| 226 MessageLoop::current())); | |
| 227 return; | |
| 228 } | |
| 229 | 251 |
| 230 buffer = buffers_.front(); | 252 case WAITING_FOR_SEEK: |
| 231 buffers_.pop_front(); | 253 case RECEIVED_EOS_WHILE_WAITING_FOR_SEEK: |
| 254 // Null buffers should be returned in this state since we are waiting |
| 255 // for a seek. Any buffers in |buffers_| should NOT be returned because |
| 256 // they are associated with the seek. |
| 257 DCHECK(read_cbs_.empty()); |
| 258 break; |
| 259 case RECEIVED_EOS: |
| 260 DCHECK(read_cbs_.empty()); |
| 261 |
| 262 if (buffers_.empty()) { |
| 263 ChangeState_Locked(RETURNING_EOS_FOR_READS); |
| 264 buffer = CreateEOSBuffer(); |
| 265 } else { |
| 266 buffer = buffers_.front(); |
| 267 buffers_.pop_front(); |
| 268 } |
| 269 break; |
| 270 |
| 271 case RETURNING_EOS_FOR_READS: |
| 272 case SHUTDOWN: |
| 273 DCHECK(buffers_.empty()); |
| 274 DCHECK(read_cbs_.empty()); |
| 275 buffer = CreateEOSBuffer(); |
| 232 } | 276 } |
| 233 } | 277 } |
| 234 | 278 |
| 235 DCHECK(buffer.get()); | |
| 236 read_callback.Run(buffer); | 279 read_callback.Run(buffer); |
| 237 } | 280 } |
| 238 | 281 |
| 239 DemuxerStream::Type ChunkDemuxerStream::type() { return type_; } | 282 DemuxerStream::Type ChunkDemuxerStream::type() { return type_; } |
| 240 | 283 |
| 241 void ChunkDemuxerStream::EnableBitstreamConverter() {} | 284 void ChunkDemuxerStream::EnableBitstreamConverter() {} |
| 242 | 285 |
| 243 const AudioDecoderConfig& ChunkDemuxerStream::audio_decoder_config() { | 286 const AudioDecoderConfig& ChunkDemuxerStream::audio_decoder_config() { |
| 244 CHECK_EQ(type_, AUDIO); | 287 CHECK_EQ(type_, AUDIO); |
| 245 return audio_config_; | 288 return audio_config_; |
| 246 } | 289 } |
| 247 | 290 |
| 248 const VideoDecoderConfig& ChunkDemuxerStream::video_decoder_config() { | 291 const VideoDecoderConfig& ChunkDemuxerStream::video_decoder_config() { |
| 249 CHECK_EQ(type_, VIDEO); | 292 CHECK_EQ(type_, VIDEO); |
| 250 return video_config_; | 293 return video_config_; |
| 251 } | 294 } |
| 252 | 295 |
| 296 void ChunkDemuxerStream::ChangeState_Locked(State state) { |
| 297 lock_.AssertAcquired(); |
| 298 state_ = state; |
| 299 } |
| 300 |
| 301 void ChunkDemuxerStream::DeferRead_Locked(const ReadCallback& read_cb) { |
| 302 lock_.AssertAcquired(); |
| 303 // Wrap & store |read_callback| so that it will |
| 304 // get called on the current MessageLoop. |
| 305 read_cbs_.push_back(base::Bind(&RunOnMessageLoop, read_cb, |
| 306 MessageLoop::current())); |
| 307 } |
| 308 |
| 309 void ChunkDemuxerStream::CreateReadDoneClosures_Locked(ClosureQueue* closures) { |
| 310 lock_.AssertAcquired(); |
| 311 |
| 312 if (state_ != RETURNING_DATA_FOR_READS && state_ != RECEIVED_EOS) |
| 313 return; |
| 314 |
| 315 while (!buffers_.empty() && !read_cbs_.empty()) { |
| 316 closures->push_back(base::Bind(read_cbs_.front(), buffers_.front())); |
| 317 buffers_.pop_front(); |
| 318 read_cbs_.pop_front(); |
| 319 } |
| 320 |
| 321 if (state_ != RECEIVED_EOS || !buffers_.empty() || read_cbs_.empty()) |
| 322 return; |
| 323 |
| 324 // Push enough EOS buffers to satisfy outstanding Read() requests. |
| 325 scoped_refptr<Buffer> end_of_stream_buffer = CreateEOSBuffer(); |
| 326 while (!read_cbs_.empty()) { |
| 327 closures->push_back(base::Bind(read_cbs_.front(), end_of_stream_buffer)); |
| 328 read_cbs_.pop_front(); |
| 329 } |
| 330 |
| 331 ChangeState_Locked(RETURNING_EOS_FOR_READS); |
| 332 } |
| 333 |
| 253 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) | 334 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) |
| 254 : state_(WAITING_FOR_INIT), | 335 : state_(WAITING_FOR_INIT), |
| 255 client_(client), | 336 client_(client), |
| 256 buffered_bytes_(0), | 337 buffered_bytes_(0), |
| 257 seek_waits_for_data_(true), | 338 seek_waits_for_data_(true), |
| 258 deferred_error_(PIPELINE_OK) { | 339 deferred_error_(PIPELINE_OK) { |
| 259 DCHECK(client); | 340 DCHECK(client); |
| 260 } | 341 } |
| 261 | 342 |
| 262 ChunkDemuxer::~ChunkDemuxer() { | 343 ChunkDemuxer::~ChunkDemuxer() { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 } | 380 } |
| 300 | 381 |
| 301 void ChunkDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { | 382 void ChunkDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { |
| 302 DVLOG(1) << "Seek(" << time.InSecondsF() << ")"; | 383 DVLOG(1) << "Seek(" << time.InSecondsF() << ")"; |
| 303 | 384 |
| 304 PipelineStatus status = PIPELINE_ERROR_INVALID_STATE; | 385 PipelineStatus status = PIPELINE_ERROR_INVALID_STATE; |
| 305 { | 386 { |
| 306 base::AutoLock auto_lock(lock_); | 387 base::AutoLock auto_lock(lock_); |
| 307 | 388 |
| 308 if (state_ == INITIALIZED || state_ == ENDED) { | 389 if (state_ == INITIALIZED || state_ == ENDED) { |
| 390 if (audio_) |
| 391 audio_->Seek(time); |
| 392 |
| 393 if (video_) |
| 394 video_->Seek(time); |
| 395 |
| 309 if (seek_waits_for_data_) { | 396 if (seek_waits_for_data_) { |
| 310 DVLOG(1) << "Seek() : waiting for more data to arrive."; | 397 DVLOG(1) << "Seek() : waiting for more data to arrive."; |
| 311 seek_cb_ = cb; | 398 seek_cb_ = cb; |
| 312 return; | 399 return; |
| 313 } | 400 } |
| 314 | 401 |
| 315 status = PIPELINE_OK; | 402 status = PIPELINE_OK; |
| 316 } | 403 } |
| 317 } | 404 } |
| 318 | 405 |
| (...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 646 if (!video_->CanAddBuffers(buffers)) | 733 if (!video_->CanAddBuffers(buffers)) |
| 647 return false; | 734 return false; |
| 648 | 735 |
| 649 video_->AddBuffers(buffers); | 736 video_->AddBuffers(buffers); |
| 650 seek_waits_for_data_ = false; | 737 seek_waits_for_data_ = false; |
| 651 | 738 |
| 652 return true; | 739 return true; |
| 653 } | 740 } |
| 654 | 741 |
| 655 } // namespace media | 742 } // namespace media |
| OLD | NEW |