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