Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(126)

Side by Side Diff: media/base/android/media_decoder_job.cc

Issue 238053004: Revert of Fix an issue that audio and video may run out of sync (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/base/android/media_decoder_job.h ('k') | media/base/android/media_source_player.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 75
76 // If this data request is for the inactive chunk, or |on_data_received_cb_| 76 // If this data request is for the inactive chunk, or |on_data_received_cb_|
77 // was set to null by ClearData() or Release(), do nothing. 77 // was set to null by ClearData() or Release(), do nothing.
78 if (done_cb.is_null()) 78 if (done_cb.is_null())
79 return; 79 return;
80 80
81 if (stop_decode_pending_) { 81 if (stop_decode_pending_) {
82 DCHECK(is_decoding()); 82 DCHECK(is_decoding());
83 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), kNoTimestamp()); 83 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), 0);
84 return; 84 return;
85 } 85 }
86 86
87 done_cb.Run(); 87 done_cb.Run();
88 } 88 }
89 89
90 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) { 90 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) {
91 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 91 DCHECK(ui_task_runner_->BelongsToCurrentThread());
92 DCHECK(on_data_received_cb_.is_null()); 92 DCHECK(on_data_received_cb_.is_null());
93 DCHECK(decode_cb_.is_null()); 93 DCHECK(decode_cb_.is_null());
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 268
269 RequestCurrentChunkIfEmpty(); 269 RequestCurrentChunkIfEmpty();
270 const AccessUnit& access_unit = CurrentAccessUnit(); 270 const AccessUnit& access_unit = CurrentAccessUnit();
271 // If the first access unit is a config change, request the player to dequeue 271 // If the first access unit is a config change, request the player to dequeue
272 // the input buffer again so that it can request config data. 272 // the input buffer again so that it can request config data.
273 if (access_unit.status == DemuxerStream::kConfigChanged) { 273 if (access_unit.status == DemuxerStream::kConfigChanged) {
274 ui_task_runner_->PostTask(FROM_HERE, 274 ui_task_runner_->PostTask(FROM_HERE,
275 base::Bind(&MediaDecoderJob::OnDecodeCompleted, 275 base::Bind(&MediaDecoderJob::OnDecodeCompleted,
276 base::Unretained(this), 276 base::Unretained(this),
277 MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER, 277 MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER,
278 kNoTimestamp(), kNoTimestamp())); 278 kNoTimestamp(),
279 0));
279 return; 280 return;
280 } 281 }
281 282
282 decoder_task_runner_->PostTask(FROM_HERE, base::Bind( 283 decoder_task_runner_->PostTask(FROM_HERE, base::Bind(
283 &MediaDecoderJob::DecodeInternal, base::Unretained(this), 284 &MediaDecoderJob::DecodeInternal, base::Unretained(this),
284 access_unit, 285 access_unit,
285 start_time_ticks, start_presentation_timestamp, needs_flush_, 286 start_time_ticks, start_presentation_timestamp, needs_flush_,
286 media::BindToCurrentLoop(base::Bind( 287 media::BindToCurrentLoop(base::Bind(
287 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this))))); 288 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this)))));
288 needs_flush_ = false; 289 needs_flush_ = false;
289 } 290 }
290 291
291 void MediaDecoderJob::DecodeInternal( 292 void MediaDecoderJob::DecodeInternal(
292 const AccessUnit& unit, 293 const AccessUnit& unit,
293 base::TimeTicks start_time_ticks, 294 base::TimeTicks start_time_ticks,
294 base::TimeDelta start_presentation_timestamp, 295 base::TimeDelta start_presentation_timestamp,
295 bool needs_flush, 296 bool needs_flush,
296 const MediaDecoderJob::DecoderCallback& callback) { 297 const MediaDecoderJob::DecoderCallback& callback) {
297 DVLOG(1) << __FUNCTION__; 298 DVLOG(1) << __FUNCTION__;
298 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); 299 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
299 TRACE_EVENT0("media", __FUNCTION__); 300 TRACE_EVENT0("media", __FUNCTION__);
300 301
301 if (needs_flush) { 302 if (needs_flush) {
302 DVLOG(1) << "DecodeInternal needs flush."; 303 DVLOG(1) << "DecodeInternal needs flush.";
303 input_eos_encountered_ = false; 304 input_eos_encountered_ = false;
304 output_eos_encountered_ = false; 305 output_eos_encountered_ = false;
305 MediaCodecStatus reset_status = media_codec_bridge_->Reset(); 306 MediaCodecStatus reset_status = media_codec_bridge_->Reset();
306 if (MEDIA_CODEC_OK != reset_status) { 307 if (MEDIA_CODEC_OK != reset_status) {
307 callback.Run(reset_status, kNoTimestamp(), kNoTimestamp()); 308 callback.Run(reset_status, kNoTimestamp(), 0);
308 return; 309 return;
309 } 310 }
310 } 311 }
311 312
312 // Once output EOS has occurred, we should not be asked to decode again. 313 // Once output EOS has occurred, we should not be asked to decode again.
313 // MediaCodec has undefined behavior if similarly asked to decode after output 314 // MediaCodec has undefined behavior if similarly asked to decode after output
314 // EOS. 315 // EOS.
315 DCHECK(!output_eos_encountered_); 316 DCHECK(!output_eos_encountered_);
316 317
317 // For aborted access unit, just skip it and inform the player. 318 // For aborted access unit, just skip it and inform the player.
318 if (unit.status == DemuxerStream::kAborted) { 319 if (unit.status == DemuxerStream::kAborted) {
319 // TODO(qinmin): use a new enum instead of MEDIA_CODEC_STOPPED. 320 // TODO(qinmin): use a new enum instead of MEDIA_CODEC_STOPPED.
320 callback.Run(MEDIA_CODEC_STOPPED, kNoTimestamp(), kNoTimestamp()); 321 callback.Run(MEDIA_CODEC_STOPPED, kNoTimestamp(), 0);
321 return; 322 return;
322 } 323 }
323 324
324 if (skip_eos_enqueue_) { 325 if (skip_eos_enqueue_) {
325 if (unit.end_of_stream || unit.data.empty()) { 326 if (unit.end_of_stream || unit.data.empty()) {
326 input_eos_encountered_ = true; 327 input_eos_encountered_ = true;
327 output_eos_encountered_ = true; 328 output_eos_encountered_ = true;
328 callback.Run(MEDIA_CODEC_OUTPUT_END_OF_STREAM, kNoTimestamp(), 329 callback.Run(MEDIA_CODEC_OUTPUT_END_OF_STREAM, kNoTimestamp(), 0);
329 kNoTimestamp());
330 return; 330 return;
331 } 331 }
332 332
333 skip_eos_enqueue_ = false; 333 skip_eos_enqueue_ = false;
334 } 334 }
335 335
336 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM; 336 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM;
337 if (!input_eos_encountered_) { 337 if (!input_eos_encountered_) {
338 input_status = QueueInputBuffer(unit); 338 input_status = QueueInputBuffer(unit);
339 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) { 339 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) {
340 input_eos_encountered_ = true; 340 input_eos_encountered_ = true;
341 } else if (input_status != MEDIA_CODEC_OK) { 341 } else if (input_status != MEDIA_CODEC_OK) {
342 callback.Run(input_status, kNoTimestamp(), kNoTimestamp()); 342 callback.Run(input_status, kNoTimestamp(), 0);
343 return; 343 return;
344 } 344 }
345 } 345 }
346 346
347 int buffer_index = 0; 347 int buffer_index = 0;
348 size_t offset = 0; 348 size_t offset = 0;
349 size_t size = 0; 349 size_t size = 0;
350 base::TimeDelta presentation_timestamp; 350 base::TimeDelta presentation_timestamp;
351 351
352 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( 352 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(
353 kMediaCodecTimeoutInMilliseconds); 353 kMediaCodecTimeoutInMilliseconds);
354 354
355 MediaCodecStatus status = 355 MediaCodecStatus status =
356 media_codec_bridge_->DequeueOutputBuffer(timeout, 356 media_codec_bridge_->DequeueOutputBuffer(timeout,
357 &buffer_index, 357 &buffer_index,
358 &offset, 358 &offset,
359 &size, 359 &size,
360 &presentation_timestamp, 360 &presentation_timestamp,
361 &output_eos_encountered_, 361 &output_eos_encountered_,
362 NULL); 362 NULL);
363 363
364 if (status != MEDIA_CODEC_OK) { 364 if (status != MEDIA_CODEC_OK) {
365 if (status == MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED && 365 if (status == MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED &&
366 !media_codec_bridge_->GetOutputBuffers()) { 366 !media_codec_bridge_->GetOutputBuffers()) {
367 status = MEDIA_CODEC_ERROR; 367 status = MEDIA_CODEC_ERROR;
368 } 368 }
369 callback.Run(status, kNoTimestamp(), kNoTimestamp()); 369 callback.Run(status, kNoTimestamp(), 0);
370 return; 370 return;
371 } 371 }
372 372
373 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up. 373 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up.
374 if (output_eos_encountered_) 374 if (output_eos_encountered_)
375 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM; 375 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM;
376 else if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) 376 else if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM)
377 status = MEDIA_CODEC_INPUT_END_OF_STREAM; 377 status = MEDIA_CODEC_INPUT_END_OF_STREAM;
378 378
379 bool render_output = presentation_timestamp >= preroll_timestamp_ && 379 bool render_output = presentation_timestamp >= preroll_timestamp_ &&
380 (status != MEDIA_CODEC_OUTPUT_END_OF_STREAM || size != 0u); 380 (status != MEDIA_CODEC_OUTPUT_END_OF_STREAM || size != 0u);
381 base::TimeDelta time_to_render; 381 base::TimeDelta time_to_render;
382 DCHECK(!start_time_ticks.is_null()); 382 DCHECK(!start_time_ticks.is_null());
383 if (render_output && ComputeTimeToRender()) { 383 if (render_output && ComputeTimeToRender()) {
384 time_to_render = presentation_timestamp - (base::TimeTicks::Now() - 384 time_to_render = presentation_timestamp - (base::TimeTicks::Now() -
385 start_time_ticks + start_presentation_timestamp); 385 start_time_ticks + start_presentation_timestamp);
386 } 386 }
387 387
388 if (time_to_render > base::TimeDelta()) { 388 if (time_to_render > base::TimeDelta()) {
389 decoder_task_runner_->PostDelayedTask( 389 decoder_task_runner_->PostDelayedTask(
390 FROM_HERE, 390 FROM_HERE,
391 base::Bind(&MediaDecoderJob::ReleaseOutputBuffer, 391 base::Bind(&MediaDecoderJob::ReleaseOutputBuffer,
392 weak_factory_.GetWeakPtr(), 392 weak_factory_.GetWeakPtr(),
393 buffer_index, 393 buffer_index,
394 size, 394 size,
395 render_output, 395 render_output,
396 presentation_timestamp, 396 base::Bind(callback, status, presentation_timestamp)),
397 base::Bind(callback, status)),
398 time_to_render); 397 time_to_render);
399 return; 398 return;
400 } 399 }
401 400
402 // TODO(qinmin): The codec is lagging behind, need to recalculate the 401 // TODO(qinmin): The codec is lagging behind, need to recalculate the
403 // |start_presentation_timestamp_| and |start_time_ticks_| in 402 // |start_presentation_timestamp_| and |start_time_ticks_| in
404 // media_source_player.cc. 403 // media_source_player.cc.
405 DVLOG(1) << "codec is lagging behind :" << time_to_render.InMicroseconds(); 404 DVLOG(1) << "codec is lagging behind :" << time_to_render.InMicroseconds();
406 if (render_output) { 405 if (render_output) {
407 // The player won't expect a timestamp smaller than the 406 // The player won't expect a timestamp smaller than the
408 // |start_presentation_timestamp|. However, this could happen due to decoder 407 // |start_presentation_timestamp|. However, this could happen due to decoder
409 // errors. 408 // errors.
410 presentation_timestamp = std::max( 409 presentation_timestamp = std::max(
411 presentation_timestamp, start_presentation_timestamp); 410 presentation_timestamp, start_presentation_timestamp);
412 } else { 411 } else {
413 presentation_timestamp = kNoTimestamp(); 412 presentation_timestamp = kNoTimestamp();
414 } 413 }
415 ReleaseOutputCompletionCallback completion_callback = base::Bind( 414 ReleaseOutputCompletionCallback completion_callback = base::Bind(
416 callback, status); 415 callback, status, presentation_timestamp);
417 ReleaseOutputBuffer(buffer_index, size, render_output, presentation_timestamp, 416 ReleaseOutputBuffer(buffer_index, size, render_output, completion_callback);
418 completion_callback);
419 } 417 }
420 418
421 void MediaDecoderJob::OnDecodeCompleted( 419 void MediaDecoderJob::OnDecodeCompleted(
422 MediaCodecStatus status, base::TimeDelta current_presentation_timestamp, 420 MediaCodecStatus status, base::TimeDelta presentation_timestamp,
423 base::TimeDelta max_presentation_timestamp) { 421 size_t audio_output_bytes) {
424 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 422 DCHECK(ui_task_runner_->BelongsToCurrentThread());
425 423
426 if (destroy_pending_) { 424 if (destroy_pending_) {
427 DVLOG(1) << __FUNCTION__ << " : completing pending deletion"; 425 DVLOG(1) << __FUNCTION__ << " : completing pending deletion";
428 delete this; 426 delete this;
429 return; 427 return;
430 } 428 }
431 429
432 DCHECK(!decode_cb_.is_null()); 430 DCHECK(!decode_cb_.is_null());
433 431
434 // If output was queued for rendering, then we have completed prerolling. 432 // If output was queued for rendering, then we have completed prerolling.
435 if (current_presentation_timestamp != kNoTimestamp()) 433 if (presentation_timestamp != kNoTimestamp())
436 prerolling_ = false; 434 prerolling_ = false;
437 435
438 switch (status) { 436 switch (status) {
439 case MEDIA_CODEC_OK: 437 case MEDIA_CODEC_OK:
440 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: 438 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
441 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: 439 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED:
442 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: 440 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
443 case MEDIA_CODEC_OUTPUT_END_OF_STREAM: 441 case MEDIA_CODEC_OUTPUT_END_OF_STREAM:
444 if (!input_eos_encountered_) 442 if (!input_eos_encountered_)
445 access_unit_index_[current_demuxer_data_index_]++; 443 access_unit_index_[current_demuxer_data_index_]++;
446 break; 444 break;
447 445
448 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: 446 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER:
449 case MEDIA_CODEC_INPUT_END_OF_STREAM: 447 case MEDIA_CODEC_INPUT_END_OF_STREAM:
450 case MEDIA_CODEC_NO_KEY: 448 case MEDIA_CODEC_NO_KEY:
451 case MEDIA_CODEC_STOPPED: 449 case MEDIA_CODEC_STOPPED:
452 case MEDIA_CODEC_ERROR: 450 case MEDIA_CODEC_ERROR:
453 // Do nothing. 451 // Do nothing.
454 break; 452 break;
455 }; 453 };
456 454
457 stop_decode_pending_ = false; 455 stop_decode_pending_ = false;
458 base::ResetAndReturn(&decode_cb_).Run( 456 base::ResetAndReturn(&decode_cb_).Run(status, presentation_timestamp,
459 status, current_presentation_timestamp, max_presentation_timestamp); 457 audio_output_bytes);
460 } 458 }
461 459
462 const AccessUnit& MediaDecoderJob::CurrentAccessUnit() const { 460 const AccessUnit& MediaDecoderJob::CurrentAccessUnit() const {
463 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 461 DCHECK(ui_task_runner_->BelongsToCurrentThread());
464 DCHECK(HasData()); 462 DCHECK(HasData());
465 int index = NoAccessUnitsRemainingInChunk(true) ? 463 int index = NoAccessUnitsRemainingInChunk(true) ?
466 inactive_demuxer_data_index() : current_demuxer_data_index_; 464 inactive_demuxer_data_index() : current_demuxer_data_index_;
467 return received_data_[index].access_units[access_unit_index_[index]]; 465 return received_data_[index].access_units[access_unit_index_[index]];
468 } 466 }
469 467
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
503 } 501 }
504 502
505 void MediaDecoderJob::InitializeReceivedData() { 503 void MediaDecoderJob::InitializeReceivedData() {
506 for (size_t i = 0; i < 2; ++i) { 504 for (size_t i = 0; i < 2; ++i) {
507 received_data_[i] = DemuxerData(); 505 received_data_[i] = DemuxerData();
508 access_unit_index_[i] = 0; 506 access_unit_index_[i] = 0;
509 } 507 }
510 } 508 }
511 509
512 } // namespace media 510 } // namespace media
OLDNEW
« no previous file with comments | « media/base/android/media_decoder_job.h ('k') | media/base/android/media_source_player.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698