| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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_decoder_job.h" | 5 #include "media/base/android/media_decoder_job.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
| 9 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
| 10 #include "base/message_loop/message_loop_proxy.h" | 10 #include "base/message_loop/message_loop_proxy.h" |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 return; | 66 return; |
| 67 } | 67 } |
| 68 | 68 |
| 69 size_t next_demuxer_data_index = inactive_demuxer_data_index(); | 69 size_t next_demuxer_data_index = inactive_demuxer_data_index(); |
| 70 received_data_[next_demuxer_data_index] = data; | 70 received_data_[next_demuxer_data_index] = data; |
| 71 access_unit_index_[next_demuxer_data_index] = 0; | 71 access_unit_index_[next_demuxer_data_index] = 0; |
| 72 is_requesting_demuxer_data_ = false; | 72 is_requesting_demuxer_data_ = false; |
| 73 | 73 |
| 74 base::Closure done_cb = base::ResetAndReturn(&on_data_received_cb_); | 74 base::Closure done_cb = base::ResetAndReturn(&on_data_received_cb_); |
| 75 if (stop_decode_pending_) { | 75 if (stop_decode_pending_) { |
| 76 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), 0); | 76 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), 0, 0, |
| 77 base::TimeTicks()); |
| 77 return; | 78 return; |
| 78 } | 79 } |
| 79 | 80 |
| 80 if (!done_cb.is_null()) | 81 if (!done_cb.is_null()) |
| 81 done_cb.Run(); | 82 done_cb.Run(); |
| 82 } | 83 } |
| 83 | 84 |
| 84 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) { | 85 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) { |
| 85 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 86 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 86 DCHECK(on_data_received_cb_.is_null()); | 87 DCHECK(on_data_received_cb_.is_null()); |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 RequestCurrentChunkIfEmpty(); | 264 RequestCurrentChunkIfEmpty(); |
| 264 const AccessUnit& access_unit = CurrentAccessUnit(); | 265 const AccessUnit& access_unit = CurrentAccessUnit(); |
| 265 // If the first access unit is a config change, request the player to dequeue | 266 // If the first access unit is a config change, request the player to dequeue |
| 266 // the input buffer again so that it can request config data. | 267 // the input buffer again so that it can request config data. |
| 267 if (access_unit.status == DemuxerStream::kConfigChanged) { | 268 if (access_unit.status == DemuxerStream::kConfigChanged) { |
| 268 ui_task_runner_->PostTask(FROM_HERE, | 269 ui_task_runner_->PostTask(FROM_HERE, |
| 269 base::Bind(&MediaDecoderJob::OnDecodeCompleted, | 270 base::Bind(&MediaDecoderJob::OnDecodeCompleted, |
| 270 base::Unretained(this), | 271 base::Unretained(this), |
| 271 MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER, | 272 MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER, |
| 272 kNoTimestamp(), | 273 kNoTimestamp(), |
| 273 0)); | 274 0, 0, base::TimeTicks())); |
| 274 return; | 275 return; |
| 275 } | 276 } |
| 276 | 277 |
| 277 decoder_task_runner_->PostTask(FROM_HERE, base::Bind( | 278 decoder_task_runner_->PostTask(FROM_HERE, base::Bind( |
| 278 &MediaDecoderJob::DecodeInternal, base::Unretained(this), | 279 &MediaDecoderJob::DecodeInternal, base::Unretained(this), |
| 279 access_unit, | 280 access_unit, |
| 280 start_time_ticks, start_presentation_timestamp, needs_flush_, | 281 start_time_ticks, start_presentation_timestamp, needs_flush_, |
| 281 media::BindToCurrentLoop(base::Bind( | 282 media::BindToCurrentLoop(base::Bind( |
| 282 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this))))); | 283 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this))))); |
| 283 needs_flush_ = false; | 284 needs_flush_ = false; |
| 284 } | 285 } |
| 285 | 286 |
| 286 void MediaDecoderJob::DecodeInternal( | 287 void MediaDecoderJob::DecodeInternal( |
| 287 const AccessUnit& unit, | 288 const AccessUnit& unit, |
| 288 base::TimeTicks start_time_ticks, | 289 base::TimeTicks start_time_ticks, |
| 289 base::TimeDelta start_presentation_timestamp, | 290 base::TimeDelta start_presentation_timestamp, |
| 290 bool needs_flush, | 291 bool needs_flush, |
| 291 const MediaDecoderJob::DecoderCallback& callback) { | 292 const MediaDecoderJob::DecoderCallback& callback) { |
| 292 DVLOG(1) << __FUNCTION__; | 293 DVLOG(1) << __FUNCTION__; |
| 293 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); | 294 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); |
| 294 TRACE_EVENT0("media", __FUNCTION__); | 295 TRACE_EVENT0("media", __FUNCTION__); |
| 295 | 296 |
| 296 if (needs_flush) { | 297 if (needs_flush) { |
| 297 DVLOG(1) << "DecodeInternal needs flush."; | 298 DVLOG(1) << "DecodeInternal needs flush."; |
| 298 input_eos_encountered_ = false; | 299 input_eos_encountered_ = false; |
| 299 output_eos_encountered_ = false; | 300 output_eos_encountered_ = false; |
| 300 MediaCodecStatus reset_status = media_codec_bridge_->Reset(); | 301 MediaCodecStatus reset_status = media_codec_bridge_->Reset(); |
| 301 if (MEDIA_CODEC_OK != reset_status) { | 302 if (MEDIA_CODEC_OK != reset_status) { |
| 302 callback.Run(reset_status, kNoTimestamp(), 0); | 303 callback.Run(reset_status, kNoTimestamp(), 0, 0, base::TimeTicks()); |
| 303 return; | 304 return; |
| 304 } | 305 } |
| 305 } | 306 } |
| 306 | 307 |
| 307 // Once output EOS has occurred, we should not be asked to decode again. | 308 // Once output EOS has occurred, we should not be asked to decode again. |
| 308 // MediaCodec has undefined behavior if similarly asked to decode after output | 309 // MediaCodec has undefined behavior if similarly asked to decode after output |
| 309 // EOS. | 310 // EOS. |
| 310 DCHECK(!output_eos_encountered_); | 311 DCHECK(!output_eos_encountered_); |
| 311 | 312 |
| 312 // For aborted access unit, just skip it and inform the player. | 313 // For aborted access unit, just skip it and inform the player. |
| 313 if (unit.status == DemuxerStream::kAborted) { | 314 if (unit.status == DemuxerStream::kAborted) { |
| 314 // TODO(qinmin): use a new enum instead of MEDIA_CODEC_STOPPED. | 315 // TODO(qinmin): use a new enum instead of MEDIA_CODEC_STOPPED. |
| 315 callback.Run(MEDIA_CODEC_STOPPED, kNoTimestamp(), 0); | 316 callback.Run(MEDIA_CODEC_STOPPED, kNoTimestamp(), 0, 0, base::TimeTicks()); |
| 316 return; | 317 return; |
| 317 } | 318 } |
| 318 | 319 |
| 319 if (skip_eos_enqueue_) { | 320 if (skip_eos_enqueue_) { |
| 320 if (unit.end_of_stream || unit.data.empty()) { | 321 if (unit.end_of_stream || unit.data.empty()) { |
| 321 input_eos_encountered_ = true; | 322 input_eos_encountered_ = true; |
| 322 output_eos_encountered_ = true; | 323 output_eos_encountered_ = true; |
| 323 callback.Run(MEDIA_CODEC_OUTPUT_END_OF_STREAM, kNoTimestamp(), 0); | 324 callback.Run(MEDIA_CODEC_OUTPUT_END_OF_STREAM, kNoTimestamp(), 0, 0, |
| 325 base::TimeTicks()); |
| 324 return; | 326 return; |
| 325 } | 327 } |
| 326 | 328 |
| 327 skip_eos_enqueue_ = false; | 329 skip_eos_enqueue_ = false; |
| 328 } | 330 } |
| 329 | 331 |
| 330 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM; | 332 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM; |
| 331 if (!input_eos_encountered_) { | 333 if (!input_eos_encountered_) { |
| 332 input_status = QueueInputBuffer(unit); | 334 input_status = QueueInputBuffer(unit); |
| 333 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) { | 335 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) { |
| 334 input_eos_encountered_ = true; | 336 input_eos_encountered_ = true; |
| 335 } else if (input_status != MEDIA_CODEC_OK) { | 337 } else if (input_status != MEDIA_CODEC_OK) { |
| 336 callback.Run(input_status, kNoTimestamp(), 0); | 338 callback.Run(input_status, kNoTimestamp(), 0, 0, base::TimeTicks()); |
| 337 return; | 339 return; |
| 338 } | 340 } |
| 339 } | 341 } |
| 340 | 342 |
| 341 int buffer_index = 0; | 343 int buffer_index = 0; |
| 342 size_t offset = 0; | 344 size_t offset = 0; |
| 343 size_t size = 0; | 345 size_t size = 0; |
| 344 base::TimeDelta presentation_timestamp; | 346 base::TimeDelta presentation_timestamp; |
| 345 | 347 |
| 346 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( | 348 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( |
| 347 kMediaCodecTimeoutInMilliseconds); | 349 kMediaCodecTimeoutInMilliseconds); |
| 348 | 350 |
| 349 MediaCodecStatus status = | 351 MediaCodecStatus status = |
| 350 media_codec_bridge_->DequeueOutputBuffer(timeout, | 352 media_codec_bridge_->DequeueOutputBuffer(timeout, |
| 351 &buffer_index, | 353 &buffer_index, |
| 352 &offset, | 354 &offset, |
| 353 &size, | 355 &size, |
| 354 &presentation_timestamp, | 356 &presentation_timestamp, |
| 355 &output_eos_encountered_, | 357 &output_eos_encountered_, |
| 356 NULL); | 358 NULL); |
| 357 | 359 |
| 358 if (status != MEDIA_CODEC_OK) { | 360 if (status != MEDIA_CODEC_OK) { |
| 359 if (status == MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED && | 361 if (status == MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED && |
| 360 !media_codec_bridge_->GetOutputBuffers()) { | 362 !media_codec_bridge_->GetOutputBuffers()) { |
| 361 status = MEDIA_CODEC_ERROR; | 363 status = MEDIA_CODEC_ERROR; |
| 362 } | 364 } |
| 363 callback.Run(status, kNoTimestamp(), 0); | 365 callback.Run(status, kNoTimestamp(), 0, 0, base::TimeTicks()); |
| 364 return; | 366 return; |
| 365 } | 367 } |
| 366 | 368 |
| 367 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up. | 369 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up. |
| 368 if (output_eos_encountered_) | 370 if (output_eos_encountered_) |
| 369 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM; | 371 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM; |
| 370 else if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) | 372 else if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) |
| 371 status = MEDIA_CODEC_INPUT_END_OF_STREAM; | 373 status = MEDIA_CODEC_INPUT_END_OF_STREAM; |
| 372 | 374 |
| 373 bool render_output = presentation_timestamp >= preroll_timestamp_ && | 375 bool render_output = presentation_timestamp >= preroll_timestamp_ && |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 } else { | 407 } else { |
| 406 presentation_timestamp = kNoTimestamp(); | 408 presentation_timestamp = kNoTimestamp(); |
| 407 } | 409 } |
| 408 ReleaseOutputCompletionCallback completion_callback = base::Bind( | 410 ReleaseOutputCompletionCallback completion_callback = base::Bind( |
| 409 callback, status, presentation_timestamp); | 411 callback, status, presentation_timestamp); |
| 410 ReleaseOutputBuffer(buffer_index, size, render_output, completion_callback); | 412 ReleaseOutputBuffer(buffer_index, size, render_output, completion_callback); |
| 411 } | 413 } |
| 412 | 414 |
| 413 void MediaDecoderJob::OnDecodeCompleted( | 415 void MediaDecoderJob::OnDecodeCompleted( |
| 414 MediaCodecStatus status, base::TimeDelta presentation_timestamp, | 416 MediaCodecStatus status, base::TimeDelta presentation_timestamp, |
| 415 size_t audio_output_bytes) { | 417 size_t audio_output_bytes, int64 audio_head_position, |
| 418 base::TimeTicks audio_render_time) { |
| 416 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 419 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 417 | 420 |
| 418 if (destroy_pending_) { | 421 if (destroy_pending_) { |
| 419 DVLOG(1) << __FUNCTION__ << " : completing pending deletion"; | 422 DVLOG(1) << __FUNCTION__ << " : completing pending deletion"; |
| 420 delete this; | 423 delete this; |
| 421 return; | 424 return; |
| 422 } | 425 } |
| 423 | 426 |
| 424 DCHECK(!decode_cb_.is_null()); | 427 DCHECK(!decode_cb_.is_null()); |
| 425 | 428 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 440 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: | 443 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: |
| 441 case MEDIA_CODEC_INPUT_END_OF_STREAM: | 444 case MEDIA_CODEC_INPUT_END_OF_STREAM: |
| 442 case MEDIA_CODEC_NO_KEY: | 445 case MEDIA_CODEC_NO_KEY: |
| 443 case MEDIA_CODEC_STOPPED: | 446 case MEDIA_CODEC_STOPPED: |
| 444 case MEDIA_CODEC_ERROR: | 447 case MEDIA_CODEC_ERROR: |
| 445 // Do nothing. | 448 // Do nothing. |
| 446 break; | 449 break; |
| 447 }; | 450 }; |
| 448 | 451 |
| 449 stop_decode_pending_ = false; | 452 stop_decode_pending_ = false; |
| 450 base::ResetAndReturn(&decode_cb_).Run(status, presentation_timestamp, | 453 base::ResetAndReturn(&decode_cb_).Run( |
| 451 audio_output_bytes); | 454 status, presentation_timestamp, audio_output_bytes, audio_head_position, |
| 455 audio_render_time); |
| 452 } | 456 } |
| 453 | 457 |
| 454 const AccessUnit& MediaDecoderJob::CurrentAccessUnit() const { | 458 const AccessUnit& MediaDecoderJob::CurrentAccessUnit() const { |
| 455 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 459 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 456 DCHECK(HasData()); | 460 DCHECK(HasData()); |
| 457 int index = NoAccessUnitsRemainingInChunk(true) ? | 461 int index = NoAccessUnitsRemainingInChunk(true) ? |
| 458 inactive_demuxer_data_index() : current_demuxer_data_index_; | 462 inactive_demuxer_data_index() : current_demuxer_data_index_; |
| 459 return received_data_[index].access_units[access_unit_index_[index]]; | 463 return received_data_[index].access_units[access_unit_index_[index]]; |
| 460 } | 464 } |
| 461 | 465 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 } | 499 } |
| 496 | 500 |
| 497 void MediaDecoderJob::InitializeReceivedData() { | 501 void MediaDecoderJob::InitializeReceivedData() { |
| 498 for (size_t i = 0; i < 2; ++i) { | 502 for (size_t i = 0; i < 2; ++i) { |
| 499 received_data_[i] = DemuxerData(); | 503 received_data_[i] = DemuxerData(); |
| 500 access_unit_index_[i] = 0; | 504 access_unit_index_[i] = 0; |
| 501 } | 505 } |
| 502 } | 506 } |
| 503 | 507 |
| 504 } // namespace media | 508 } // namespace media |
| OLD | NEW |