OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/base/android/media_codec_decoder.h" | 5 #include "media/base/android/media_codec_decoder.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 11 matching lines...) Expand all Loading... | |
22 const int kPlaybackLowLimit = 4; | 22 const int kPlaybackLowLimit = 4; |
23 | 23 |
24 // Posting delay of the next frame processing, in milliseconds | 24 // Posting delay of the next frame processing, in milliseconds |
25 const int kNextFrameDelay = 1; | 25 const int kNextFrameDelay = 1; |
26 | 26 |
27 // Timeout for dequeuing an input buffer from MediaCodec in milliseconds. | 27 // Timeout for dequeuing an input buffer from MediaCodec in milliseconds. |
28 const int kInputBufferTimeout = 20; | 28 const int kInputBufferTimeout = 20; |
29 | 29 |
30 // Timeout for dequeuing an output buffer from MediaCodec in milliseconds. | 30 // Timeout for dequeuing an output buffer from MediaCodec in milliseconds. |
31 const int kOutputBufferTimeout = 20; | 31 const int kOutputBufferTimeout = 20; |
32 | |
33 // Estimated frame period in milliseconds | |
34 const int kEstimatedFramePeriod = 20; | |
qinmin
2015/07/28 18:09:46
why we need this variable? If we allow preroll for
| |
32 } | 35 } |
33 | 36 |
34 MediaCodecDecoder::MediaCodecDecoder( | 37 MediaCodecDecoder::MediaCodecDecoder( |
35 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, | 38 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, |
36 const base::Closure& external_request_data_cb, | 39 const base::Closure& external_request_data_cb, |
37 const base::Closure& starvation_cb, | 40 const base::Closure& starvation_cb, |
41 const base::Closure& preroll_done_cb, | |
38 const base::Closure& stop_done_cb, | 42 const base::Closure& stop_done_cb, |
39 const base::Closure& error_cb, | 43 const base::Closure& error_cb, |
40 const char* decoder_thread_name) | 44 const char* decoder_thread_name) |
41 : media_task_runner_(media_task_runner), | 45 : media_task_runner_(media_task_runner), |
42 decoder_thread_(decoder_thread_name), | 46 decoder_thread_(decoder_thread_name), |
43 needs_reconfigure_(false), | 47 needs_reconfigure_(false), |
44 external_request_data_cb_(external_request_data_cb), | 48 external_request_data_cb_(external_request_data_cb), |
45 starvation_cb_(starvation_cb), | 49 starvation_cb_(starvation_cb), |
50 preroll_done_cb_(preroll_done_cb), | |
46 stop_done_cb_(stop_done_cb), | 51 stop_done_cb_(stop_done_cb), |
47 error_cb_(error_cb), | 52 error_cb_(error_cb), |
48 state_(kStopped), | 53 state_(kStopped), |
49 eos_enqueued_(false), | 54 eos_enqueued_(false), |
50 completed_(false), | 55 completed_(false), |
51 last_frame_posted_(false), | 56 last_frame_posted_(false), |
52 is_data_request_in_progress_(false), | 57 is_data_request_in_progress_(false), |
53 is_incoming_data_invalid_(false), | 58 is_incoming_data_invalid_(false), |
54 #ifndef NDEBUG | 59 #ifndef NDEBUG |
55 verify_next_frame_is_key_(false), | 60 verify_next_frame_is_key_(false), |
56 #endif | 61 #endif |
57 weak_factory_(this) { | 62 weak_factory_(this) { |
58 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 63 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
59 | 64 |
60 DVLOG(1) << "Decoder::Decoder() " << decoder_thread_name; | 65 DVLOG(1) << "Decoder::Decoder() " << decoder_thread_name; |
61 | 66 |
67 // For simplicity we use constant value instead of truly measuring the frame | |
68 // period. As long as it is used for determination of the | |
69 // kPrerolling -> kPrerolled switch only this simplification seems ok. | |
70 estimated_frame_period_ = | |
71 base::TimeDelta::FromMilliseconds(kEstimatedFramePeriod); | |
72 | |
62 internal_error_cb_ = | 73 internal_error_cb_ = |
63 base::Bind(&MediaCodecDecoder::OnCodecError, weak_factory_.GetWeakPtr()); | 74 base::Bind(&MediaCodecDecoder::OnCodecError, weak_factory_.GetWeakPtr()); |
75 internal_preroll_done_cb_ = | |
76 base::Bind(&MediaCodecDecoder::OnPrerollDone, weak_factory_.GetWeakPtr()); | |
64 request_data_cb_ = | 77 request_data_cb_ = |
65 base::Bind(&MediaCodecDecoder::RequestData, weak_factory_.GetWeakPtr()); | 78 base::Bind(&MediaCodecDecoder::RequestData, weak_factory_.GetWeakPtr()); |
66 } | 79 } |
67 | 80 |
68 MediaCodecDecoder::~MediaCodecDecoder() { | 81 MediaCodecDecoder::~MediaCodecDecoder() { |
69 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 82 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
70 | 83 |
71 DVLOG(1) << "Decoder::~Decoder()"; | 84 DVLOG(1) << "Decoder::~Decoder()"; |
72 | 85 |
73 // NB: ReleaseDecoderResources() is virtual | 86 // NB: ReleaseDecoderResources() is virtual |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
132 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 145 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
133 | 146 |
134 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 147 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
135 | 148 |
136 media_codec_bridge_.reset(); | 149 media_codec_bridge_.reset(); |
137 } | 150 } |
138 | 151 |
139 bool MediaCodecDecoder::IsPrefetchingOrPlaying() const { | 152 bool MediaCodecDecoder::IsPrefetchingOrPlaying() const { |
140 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 153 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
141 | 154 |
155 // Whether decoder needs to be stopped. | |
142 base::AutoLock lock(state_lock_); | 156 base::AutoLock lock(state_lock_); |
143 return state_ == kPrefetching || state_ == kRunning; | 157 switch (state_) { |
158 case kPrefetching: | |
159 case kPrefetched: | |
160 case kPrerolling: | |
161 case kPrerolled: | |
162 case kRunning: | |
163 return true; | |
164 case kStopped: | |
165 case kStopping: | |
166 case kInEmergencyStop: | |
167 case kError: | |
168 return false; | |
169 } | |
170 NOTREACHED(); | |
171 return false; | |
172 } | |
173 | |
174 bool MediaCodecDecoder::IsPrerollDone() const { | |
175 DCHECK(media_task_runner_->BelongsToCurrentThread()); | |
176 | |
177 return !HasStream() || IsCompleted() || GetState() == kPrerolled; | |
144 } | 178 } |
145 | 179 |
146 bool MediaCodecDecoder::IsStopped() const { | 180 bool MediaCodecDecoder::IsStopped() const { |
147 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 181 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
148 | 182 |
149 return GetState() == kStopped; | 183 return GetState() == kStopped; |
150 } | 184 } |
151 | 185 |
152 bool MediaCodecDecoder::IsCompleted() const { | 186 bool MediaCodecDecoder::IsCompleted() const { |
153 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 187 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
216 | 250 |
217 // For video the first frame after reconfiguration must be key frame. | 251 // For video the first frame after reconfiguration must be key frame. |
218 if (result == CONFIG_OK) | 252 if (result == CONFIG_OK) |
219 verify_next_frame_is_key_ = true; | 253 verify_next_frame_is_key_ = true; |
220 #endif | 254 #endif |
221 } | 255 } |
222 | 256 |
223 return result; | 257 return result; |
224 } | 258 } |
225 | 259 |
226 bool MediaCodecDecoder::Start(base::TimeDelta current_time) { | 260 void MediaCodecDecoder::SetPrerollTimestamp(base::TimeDelta preroll_timestamp) { |
261 DCHECK(media_task_runner_->BelongsToCurrentThread()); | |
262 DCHECK(!decoder_thread_.IsRunning()); | |
263 | |
264 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": " << preroll_timestamp; | |
265 | |
266 // Do not set preroll timestamp if it's too close to zero. | |
267 preroll_timestamp_ = (preroll_timestamp < estimated_frame_period_) | |
268 ? base::TimeDelta() | |
269 : preroll_timestamp; | |
270 } | |
271 | |
272 bool MediaCodecDecoder::Start(base::TimeDelta start_timestamp) { | |
227 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 273 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
228 | 274 |
229 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 275 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
230 << " current_time:" << current_time; | 276 << " start_timestamp:" << start_timestamp; |
231 | 277 |
232 DecoderState state = GetState(); | 278 DecoderState state = GetState(); |
233 if (state == kRunning) { | 279 if (state == kPrerolling || state == kRunning) { |
234 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": already started"; | 280 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": already started"; |
235 return true; // already started | 281 return true; // already started |
236 } | 282 } |
237 | 283 |
238 if (state != kPrefetched) { | 284 if (state != kPrefetched) { |
239 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state " | 285 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state " |
240 << AsString(state) << " ignoring"; | 286 << AsString(state) << " ignoring"; |
241 return false; | 287 return false; |
242 } | 288 } |
243 | 289 |
244 if (!media_codec_bridge_) { | 290 if (!media_codec_bridge_) { |
245 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 291 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
246 << ": not configured, ignoring"; | 292 << ": not configured, ignoring"; |
247 return false; | 293 return false; |
248 } | 294 } |
249 | 295 |
250 DCHECK(!decoder_thread_.IsRunning()); | 296 DCHECK(!decoder_thread_.IsRunning()); |
251 | 297 |
298 const bool needs_preroll = (preroll_timestamp_ != base::TimeDelta()); | |
299 | |
252 // We only synchronize video stream. | 300 // We only synchronize video stream. |
253 // When audio is present, the |current_time| is audio time. | 301 if (needs_preroll) |
254 SynchronizePTSWithTime(current_time); | 302 DissociatePTSFromTime(); // associaton will happen after preroll is done. |
303 else | |
304 AssociateCurrentTimeWithPTS(start_timestamp); | |
255 | 305 |
256 last_frame_posted_ = false; | 306 last_frame_posted_ = false; |
257 | 307 |
258 // Start the decoder thread | 308 // Start the decoder thread |
259 if (!decoder_thread_.Start()) { | 309 if (!decoder_thread_.Start()) { |
260 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 310 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
261 << ": cannot start decoder thread"; | 311 << ": cannot start decoder thread"; |
262 return false; | 312 return false; |
263 } | 313 } |
264 | 314 |
265 SetState(kRunning); | 315 SetState(needs_preroll ? kPrerolling : kRunning); |
266 | 316 |
267 decoder_thread_.task_runner()->PostTask( | 317 decoder_thread_.task_runner()->PostTask( |
268 FROM_HERE, | 318 FROM_HERE, |
269 base::Bind(&MediaCodecDecoder::ProcessNextFrame, base::Unretained(this))); | 319 base::Bind(&MediaCodecDecoder::ProcessNextFrame, base::Unretained(this))); |
270 | 320 |
271 return true; | 321 return true; |
272 } | 322 } |
273 | 323 |
324 void MediaCodecDecoder::ResumeAfterPreroll() { | |
325 DCHECK(media_task_runner_->BelongsToCurrentThread()); | |
326 | |
327 DVLOG(1) << class_name() << "::" << __FUNCTION__; | |
328 | |
329 DCHECK(GetState() == kPrerolled); | |
330 DCHECK(decoder_thread_.IsRunning()); | |
331 | |
332 SetState(kRunning); | |
333 | |
334 AssociateCurrentTimeWithPTS(preroll_timestamp_); | |
335 preroll_timestamp_ = base::TimeDelta(); | |
336 | |
337 decoder_thread_.task_runner()->PostTask( | |
338 FROM_HERE, | |
339 base::Bind(&MediaCodecDecoder::ProcessNextFrame, base::Unretained(this))); | |
340 } | |
341 | |
274 void MediaCodecDecoder::SyncStop() { | 342 void MediaCodecDecoder::SyncStop() { |
275 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 343 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
276 | 344 |
277 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 345 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
278 | 346 |
279 if (GetState() == kError) { | 347 if (GetState() == kError) { |
280 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 348 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
281 << ": wrong state kError, ignoring"; | 349 << ": wrong state kError, ignoring"; |
282 return; | 350 return; |
283 } | 351 } |
(...skipping 18 matching lines...) Expand all Loading... | |
302 | 370 |
303 DecoderState state = GetState(); | 371 DecoderState state = GetState(); |
304 switch (state) { | 372 switch (state) { |
305 case kError: | 373 case kError: |
306 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 374 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
307 << ": wrong state kError, ignoring"; | 375 << ": wrong state kError, ignoring"; |
308 break; | 376 break; |
309 case kRunning: | 377 case kRunning: |
310 SetState(kStopping); | 378 SetState(kStopping); |
311 break; | 379 break; |
380 case kPrerolling: | |
381 case kPrerolled: | |
382 DCHECK(decoder_thread_.IsRunning()); | |
383 // Synchronous stop. | |
384 decoder_thread_.Stop(); | |
385 SetState(kStopped); | |
386 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); | |
387 break; | |
312 case kStopping: | 388 case kStopping: |
313 break; // ignore | 389 break; // ignore |
314 case kStopped: | 390 case kStopped: |
315 case kPrefetching: | 391 case kPrefetching: |
316 case kPrefetched: | 392 case kPrefetched: |
317 // There is nothing to wait for, we can sent nofigication right away. | 393 // There is nothing to wait for, we can sent nofigication right away. |
318 DCHECK(!decoder_thread_.IsRunning()); | 394 DCHECK(!decoder_thread_.IsRunning()); |
319 SetState(kStopped); | 395 SetState(kStopped); |
320 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); | 396 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); |
321 break; | 397 break; |
(...skipping 10 matching lines...) Expand all Loading... | |
332 << " completed:" << completed; | 408 << " completed:" << completed; |
333 | 409 |
334 decoder_thread_.Stop(); // synchronous | 410 decoder_thread_.Stop(); // synchronous |
335 | 411 |
336 SetState(kStopped); | 412 SetState(kStopped); |
337 completed_ = completed; | 413 completed_ = completed; |
338 | 414 |
339 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); | 415 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); |
340 } | 416 } |
341 | 417 |
418 void MediaCodecDecoder::OnPrerollDone() { | |
419 DCHECK(media_task_runner_->BelongsToCurrentThread()); | |
420 | |
421 DVLOG(1) << class_name() << "::" << __FUNCTION__; | |
422 | |
423 if (GetState() == kPrerolling) { | |
424 SetState(kPrerolled); | |
425 media_task_runner_->PostTask(FROM_HERE, preroll_done_cb_); | |
426 } | |
427 } | |
428 | |
342 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) { | 429 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) { |
343 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 430 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
344 | 431 |
345 // If |data| contains an aborted data, the last AU will have kAborted status. | 432 // If |data| contains an aborted data, the last AU will have kAborted status. |
346 bool aborted_data = | 433 bool aborted_data = |
347 !data.access_units.empty() && | 434 !data.access_units.empty() && |
348 data.access_units.back().status == DemuxerStream::kAborted; | 435 data.access_units.back().status == DemuxerStream::kAborted; |
349 | 436 |
350 #ifndef NDEBUG | 437 #ifndef NDEBUG |
351 const char* explain_if_skipped = | 438 const char* explain_if_skipped = |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
433 request_data_cb_.Run(); | 520 request_data_cb_.Run(); |
434 } | 521 } |
435 | 522 |
436 void MediaCodecDecoder::ProcessNextFrame() { | 523 void MediaCodecDecoder::ProcessNextFrame() { |
437 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 524 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
438 | 525 |
439 DVLOG(2) << class_name() << "::" << __FUNCTION__; | 526 DVLOG(2) << class_name() << "::" << __FUNCTION__; |
440 | 527 |
441 DecoderState state = GetState(); | 528 DecoderState state = GetState(); |
442 | 529 |
443 if (state != kRunning && state != kStopping) { | 530 if (state != kPrerolling && state != kRunning && state != kStopping) { |
444 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": not running"; | 531 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": not running"; |
445 return; | 532 return; |
446 } | 533 } |
447 | 534 |
448 if (state == kStopping) { | 535 if (state == kStopping) { |
449 if (NumDelayedRenderTasks() == 0 && !last_frame_posted_) { | 536 if (NumDelayedRenderTasks() == 0 && !last_frame_posted_) { |
450 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 537 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
451 << ": kStopping, posting OnLastFrameRendered"; | 538 << ": kStopping, posting OnLastFrameRendered"; |
452 media_task_runner_->PostTask( | 539 media_task_runner_->PostTask( |
453 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered, | 540 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered, |
454 weak_factory_.GetWeakPtr(), false)); | 541 weak_factory_.GetWeakPtr(), false)); |
455 last_frame_posted_ = true; | 542 last_frame_posted_ = true; |
456 } | 543 } |
457 | 544 |
458 // We can stop processing, the |au_queue_| and MediaCodec queues can freeze. | 545 // We can stop processing, the |au_queue_| and MediaCodec queues can freeze. |
459 // We only need to let finish the delayed rendering tasks. | 546 // We only need to let finish the delayed rendering tasks. |
460 return; | 547 return; |
461 } | 548 } |
462 | 549 |
463 DCHECK(state == kRunning); | 550 DCHECK(state == kPrerolling || state == kRunning); |
464 | 551 |
465 if (!EnqueueInputBuffer()) | 552 if (!EnqueueInputBuffer()) |
466 return; | 553 return; |
467 | 554 |
468 if (!DepleteOutputBufferQueue()) | 555 if (!DepleteOutputBufferQueue()) |
469 return; | 556 return; |
470 | 557 |
471 // We need a small delay if we want to stop this thread by | 558 // We need a small delay if we want to stop this thread by |
472 // decoder_thread_.Stop() reliably. | 559 // decoder_thread_.Stop() reliably. |
473 // The decoder thread message loop processes all pending | 560 // The decoder thread message loop processes all pending |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
594 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 681 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
595 | 682 |
596 DVLOG(2) << class_name() << "::" << __FUNCTION__; | 683 DVLOG(2) << class_name() << "::" << __FUNCTION__; |
597 | 684 |
598 int buffer_index = 0; | 685 int buffer_index = 0; |
599 size_t offset = 0; | 686 size_t offset = 0; |
600 size_t size = 0; | 687 size_t size = 0; |
601 base::TimeDelta pts; | 688 base::TimeDelta pts; |
602 MediaCodecStatus status; | 689 MediaCodecStatus status; |
603 bool eos_encountered = false; | 690 bool eos_encountered = false; |
691 bool preroll_done = false; | |
604 | 692 |
605 base::TimeDelta timeout = | 693 base::TimeDelta timeout = |
606 base::TimeDelta::FromMilliseconds(kOutputBufferTimeout); | 694 base::TimeDelta::FromMilliseconds(kOutputBufferTimeout); |
607 | 695 |
608 // Extract all output buffers that are available. | 696 // Extract all output buffers that are available. |
609 // Usually there will be only one, but sometimes it is preceeded by | 697 // Usually there will be only one, but sometimes it is preceeded by |
610 // MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED or MEDIA_CODEC_OUTPUT_FORMAT_CHANGED. | 698 // MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED or MEDIA_CODEC_OUTPUT_FORMAT_CHANGED. |
611 do { | 699 do { |
612 status = media_codec_bridge_->DequeueOutputBuffer( | 700 status = media_codec_bridge_->DequeueOutputBuffer( |
613 timeout, &buffer_index, &offset, &size, &pts, &eos_encountered, | 701 timeout, &buffer_index, &offset, &size, &pts, &eos_encountered, |
614 nullptr); | 702 nullptr); |
615 | 703 |
616 // Reset the timeout to 0 for the subsequent DequeueOutputBuffer() calls | 704 // Reset the timeout to 0 for the subsequent DequeueOutputBuffer() calls |
617 // to quickly break the loop after we got all currently available buffers. | 705 // to quickly break the loop after we got all currently available buffers. |
618 timeout = base::TimeDelta::FromMilliseconds(0); | 706 timeout = base::TimeDelta::FromMilliseconds(0); |
619 | 707 |
620 switch (status) { | 708 switch (status) { |
621 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: | 709 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: |
622 // Output buffers are replaced in MediaCodecBridge, nothing to do. | 710 // Output buffers are replaced in MediaCodecBridge, nothing to do. |
623 break; | 711 break; |
624 | 712 |
625 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: | 713 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: |
626 DVLOG(2) << class_name() << "::" << __FUNCTION__ | 714 DVLOG(2) << class_name() << "::" << __FUNCTION__ |
627 << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED"; | 715 << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED"; |
628 OnOutputFormatChanged(); | 716 OnOutputFormatChanged(); |
629 break; | 717 break; |
630 | 718 |
631 case MEDIA_CODEC_OK: | 719 case MEDIA_CODEC_OK: { |
632 // We got the decoded frame | 720 // We got the decoded frame. |
633 Render(buffer_index, size, true, pts, eos_encountered); | 721 |
634 break; | 722 // TODO(timav): this code won't render the very first frame in |
723 // kPrerolling if it is already behind preroll_timestamp_. A more | |
724 // precise method would be to stop before Render() and resume after | |
725 // preroll with the Render(), but it would be more complicated. | |
726 | |
727 DecoderState state = GetState(); | |
728 const bool do_render = (state == kRunning || state == kStopping); | |
qinmin
2015/07/28 18:09:46
I think it is ok to render if (state == kPrerollin
Tima Vaisburd
2015/07/28 18:34:04
I believe you mean "in addition to kRunning and kS
qinmin
2015/07/28 18:55:06
You can modify the MediaCodecBridge.playOutputBuff
| |
729 | |
730 Render(buffer_index, size, do_render, pts, eos_encountered); | |
731 | |
732 // If next pts passes over |preroll_timestamp_| this frame is the last | |
733 // preroll frame. | |
734 if (!do_render && preroll_timestamp_ <= pts + estimated_frame_period_) { | |
735 media_task_runner_->PostTask(FROM_HERE, internal_preroll_done_cb_); | |
736 preroll_done = true; | |
737 } | |
738 } break; | |
635 | 739 |
636 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: | 740 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: |
637 // Nothing to do. | 741 // Nothing to do. |
638 break; | 742 break; |
639 | 743 |
640 case MEDIA_CODEC_ERROR: | 744 case MEDIA_CODEC_ERROR: |
641 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 745 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
642 << ": MEDIA_CODEC_ERROR from DequeueOutputBuffer"; | 746 << ": MEDIA_CODEC_ERROR from DequeueOutputBuffer"; |
643 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); | 747 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); |
644 break; | 748 break; |
645 | 749 |
646 default: | 750 default: |
647 NOTREACHED(); | 751 NOTREACHED(); |
648 break; | 752 break; |
649 } | 753 } |
650 | 754 |
651 } while (status != MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER && | 755 } while (status != MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER && |
652 status != MEDIA_CODEC_ERROR && !eos_encountered); | 756 status != MEDIA_CODEC_ERROR && !eos_encountered && !preroll_done); |
653 | 757 |
654 if (eos_encountered) { | 758 if (eos_encountered) { |
655 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 759 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
656 << " EOS dequeued, stopping frame processing"; | 760 << " EOS dequeued, stopping frame processing"; |
657 return false; | 761 return false; |
658 } | 762 } |
659 | 763 |
764 if (preroll_done) { | |
765 DVLOG(1) << class_name() << "::" << __FUNCTION__ | |
766 << " preroll done, stopping frame processing"; | |
767 return false; | |
768 } | |
769 | |
660 if (status == MEDIA_CODEC_ERROR) { | 770 if (status == MEDIA_CODEC_ERROR) { |
661 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 771 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
662 << " MediaCodec error, stopping frame processing"; | 772 << " MediaCodec error, stopping frame processing"; |
663 return false; | 773 return false; |
664 } | 774 } |
665 | 775 |
666 return true; | 776 return true; |
667 } | 777 } |
668 | 778 |
669 MediaCodecDecoder::DecoderState MediaCodecDecoder::GetState() const { | 779 MediaCodecDecoder::DecoderState MediaCodecDecoder::GetState() const { |
(...skipping 11 matching lines...) Expand all Loading... | |
681 #undef RETURN_STRING | 791 #undef RETURN_STRING |
682 #define RETURN_STRING(x) \ | 792 #define RETURN_STRING(x) \ |
683 case x: \ | 793 case x: \ |
684 return #x; | 794 return #x; |
685 | 795 |
686 const char* MediaCodecDecoder::AsString(DecoderState state) { | 796 const char* MediaCodecDecoder::AsString(DecoderState state) { |
687 switch (state) { | 797 switch (state) { |
688 RETURN_STRING(kStopped); | 798 RETURN_STRING(kStopped); |
689 RETURN_STRING(kPrefetching); | 799 RETURN_STRING(kPrefetching); |
690 RETURN_STRING(kPrefetched); | 800 RETURN_STRING(kPrefetched); |
801 RETURN_STRING(kPrerolling); | |
802 RETURN_STRING(kPrerolled); | |
691 RETURN_STRING(kRunning); | 803 RETURN_STRING(kRunning); |
692 RETURN_STRING(kStopping); | 804 RETURN_STRING(kStopping); |
693 RETURN_STRING(kInEmergencyStop); | 805 RETURN_STRING(kInEmergencyStop); |
694 RETURN_STRING(kError); | 806 RETURN_STRING(kError); |
695 default: | 807 default: |
696 return "Unknown DecoderState"; | 808 return "Unknown DecoderState"; |
697 } | 809 } |
698 } | 810 } |
699 | 811 |
700 #undef RETURN_STRING | 812 #undef RETURN_STRING |
701 | 813 |
702 } // namespace media | 814 } // namespace media |
OLD | NEW |