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 = media_codec_bridge_->DequeueOutputBuffer( | 329 MediaCodecStatus status = media_codec_bridge_->DequeueOutputBuffer( |
324 timeout, &buffer_index, &offset, &size, &presentation_timestamp, | 330 timeout, &buffer_index, &offset, &size, &presentation_timestamp, |
325 &output_eos_encountered); | 331 &output_eos_encountered_); |
326 | 332 |
327 if (status != MEDIA_CODEC_OK) { | 333 if (status != MEDIA_CODEC_OK) { |
328 if (status == MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED && | 334 if (status == MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED && |
329 !media_codec_bridge_->GetOutputBuffers()) { | 335 !media_codec_bridge_->GetOutputBuffers()) { |
330 status = MEDIA_CODEC_ERROR; | 336 status = MEDIA_CODEC_ERROR; |
331 } | 337 } |
332 callback.Run(status, kNoTimestamp(), 0); | 338 callback.Run(status, kNoTimestamp(), 0); |
333 return; | 339 return; |
334 } | 340 } |
335 | 341 |
336 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up. | 342 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up. |
337 if (output_eos_encountered) | 343 if (output_eos_encountered_) |
338 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM; | 344 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM; |
339 else if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) | 345 else if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) |
340 status = MEDIA_CODEC_INPUT_END_OF_STREAM; | 346 status = MEDIA_CODEC_INPUT_END_OF_STREAM; |
341 | 347 |
342 // Check whether we need to render the output. | 348 // Check whether we need to render the output. |
343 // TODO(qinmin): comparing most recently queued input's |unit.timestamp| with | 349 // TODO(qinmin): comparing most recently queued input's |unit.timestamp| with |
344 // |preroll_timestamp_| is not accurate due to data reordering and possible | 350 // |preroll_timestamp_| is not accurate due to data reordering and possible |
345 // input queueing without immediate dequeue when |input_status| != | 351 // input queueing without immediate dequeue when |input_status| != |
346 // |MEDIA_CODEC_OK|. Need to use the |presentation_timestamp| for video, and | 352 // |MEDIA_CODEC_OK|. Need to use the |presentation_timestamp| for video, and |
347 // use |size| to calculate the timestamp for audio. See | 353 // use |size| to calculate the timestamp for audio. See |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 // Do nothing. | 424 // Do nothing. |
419 break; | 425 break; |
420 }; | 426 }; |
421 | 427 |
422 stop_decode_pending_ = false; | 428 stop_decode_pending_ = false; |
423 base::ResetAndReturn(&decode_cb_).Run(status, presentation_timestamp, | 429 base::ResetAndReturn(&decode_cb_).Run(status, presentation_timestamp, |
424 audio_output_bytes); | 430 audio_output_bytes); |
425 } | 431 } |
426 | 432 |
427 } // namespace media | 433 } // namespace media |
OLD | NEW |