1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "media/base/android/media_decoder_job.h" 6 7#include "base/bind.h" 8#include "base/callback_helpers.h" 9#include "base/debug/trace_event.h" 10#include "base/message_loop/message_loop_proxy.h" 11#include "media/base/android/media_codec_bridge.h" 12#include "media/base/android/media_drm_bridge.h" 13#include "media/base/bind_to_current_loop.h" 14#include "media/base/buffers.h" 15 16namespace media { 17 18// Timeout value for media codec operations. Because the first 19// DequeInputBuffer() can take about 150 milliseconds, use 250 milliseconds 20// here. See http://b/9357571. 21static const int kMediaCodecTimeoutInMilliseconds = 250; 22 23MediaDecoderJob::MediaDecoderJob( 24 const scoped_refptr<base::SingleThreadTaskRunner>& decoder_task_runner, 25 const base::Closure& request_data_cb, 26 const base::Closure& config_changed_cb) 27 : need_to_reconfig_decoder_job_(false), 28 ui_task_runner_(base::MessageLoopProxy::current()), 29 decoder_task_runner_(decoder_task_runner), 30 needs_flush_(false), 31 input_eos_encountered_(false), 32 output_eos_encountered_(false), 33 skip_eos_enqueue_(true), 34 prerolling_(true), 35 request_data_cb_(request_data_cb), 36 config_changed_cb_(config_changed_cb), 37 current_demuxer_data_index_(0), 38 input_buf_index_(-1), 39 is_content_encrypted_(false), 40 stop_decode_pending_(false), 41 destroy_pending_(false), 42 is_requesting_demuxer_data_(false), 43 is_incoming_data_invalid_(false), 44 release_resources_pending_(false), 45 drm_bridge_(NULL), 46 drain_decoder_(false) { 47 InitializeReceivedData(); 48 eos_unit_.end_of_stream = true; 49} 50 51MediaDecoderJob::~MediaDecoderJob() { 52 ReleaseMediaCodecBridge(); 53} 54 55void MediaDecoderJob::OnDataReceived(const DemuxerData& data) { 56 DVLOG(1) << __FUNCTION__ << ": " << data.access_units.size() << " units"; 57 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 58 DCHECK(NoAccessUnitsRemainingInChunk(false)); 59 60 TRACE_EVENT_ASYNC_END2( 61 "media", "MediaDecoderJob::RequestData", this, 62 "Data type", data.type == media::DemuxerStream::AUDIO ? "AUDIO" : "VIDEO", 63 "Units read", data.access_units.size()); 64 65 if (is_incoming_data_invalid_) { 66 is_incoming_data_invalid_ = false; 67 68 // If there is a pending callback, need to request the data again to get 69 // valid data. 70 if (!data_received_cb_.is_null()) 71 request_data_cb_.Run(); 72 else 73 is_requesting_demuxer_data_ = false; 74 return; 75 } 76 77 size_t next_demuxer_data_index = inactive_demuxer_data_index(); 78 received_data_[next_demuxer_data_index] = data; 79 access_unit_index_[next_demuxer_data_index] = 0; 80 is_requesting_demuxer_data_ = false; 81 82 base::Closure done_cb = base::ResetAndReturn(&data_received_cb_); 83 84 // If this data request is for the inactive chunk, or |data_received_cb_| 85 // was set to null by Flush() or Release(), do nothing. 86 if (done_cb.is_null()) 87 return; 88 89 if (stop_decode_pending_) { 90 DCHECK(is_decoding()); 91 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), kNoTimestamp()); 92 return; 93 } 94 95 done_cb.Run(); 96} 97 98void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) { 99 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 100 DCHECK(data_received_cb_.is_null()); 101 DCHECK(decode_cb_.is_null()); 102 103 if (HasData()) { 104 DVLOG(1) << __FUNCTION__ << " : using previously received data"; 105 ui_task_runner_->PostTask(FROM_HERE, prefetch_cb); 106 return; 107 } 108 109 DVLOG(1) << __FUNCTION__ << " : requesting data"; 110 RequestData(prefetch_cb); 111} 112 113bool MediaDecoderJob::Decode( 114 base::TimeTicks start_time_ticks, 115 base::TimeDelta start_presentation_timestamp, 116 const DecoderCallback& callback) { 117 DCHECK(decode_cb_.is_null()); 118 DCHECK(data_received_cb_.is_null()); 119 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 120 121 if (!media_codec_bridge_ || need_to_reconfig_decoder_job_) { 122 need_to_reconfig_decoder_job_ = !CreateMediaCodecBridge(); 123 if (drain_decoder_) { 124 // Decoder has been recreated, stop draining. 125 drain_decoder_ = false; 126 input_eos_encountered_ = false; 127 output_eos_encountered_ = false; 128 access_unit_index_[current_demuxer_data_index_]++; 129 } 130 skip_eos_enqueue_ = true; 131 if (need_to_reconfig_decoder_job_) 132 return false; 133 } 134 135 decode_cb_ = callback; 136 137 if (!HasData()) { 138 RequestData(base::Bind(&MediaDecoderJob::DecodeCurrentAccessUnit, 139 base::Unretained(this), 140 start_time_ticks, 141 start_presentation_timestamp)); 142 return true; 143 } 144 145 DecodeCurrentAccessUnit(start_time_ticks, start_presentation_timestamp); 146 return true; 147} 148 149void MediaDecoderJob::StopDecode() { 150 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 151 DCHECK(is_decoding()); 152 stop_decode_pending_ = true; 153} 154 155bool MediaDecoderJob::OutputEOSReached() const { 156 return !drain_decoder_ && output_eos_encountered_; 157} 158 159void MediaDecoderJob::SetDrmBridge(MediaDrmBridge* drm_bridge) { 160 drm_bridge_ = drm_bridge; 161 need_to_reconfig_decoder_job_ = true; 162} 163 164void MediaDecoderJob::Flush() { 165 DVLOG(1) << __FUNCTION__; 166 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 167 DCHECK(data_received_cb_.is_null()); 168 DCHECK(decode_cb_.is_null()); 169 170 // Clean up the received data. 171 current_demuxer_data_index_ = 0; 172 InitializeReceivedData(); 173 if (is_requesting_demuxer_data_) 174 is_incoming_data_invalid_ = true; 175 input_eos_encountered_ = false; 176 output_eos_encountered_ = false; 177 drain_decoder_ = false; 178 179 // Do nothing, flush when the next Decode() happens. 180 needs_flush_ = true; 181} 182 183void MediaDecoderJob::BeginPrerolling(base::TimeDelta preroll_timestamp) { 184 DVLOG(1) << __FUNCTION__ << "(" << preroll_timestamp.InSecondsF() << ")"; 185 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 186 DCHECK(!is_decoding()); 187 188 preroll_timestamp_ = preroll_timestamp; 189 prerolling_ = true; 190} 191 192void MediaDecoderJob::ReleaseDecoderResources() { 193 DVLOG(1) << __FUNCTION__; 194 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 195 if (decode_cb_.is_null()) { 196 DCHECK(!drain_decoder_); 197 // Since the decoder job is not decoding data, we can safely destroy 198 // |media_codec_bridge_|. 199 ReleaseMediaCodecBridge(); 200 return; 201 } 202 203 // Release |media_codec_bridge_| once decoding is completed. 204 release_resources_pending_ = true; 205} 206 207base::android::ScopedJavaLocalRef<jobject> MediaDecoderJob::GetMediaCrypto() { 208 base::android::ScopedJavaLocalRef<jobject> media_crypto; 209 if (drm_bridge_) 210 media_crypto = drm_bridge_->GetMediaCrypto(); 211 return media_crypto; 212} 213 214void MediaDecoderJob::Release() { 215 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 216 DVLOG(1) << __FUNCTION__; 217 218 // If the decoder job is still decoding, we cannot delete the job immediately. 219 destroy_pending_ = is_decoding(); 220 221 request_data_cb_.Reset(); 222 data_received_cb_.Reset(); 223 decode_cb_.Reset(); 224 225 if (destroy_pending_) { 226 DVLOG(1) << __FUNCTION__ << " : delete is pending decode completion"; 227 return; 228 } 229 230 delete this; 231} 232 233MediaCodecStatus MediaDecoderJob::QueueInputBuffer(const AccessUnit& unit) { 234 DVLOG(1) << __FUNCTION__; 235 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); 236 TRACE_EVENT0("media", __FUNCTION__); 237 238 int input_buf_index = input_buf_index_; 239 input_buf_index_ = -1; 240 241 // TODO(xhwang): Hide DequeueInputBuffer() and the index in MediaCodecBridge. 242 if (input_buf_index == -1) { 243 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( 244 kMediaCodecTimeoutInMilliseconds); 245 MediaCodecStatus status = 246 media_codec_bridge_->DequeueInputBuffer(timeout, &input_buf_index); 247 if (status != MEDIA_CODEC_OK) { 248 DVLOG(1) << "DequeueInputBuffer fails: " << status; 249 return status; 250 } 251 } 252 253 // TODO(qinmin): skip frames if video is falling far behind. 254 DCHECK_GE(input_buf_index, 0); 255 if (unit.end_of_stream || unit.data.empty()) { 256 media_codec_bridge_->QueueEOS(input_buf_index); 257 return MEDIA_CODEC_INPUT_END_OF_STREAM; 258 } 259 260 if (unit.key_id.empty() || unit.iv.empty()) { 261 DCHECK(unit.iv.empty() || !unit.key_id.empty()); 262 return media_codec_bridge_->QueueInputBuffer( 263 input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp); 264 } 265 266 MediaCodecStatus status = media_codec_bridge_->QueueSecureInputBuffer( 267 input_buf_index, 268 &unit.data[0], unit.data.size(), 269 reinterpret_cast<const uint8*>(&unit.key_id[0]), unit.key_id.size(), 270 reinterpret_cast<const uint8*>(&unit.iv[0]), unit.iv.size(), 271 unit.subsamples.empty() ? NULL : &unit.subsamples[0], 272 unit.subsamples.size(), 273 unit.timestamp); 274 275 // In case of MEDIA_CODEC_NO_KEY, we must reuse the |input_buf_index_|. 276 // Otherwise MediaDrm will report errors. 277 if (status == MEDIA_CODEC_NO_KEY) 278 input_buf_index_ = input_buf_index; 279 280 return status; 281} 282 283bool MediaDecoderJob::HasData() const { 284 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 285 // When |input_eos_encountered_| is set, |access_unit_index_| and 286 // |current_demuxer_data_index_| must be pointing to an EOS unit, 287 // or a |kConfigChanged| unit if |drain_decoder_| is true. In both cases, 288 // we'll feed an EOS input unit to drain the decoder until we hit output EOS. 289 DCHECK(!input_eos_encountered_ || !NoAccessUnitsRemainingInChunk(true)); 290 return !NoAccessUnitsRemainingInChunk(true) || 291 !NoAccessUnitsRemainingInChunk(false); 292} 293 294void MediaDecoderJob::RequestData(const base::Closure& done_cb) { 295 DVLOG(1) << __FUNCTION__; 296 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 297 DCHECK(data_received_cb_.is_null()); 298 DCHECK(!input_eos_encountered_); 299 DCHECK(NoAccessUnitsRemainingInChunk(false)); 300 301 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaDecoderJob::RequestData", this); 302 303 data_received_cb_ = done_cb; 304 305 // If we are already expecting new data, just set the callback and do 306 // nothing. 307 if (is_requesting_demuxer_data_) 308 return; 309 310 // The new incoming data will be stored as the next demuxer data chunk, since 311 // the decoder might still be decoding the current one. 312 size_t next_demuxer_data_index = inactive_demuxer_data_index(); 313 received_data_[next_demuxer_data_index] = DemuxerData(); 314 access_unit_index_[next_demuxer_data_index] = 0; 315 is_requesting_demuxer_data_ = true; 316 317 request_data_cb_.Run(); 318} 319 320void MediaDecoderJob::DecodeCurrentAccessUnit( 321 base::TimeTicks start_time_ticks, 322 base::TimeDelta start_presentation_timestamp) { 323 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 324 DCHECK(!decode_cb_.is_null()); 325 326 RequestCurrentChunkIfEmpty(); 327 const AccessUnit& access_unit = CurrentAccessUnit(); 328 if (CurrentAccessUnit().status == DemuxerStream::kConfigChanged) { 329 int index = CurrentReceivedDataChunkIndex(); 330 const DemuxerConfigs& configs = received_data_[index].demuxer_configs[0]; 331 bool reconfigure_needed = IsCodecReconfigureNeeded(configs); 332 SetDemuxerConfigs(configs); 333 if (!drain_decoder_) { 334 // If we haven't decoded any data yet, just skip the current access unit 335 // and request the MediaCodec to be recreated on next Decode(). 336 if (skip_eos_enqueue_ || !reconfigure_needed) { 337 need_to_reconfig_decoder_job_ = 338 need_to_reconfig_decoder_job_ || reconfigure_needed; 339 // Report MEDIA_CODEC_OK status so decoder will continue decoding and 340 // MEDIA_CODEC_OUTPUT_FORMAT_CHANGED status will come later. 341 ui_task_runner_->PostTask(FROM_HERE, base::Bind( 342 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this), 343 MEDIA_CODEC_OK, kNoTimestamp(), kNoTimestamp())); 344 return; 345 } 346 // Start draining the decoder so that all the remaining frames are 347 // rendered. 348 drain_decoder_ = true; 349 } 350 } 351 352 DCHECK(!(needs_flush_ && drain_decoder_)); 353 decoder_task_runner_->PostTask(FROM_HERE, base::Bind( 354 &MediaDecoderJob::DecodeInternal, base::Unretained(this), 355 drain_decoder_ ? eos_unit_ : access_unit, 356 start_time_ticks, start_presentation_timestamp, needs_flush_, 357 media::BindToCurrentLoop(base::Bind( 358 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this))))); 359 needs_flush_ = false; 360} 361 362void MediaDecoderJob::DecodeInternal( 363 const AccessUnit& unit, 364 base::TimeTicks start_time_ticks, 365 base::TimeDelta start_presentation_timestamp, 366 bool needs_flush, 367 const MediaDecoderJob::DecoderCallback& callback) { 368 DVLOG(1) << __FUNCTION__; 369 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); 370 TRACE_EVENT0("media", __FUNCTION__); 371 372 if (needs_flush) { 373 DVLOG(1) << "DecodeInternal needs flush."; 374 input_eos_encountered_ = false; 375 output_eos_encountered_ = false; 376 MediaCodecStatus reset_status = media_codec_bridge_->Reset(); 377 if (MEDIA_CODEC_OK != reset_status) { 378 callback.Run(reset_status, kNoTimestamp(), kNoTimestamp()); 379 return; 380 } 381 } 382 383 // Once output EOS has occurred, we should not be asked to decode again. 384 // MediaCodec has undefined behavior if similarly asked to decode after output 385 // EOS. 386 DCHECK(!output_eos_encountered_); 387 388 // For aborted access unit, just skip it and inform the player. 389 if (unit.status == DemuxerStream::kAborted) { 390 // TODO(qinmin): use a new enum instead of MEDIA_CODEC_STOPPED. 391 callback.Run(MEDIA_CODEC_STOPPED, kNoTimestamp(), kNoTimestamp()); 392 return; 393 } 394 395 if (skip_eos_enqueue_) { 396 if (unit.end_of_stream || unit.data.empty()) { 397 input_eos_encountered_ = true; 398 output_eos_encountered_ = true; 399 callback.Run(MEDIA_CODEC_OUTPUT_END_OF_STREAM, kNoTimestamp(), 400 kNoTimestamp()); 401 return; 402 } 403 404 skip_eos_enqueue_ = false; 405 } 406 407 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM; 408 if (!input_eos_encountered_) { 409 input_status = QueueInputBuffer(unit); 410 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) { 411 input_eos_encountered_ = true; 412 } else if (input_status != MEDIA_CODEC_OK) { 413 callback.Run(input_status, kNoTimestamp(), kNoTimestamp()); 414 return; 415 } 416 } 417 418 int buffer_index = 0; 419 size_t offset = 0; 420 size_t size = 0; 421 base::TimeDelta presentation_timestamp; 422 423 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( 424 kMediaCodecTimeoutInMilliseconds); 425 426 MediaCodecStatus status = MEDIA_CODEC_OK; 427 bool has_format_change = false; 428 // Dequeue the output buffer until a MEDIA_CODEC_OK, MEDIA_CODEC_ERROR or 429 // MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER is received. 430 do { 431 status = media_codec_bridge_->DequeueOutputBuffer( 432 timeout, 433 &buffer_index, 434 &offset, 435 &size, 436 &presentation_timestamp, 437 &output_eos_encountered_, 438 NULL); 439 if (status == MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED && 440 !media_codec_bridge_->GetOutputBuffers()) { 441 status = MEDIA_CODEC_ERROR; 442 } else if (status == MEDIA_CODEC_OUTPUT_FORMAT_CHANGED) { 443 // TODO(qinmin): instead of waiting for the next output buffer to be 444 // dequeued, post a task on the UI thread to signal the format change. 445 has_format_change = true; 446 } 447 } while (status != MEDIA_CODEC_OK && status != MEDIA_CODEC_ERROR && 448 status != MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER); 449 450 if (status != MEDIA_CODEC_OK) { 451 callback.Run(status, kNoTimestamp(), kNoTimestamp()); 452 return; 453 } 454 455 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up. 456 if (output_eos_encountered_) 457 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM; 458 else if (has_format_change) 459 status = MEDIA_CODEC_OUTPUT_FORMAT_CHANGED; 460 461 bool render_output = presentation_timestamp >= preroll_timestamp_ && 462 (status != MEDIA_CODEC_OUTPUT_END_OF_STREAM || size != 0u); 463 base::TimeDelta time_to_render; 464 DCHECK(!start_time_ticks.is_null()); 465 if (render_output && ComputeTimeToRender()) { 466 time_to_render = presentation_timestamp - (base::TimeTicks::Now() - 467 start_time_ticks + start_presentation_timestamp); 468 } 469 470 if (time_to_render > base::TimeDelta()) { 471 decoder_task_runner_->PostDelayedTask( 472 FROM_HERE, 473 base::Bind(&MediaDecoderJob::ReleaseOutputBuffer, 474 base::Unretained(this), 475 buffer_index, 476 size, 477 render_output, 478 presentation_timestamp, 479 base::Bind(callback, status)), 480 time_to_render); 481 return; 482 } 483 484 // TODO(qinmin): The codec is lagging behind, need to recalculate the 485 // |start_presentation_timestamp_| and |start_time_ticks_| in 486 // media_source_player.cc. 487 DVLOG(1) << "codec is lagging behind :" << time_to_render.InMicroseconds(); 488 if (render_output) { 489 // The player won't expect a timestamp smaller than the 490 // |start_presentation_timestamp|. However, this could happen due to decoder 491 // errors. 492 presentation_timestamp = std::max( 493 presentation_timestamp, start_presentation_timestamp); 494 } else { 495 presentation_timestamp = kNoTimestamp(); 496 } 497 ReleaseOutputCompletionCallback completion_callback = base::Bind( 498 callback, status); 499 ReleaseOutputBuffer(buffer_index, size, render_output, presentation_timestamp, 500 completion_callback); 501} 502 503void MediaDecoderJob::OnDecodeCompleted( 504 MediaCodecStatus status, base::TimeDelta current_presentation_timestamp, 505 base::TimeDelta max_presentation_timestamp) { 506 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 507 508 if (destroy_pending_) { 509 DVLOG(1) << __FUNCTION__ << " : completing pending deletion"; 510 delete this; 511 return; 512 } 513 514 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) 515 output_eos_encountered_ = true; 516 517 DCHECK(!decode_cb_.is_null()); 518 519 // If output was queued for rendering, then we have completed prerolling. 520 if (current_presentation_timestamp != kNoTimestamp()) 521 prerolling_ = false; 522 523 switch (status) { 524 case MEDIA_CODEC_OK: 525 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: 526 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: 527 case MEDIA_CODEC_OUTPUT_END_OF_STREAM: 528 if (!input_eos_encountered_) { 529 CurrentDataConsumed( 530 CurrentAccessUnit().status == DemuxerStream::kConfigChanged); 531 access_unit_index_[current_demuxer_data_index_]++; 532 } 533 break; 534 535 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: 536 case MEDIA_CODEC_INPUT_END_OF_STREAM: 537 case MEDIA_CODEC_NO_KEY: 538 case MEDIA_CODEC_STOPPED: 539 case MEDIA_CODEC_ERROR: 540 // Do nothing. 541 break; 542 543 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: 544 DCHECK(false) << "Invalid output status"; 545 break; 546 }; 547 548 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM && drain_decoder_) { 549 OnDecoderDrained(); 550 status = MEDIA_CODEC_OK; 551 } 552 553 if (status == MEDIA_CODEC_OUTPUT_FORMAT_CHANGED) { 554 if (UpdateOutputFormat()) 555 config_changed_cb_.Run(); 556 status = MEDIA_CODEC_OK; 557 } 558 559 if (release_resources_pending_) { 560 ReleaseMediaCodecBridge(); 561 release_resources_pending_ = false; 562 if (drain_decoder_) 563 OnDecoderDrained(); 564 } 565 566 stop_decode_pending_ = false; 567 base::ResetAndReturn(&decode_cb_).Run( 568 status, current_presentation_timestamp, max_presentation_timestamp); 569} 570 571const AccessUnit& MediaDecoderJob::CurrentAccessUnit() const { 572 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 573 DCHECK(HasData()); 574 size_t index = CurrentReceivedDataChunkIndex(); 575 return received_data_[index].access_units[access_unit_index_[index]]; 576} 577 578size_t MediaDecoderJob::CurrentReceivedDataChunkIndex() const { 579 return NoAccessUnitsRemainingInChunk(true) ? 580 inactive_demuxer_data_index() : current_demuxer_data_index_; 581} 582 583bool MediaDecoderJob::NoAccessUnitsRemainingInChunk( 584 bool is_active_chunk) const { 585 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 586 size_t index = is_active_chunk ? current_demuxer_data_index_ : 587 inactive_demuxer_data_index(); 588 return received_data_[index].access_units.size() <= access_unit_index_[index]; 589} 590 591void MediaDecoderJob::RequestCurrentChunkIfEmpty() { 592 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 593 DCHECK(HasData()); 594 if (!NoAccessUnitsRemainingInChunk(true)) 595 return; 596 597 // Requests new data if the the last access unit of the next chunk is not EOS. 598 current_demuxer_data_index_ = inactive_demuxer_data_index(); 599 const AccessUnit last_access_unit = 600 received_data_[current_demuxer_data_index_].access_units.back(); 601 if (!last_access_unit.end_of_stream && 602 last_access_unit.status != DemuxerStream::kAborted) { 603 RequestData(base::Closure()); 604 } 605} 606 607void MediaDecoderJob::InitializeReceivedData() { 608 for (size_t i = 0; i < 2; ++i) { 609 received_data_[i] = DemuxerData(); 610 access_unit_index_[i] = 0; 611 } 612} 613 614void MediaDecoderJob::OnDecoderDrained() { 615 DVLOG(1) << __FUNCTION__; 616 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 617 DCHECK(drain_decoder_); 618 619 input_eos_encountered_ = false; 620 output_eos_encountered_ = false; 621 drain_decoder_ = false; 622 ReleaseMediaCodecBridge(); 623 // Increase the access unit index so that the new decoder will not handle 624 // the config change again. 625 access_unit_index_[current_demuxer_data_index_]++; 626 CurrentDataConsumed(true); 627} 628 629bool MediaDecoderJob::CreateMediaCodecBridge() { 630 DVLOG(1) << __FUNCTION__; 631 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 632 DCHECK(decode_cb_.is_null()); 633 634 if (!HasStream()) { 635 ReleaseMediaCodecBridge(); 636 return false; 637 } 638 639 // Create |media_codec_bridge_| only if config changes. 640 if (media_codec_bridge_ && !need_to_reconfig_decoder_job_) 641 return true; 642 643 base::android::ScopedJavaLocalRef<jobject> media_crypto = GetMediaCrypto(); 644 if (is_content_encrypted_ && media_crypto.is_null()) 645 return false; 646 647 ReleaseMediaCodecBridge(); 648 DVLOG(1) << __FUNCTION__ << " : creating new media codec bridge"; 649 650 return CreateMediaCodecBridgeInternal(); 651} 652 653bool MediaDecoderJob::IsCodecReconfigureNeeded( 654 const DemuxerConfigs& configs) const { 655 if (!AreDemuxerConfigsChanged(configs)) 656 return false; 657 return true; 658} 659 660bool MediaDecoderJob::UpdateOutputFormat() { 661 return false; 662} 663 664void MediaDecoderJob::ReleaseMediaCodecBridge() { 665 if (!media_codec_bridge_) 666 return; 667 668 media_codec_bridge_.reset(); 669 input_buf_index_ = -1; 670} 671 672} // namespace media 673