Chromium Code Reviews| 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 |