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_END_OF_STREAM, | |
Ami GONE FROM CHROMIUM
2012/01/29 22:12:38
s/END_OF_STREAM/EOS/ here and below to match the p
acolwell GONE FROM CHROMIUM
2012/01/30 00:14:14
Done.
| |
57 SENT_END_OF_STREAM, | |
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_|. | |
Ami GONE FROM CHROMIUM
2012/01/29 22:12:38
It also pops the respective queues, though, right?
acolwell GONE FROM CHROMIUM
2012/01/30 00:14:14
Done.
| |
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_END_OF_STREAM); | |
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_END_OF_STREAM); | |
165 DCHECK_NE(state_, SENT_END_OF_STREAM); | |
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_END_OF_STREAM); |
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_END_OF_STREAM: | |
260 DCHECK(read_cbs_.empty()); | |
261 | |
262 if (buffers_.empty()) { | |
263 ChangeState_Locked(SENT_END_OF_STREAM); | |
264 buffer = CreateEOSBuffer(); | |
265 } else { | |
266 buffer = buffers_.front(); | |
267 buffers_.pop_front(); | |
268 } | |
269 break; | |
270 | |
271 case SENT_END_OF_STREAM: | |
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( | |
310 ClosureQueue* closures) { | |
Ami GONE FROM CHROMIUM
2012/01/29 22:12:38
one line?
acolwell GONE FROM CHROMIUM
2012/01/30 00:14:14
Done.
| |
311 lock_.AssertAcquired(); | |
312 | |
313 if (state_ != RETURNING_DATA_FOR_READS && state_ != RECEIVED_END_OF_STREAM) | |
314 return; | |
315 | |
316 while (!buffers_.empty() && !read_cbs_.empty()) { | |
317 closures->push_back(base::Bind(read_cbs_.front(), buffers_.front())); | |
318 buffers_.pop_front(); | |
319 read_cbs_.pop_front(); | |
320 } | |
321 | |
322 if (state_ == RECEIVED_END_OF_STREAM && | |
Ami GONE FROM CHROMIUM
2012/01/29 22:12:38
reverse test and early return.
acolwell GONE FROM CHROMIUM
2012/01/30 00:14:14
Done.
| |
323 buffers_.empty() && !read_cbs_.empty()) { | |
324 | |
Ami GONE FROM CHROMIUM
2012/01/29 22:12:38
extra \n
acolwell GONE FROM CHROMIUM
2012/01/30 00:14:14
Done.
| |
325 // Push enough EOS buffers to satisfy outstanding Read() requests. | |
326 scoped_refptr<Buffer> end_of_stream_buffer = CreateEOSBuffer(); | |
327 while (!read_cbs_.empty()) { | |
328 closures->push_back(base::Bind(read_cbs_.front(), end_of_stream_buffer)); | |
329 read_cbs_.pop_front(); | |
330 } | |
331 | |
332 ChangeState_Locked(SENT_END_OF_STREAM); | |
Ami GONE FROM CHROMIUM
2012/01/29 22:12:38
It's a tad sketchy that this state change happens
acolwell GONE FROM CHROMIUM
2012/01/30 00:14:14
True. I think the state name is the problem. I've
| |
333 } | |
334 } | |
335 | |
253 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) | 336 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) |
254 : state_(WAITING_FOR_INIT), | 337 : state_(WAITING_FOR_INIT), |
255 client_(client), | 338 client_(client), |
256 buffered_bytes_(0), | 339 buffered_bytes_(0), |
257 seek_waits_for_data_(true), | 340 seek_waits_for_data_(true), |
258 deferred_error_(PIPELINE_OK) { | 341 deferred_error_(PIPELINE_OK) { |
259 DCHECK(client); | 342 DCHECK(client); |
260 } | 343 } |
261 | 344 |
262 ChunkDemuxer::~ChunkDemuxer() { | 345 ChunkDemuxer::~ChunkDemuxer() { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
299 } | 382 } |
300 | 383 |
301 void ChunkDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { | 384 void ChunkDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { |
302 DVLOG(1) << "Seek(" << time.InSecondsF() << ")"; | 385 DVLOG(1) << "Seek(" << time.InSecondsF() << ")"; |
303 | 386 |
304 PipelineStatus status = PIPELINE_ERROR_INVALID_STATE; | 387 PipelineStatus status = PIPELINE_ERROR_INVALID_STATE; |
305 { | 388 { |
306 base::AutoLock auto_lock(lock_); | 389 base::AutoLock auto_lock(lock_); |
307 | 390 |
308 if (state_ == INITIALIZED || state_ == ENDED) { | 391 if (state_ == INITIALIZED || state_ == ENDED) { |
392 if (audio_) | |
393 audio_->Seek(time); | |
394 | |
395 if (video_) | |
396 video_->Seek(time); | |
397 | |
309 if (seek_waits_for_data_) { | 398 if (seek_waits_for_data_) { |
310 DVLOG(1) << "Seek() : waiting for more data to arrive."; | 399 DVLOG(1) << "Seek() : waiting for more data to arrive."; |
311 seek_cb_ = cb; | 400 seek_cb_ = cb; |
312 return; | 401 return; |
313 } | 402 } |
314 | 403 |
315 status = PIPELINE_OK; | 404 status = PIPELINE_OK; |
316 } | 405 } |
317 } | 406 } |
318 | 407 |
(...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
646 if (!video_->CanAddBuffers(buffers)) | 735 if (!video_->CanAddBuffers(buffers)) |
647 return false; | 736 return false; |
648 | 737 |
649 video_->AddBuffers(buffers); | 738 video_->AddBuffers(buffers); |
650 seek_waits_for_data_ = false; | 739 seek_waits_for_data_ = false; |
651 | 740 |
652 return true; | 741 return true; |
653 } | 742 } |
654 | 743 |
655 } // namespace media | 744 } // namespace media |
OLD | NEW |