| 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.h" | 10 #include "base/message_loop/message_loop.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 | 21 |
| 22 MediaDecoderJob::MediaDecoderJob( | 22 MediaDecoderJob::MediaDecoderJob( |
| 23 const scoped_refptr<base::MessageLoopProxy>& decoder_loop, | 23 const scoped_refptr<base::MessageLoopProxy>& decoder_loop, |
| 24 MediaCodecBridge* media_codec_bridge, | 24 MediaCodecBridge* media_codec_bridge, |
| 25 const base::Closure& request_data_cb) | 25 const base::Closure& request_data_cb) |
| 26 : ui_loop_(base::MessageLoopProxy::current()), | 26 : ui_loop_(base::MessageLoopProxy::current()), |
| 27 decoder_loop_(decoder_loop), | 27 decoder_loop_(decoder_loop), |
| 28 media_codec_bridge_(media_codec_bridge), | 28 media_codec_bridge_(media_codec_bridge), |
| 29 needs_flush_(false), | 29 needs_flush_(false), |
| 30 input_eos_encountered_(false), | 30 input_eos_encountered_(false), |
| 31 output_eos_encountered_(false), |
| 31 skip_eos_enqueue_(true), | 32 skip_eos_enqueue_(true), |
| 32 prerolling_(true), | 33 prerolling_(true), |
| 33 weak_this_(this), | 34 weak_this_(this), |
| 34 request_data_cb_(request_data_cb), | 35 request_data_cb_(request_data_cb), |
| 35 access_unit_index_(0), | 36 access_unit_index_(0), |
| 36 input_buf_index_(-1), | 37 input_buf_index_(-1), |
| 37 stop_decode_pending_(false), | 38 stop_decode_pending_(false), |
| 38 destroy_pending_(false) { | 39 destroy_pending_(false) { |
| 39 } | 40 } |
| 40 | 41 |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 const base::TimeDelta& start_presentation_timestamp, | 269 const base::TimeDelta& start_presentation_timestamp, |
| 269 bool needs_flush, | 270 bool needs_flush, |
| 270 const MediaDecoderJob::DecoderCallback& callback) { | 271 const MediaDecoderJob::DecoderCallback& callback) { |
| 271 DVLOG(1) << __FUNCTION__; | 272 DVLOG(1) << __FUNCTION__; |
| 272 DCHECK(decoder_loop_->BelongsToCurrentThread()); | 273 DCHECK(decoder_loop_->BelongsToCurrentThread()); |
| 273 TRACE_EVENT0("media", __FUNCTION__); | 274 TRACE_EVENT0("media", __FUNCTION__); |
| 274 | 275 |
| 275 if (needs_flush) { | 276 if (needs_flush) { |
| 276 DVLOG(1) << "DecodeInternal needs flush."; | 277 DVLOG(1) << "DecodeInternal needs flush."; |
| 277 input_eos_encountered_ = false; | 278 input_eos_encountered_ = false; |
| 279 output_eos_encountered_ = false; |
| 278 MediaCodecStatus reset_status = media_codec_bridge_->Reset(); | 280 MediaCodecStatus reset_status = media_codec_bridge_->Reset(); |
| 279 if (MEDIA_CODEC_OK != reset_status) { | 281 if (MEDIA_CODEC_OK != reset_status) { |
| 280 callback.Run(reset_status, kNoTimestamp(), 0); | 282 callback.Run(reset_status, kNoTimestamp(), 0); |
| 281 return; | 283 return; |
| 282 } | 284 } |
| 283 } | 285 } |
| 284 | 286 |
| 287 // Once output EOS has occurred, we should not be asked to decode again. |
| 288 // MediaCodec has undefined behavior if similarly asked to decode after output |
| 289 // EOS. |
| 290 DCHECK(!output_eos_encountered_); |
| 291 |
| 285 // For aborted access unit, just skip it and inform the player. | 292 // For aborted access unit, just skip it and inform the player. |
| 286 if (unit.status == DemuxerStream::kAborted) { | 293 if (unit.status == DemuxerStream::kAborted) { |
| 287 // TODO(qinmin): use a new enum instead of MEDIA_CODEC_STOPPED. | 294 // TODO(qinmin): use a new enum instead of MEDIA_CODEC_STOPPED. |
| 288 callback.Run(MEDIA_CODEC_STOPPED, kNoTimestamp(), 0); | 295 callback.Run(MEDIA_CODEC_STOPPED, kNoTimestamp(), 0); |
| 289 return; | 296 return; |
| 290 } | 297 } |
| 291 | 298 |
| 292 if (skip_eos_enqueue_) { | 299 if (skip_eos_enqueue_) { |
| 293 if (unit.end_of_stream || unit.data.empty()) { | 300 if (unit.end_of_stream || unit.data.empty()) { |
| 294 input_eos_encountered_ = true; | 301 input_eos_encountered_ = true; |
| 302 output_eos_encountered_ = true; |
| 295 callback.Run(MEDIA_CODEC_OUTPUT_END_OF_STREAM, kNoTimestamp(), 0); | 303 callback.Run(MEDIA_CODEC_OUTPUT_END_OF_STREAM, kNoTimestamp(), 0); |
| 296 return; | 304 return; |
| 297 } | 305 } |
| 298 | 306 |
| 299 skip_eos_enqueue_ = false; | 307 skip_eos_enqueue_ = false; |
| 300 } | 308 } |
| 301 | 309 |
| 302 | |
| 303 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM; | 310 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM; |
| 304 if (!input_eos_encountered_) { | 311 if (!input_eos_encountered_) { |
| 305 input_status = QueueInputBuffer(unit); | 312 input_status = QueueInputBuffer(unit); |
| 306 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) { | 313 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) { |
| 307 input_eos_encountered_ = true; | 314 input_eos_encountered_ = true; |
| 308 } else if (input_status != MEDIA_CODEC_OK) { | 315 } else if (input_status != MEDIA_CODEC_OK) { |
| 309 callback.Run(input_status, kNoTimestamp(), 0); | 316 callback.Run(input_status, kNoTimestamp(), 0); |
| 310 return; | 317 return; |
| 311 } | 318 } |
| 312 } | 319 } |
| 313 | 320 |
| 314 int buffer_index = 0; | 321 int buffer_index = 0; |
| 315 size_t offset = 0; | 322 size_t offset = 0; |
| 316 size_t size = 0; | 323 size_t size = 0; |
| 317 base::TimeDelta presentation_timestamp; | 324 base::TimeDelta presentation_timestamp; |
| 318 bool output_eos_encountered = false; | |
| 319 | 325 |
| 320 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( | 326 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( |
| 321 kMediaCodecTimeoutInMilliseconds); | 327 kMediaCodecTimeoutInMilliseconds); |
| 322 | 328 |
| 323 MediaCodecStatus status = | 329 MediaCodecStatus status = |
| 324 media_codec_bridge_->DequeueOutputBuffer(timeout, | 330 media_codec_bridge_->DequeueOutputBuffer(timeout, |
| 325 &buffer_index, | 331 &buffer_index, |
| 326 &offset, | 332 &offset, |
| 327 &size, | 333 &size, |
| 328 &presentation_timestamp, | 334 &presentation_timestamp, |
| 329 &output_eos_encountered, | 335 &output_eos_encountered_, |
| 330 NULL); | 336 NULL); |
| 331 | 337 |
| 332 if (status != MEDIA_CODEC_OK) { | 338 if (status != MEDIA_CODEC_OK) { |
| 333 if (status == MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED && | 339 if (status == MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED && |
| 334 !media_codec_bridge_->GetOutputBuffers()) { | 340 !media_codec_bridge_->GetOutputBuffers()) { |
| 335 status = MEDIA_CODEC_ERROR; | 341 status = MEDIA_CODEC_ERROR; |
| 336 } | 342 } |
| 337 callback.Run(status, kNoTimestamp(), 0); | 343 callback.Run(status, kNoTimestamp(), 0); |
| 338 return; | 344 return; |
| 339 } | 345 } |
| 340 | 346 |
| 341 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up. | 347 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up. |
| 342 if (output_eos_encountered) | 348 if (output_eos_encountered_) |
| 343 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM; | 349 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM; |
| 344 else if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) | 350 else if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) |
| 345 status = MEDIA_CODEC_INPUT_END_OF_STREAM; | 351 status = MEDIA_CODEC_INPUT_END_OF_STREAM; |
| 346 | 352 |
| 347 // Check whether we need to render the output. | 353 // Check whether we need to render the output. |
| 348 // TODO(qinmin): comparing most recently queued input's |unit.timestamp| with | 354 // TODO(qinmin): comparing most recently queued input's |unit.timestamp| with |
| 349 // |preroll_timestamp_| is not accurate due to data reordering and possible | 355 // |preroll_timestamp_| is not accurate due to data reordering and possible |
| 350 // input queueing without immediate dequeue when |input_status| != | 356 // input queueing without immediate dequeue when |input_status| != |
| 351 // |MEDIA_CODEC_OK|. Need to use the |presentation_timestamp| for video, and | 357 // |MEDIA_CODEC_OK|. Need to use the |presentation_timestamp| for video, and |
| 352 // use |size| to calculate the timestamp for audio. See | 358 // use |size| to calculate the timestamp for audio. See |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 423 // Do nothing. | 429 // Do nothing. |
| 424 break; | 430 break; |
| 425 }; | 431 }; |
| 426 | 432 |
| 427 stop_decode_pending_ = false; | 433 stop_decode_pending_ = false; |
| 428 base::ResetAndReturn(&decode_cb_).Run(status, presentation_timestamp, | 434 base::ResetAndReturn(&decode_cb_).Run(status, presentation_timestamp, |
| 429 audio_output_bytes); | 435 audio_output_bytes); |
| 430 } | 436 } |
| 431 | 437 |
| 432 } // namespace media | 438 } // namespace media |
| OLD | NEW |