|
34 | 34 | #include <media/stagefright/foundation/ADebug.h> |
35 | 35 | #include <media/stagefright/foundation/AMessage.h> |
36 | 36 | #include <media/stagefright/ACodec.h> |
| 37 | +#include <media/stagefright/MediaDefs.h> |
37 | 38 | #include <media/stagefright/MediaErrors.h> |
38 | 39 | #include <media/stagefright/MetaData.h> |
39 | 40 | #include <surfaceflinger/Surface.h> |
40 | 41 | #include <gui/ISurfaceTexture.h> |
41 | 42 |
|
| 43 | +#include "avc_utils.h" |
| 44 | + |
42 | 45 | namespace android { |
43 | 46 |
|
44 | 47 | //////////////////////////////////////////////////////////////////////////////// |
45 | 48 |
|
46 | 49 | NuPlayer::NuPlayer() |
47 | 50 | : mUIDValid(false), |
| 51 | + mVideoIsAVC(false), |
48 | 52 | mAudioEOS(false), |
49 | 53 | mVideoEOS(false), |
50 | 54 | mScanSourcesPending(false), |
51 | 55 | mScanSourcesGeneration(0), |
52 | 56 | mFlushingAudio(NONE), |
53 | 57 | mFlushingVideo(NONE), |
54 | 58 | mResetInProgress(false), |
55 | | - mResetPostponed(false) { |
| 59 | + mResetPostponed(false), |
| 60 | + mSkipRenderingAudioUntilMediaTimeUs(-1ll), |
| 61 | + mSkipRenderingVideoUntilMediaTimeUs(-1ll), |
| 62 | + mVideoLateByUs(0ll), |
| 63 | + mNumFramesTotal(0ll), |
| 64 | + mNumFramesDropped(0ll) { |
56 | 65 | } |
57 | 66 |
|
58 | 67 | NuPlayer::~NuPlayer() { |
@@ -185,10 +194,14 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { |
185 | 194 | { |
186 | 195 | LOGV("kWhatStart"); |
187 | 196 |
|
| 197 | + mVideoIsAVC = false; |
188 | 198 | mAudioEOS = false; |
189 | 199 | mVideoEOS = false; |
190 | 200 | mSkipRenderingAudioUntilMediaTimeUs = -1; |
191 | 201 | mSkipRenderingVideoUntilMediaTimeUs = -1; |
| 202 | + mVideoLateByUs = 0; |
| 203 | + mNumFramesTotal = 0; |
| 204 | + mNumFramesDropped = 0; |
192 | 205 |
|
193 | 206 | mSource->start(); |
194 | 207 |
|
@@ -269,6 +282,8 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { |
269 | 282 | } else { |
270 | 283 | CHECK(IsFlushingState(mFlushingVideo, &needShutdown)); |
271 | 284 | mFlushingVideo = FLUSHED; |
| 285 | + |
| 286 | + mVideoLateByUs = 0; |
272 | 287 | } |
273 | 288 |
|
274 | 289 | LOGV("decoder %s flush completed", audio ? "audio" : "video"); |
@@ -397,13 +412,18 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { |
397 | 412 | int64_t positionUs; |
398 | 413 | CHECK(msg->findInt64("positionUs", &positionUs)); |
399 | 414 |
|
| 415 | + CHECK(msg->findInt64("videoLateByUs", &mVideoLateByUs)); |
| 416 | + |
400 | 417 | if (mDriver != NULL) { |
401 | 418 | sp<NuPlayerDriver> driver = mDriver.promote(); |
402 | 419 | if (driver != NULL) { |
403 | 420 | driver->notifyPosition(positionUs); |
| 421 | + |
| 422 | + driver->notifyFrameStats( |
| 423 | + mNumFramesTotal, mNumFramesDropped); |
404 | 424 | } |
405 | 425 | } |
406 | | - } else { |
| 426 | + } else if (what == Renderer::kWhatFlushComplete) { |
407 | 427 | CHECK_EQ(what, (int32_t)Renderer::kWhatFlushComplete); |
408 | 428 |
|
409 | 429 | int32_t audio; |
@@ -565,6 +585,12 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) { |
565 | 585 | return -EWOULDBLOCK; |
566 | 586 | } |
567 | 587 |
|
| 588 | + if (!audio) { |
| 589 | + const char *mime; |
| 590 | + CHECK(meta->findCString(kKeyMIMEType, &mime)); |
| 591 | + mVideoIsAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime); |
| 592 | + } |
| 593 | + |
568 | 594 | sp<AMessage> notify = |
569 | 595 | new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify, |
570 | 596 | id()); |
@@ -598,53 +624,70 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) { |
598 | 624 | } |
599 | 625 |
|
600 | 626 | sp<ABuffer> accessUnit; |
601 | | - status_t err = mSource->dequeueAccessUnit(audio, &accessUnit); |
602 | 627 |
|
603 | | - if (err == -EWOULDBLOCK) { |
604 | | - return err; |
605 | | - } else if (err != OK) { |
606 | | - if (err == INFO_DISCONTINUITY) { |
607 | | - int32_t type; |
608 | | - CHECK(accessUnit->meta()->findInt32("discontinuity", &type)); |
| 628 | + bool dropAccessUnit; |
| 629 | + do { |
| 630 | + status_t err = mSource->dequeueAccessUnit(audio, &accessUnit); |
609 | 631 |
|
610 | | - bool formatChange = |
611 | | - type == ATSParser::DISCONTINUITY_FORMATCHANGE; |
| 632 | + if (err == -EWOULDBLOCK) { |
| 633 | + return err; |
| 634 | + } else if (err != OK) { |
| 635 | + if (err == INFO_DISCONTINUITY) { |
| 636 | + int32_t type; |
| 637 | + CHECK(accessUnit->meta()->findInt32("discontinuity", &type)); |
612 | 638 |
|
613 | | - LOGV("%s discontinuity (formatChange=%d)", |
614 | | - audio ? "audio" : "video", formatChange); |
| 639 | + bool formatChange = |
| 640 | + type == ATSParser::DISCONTINUITY_FORMATCHANGE; |
615 | 641 |
|
616 | | - if (audio) { |
617 | | - mSkipRenderingAudioUntilMediaTimeUs = -1; |
618 | | - } else { |
619 | | - mSkipRenderingVideoUntilMediaTimeUs = -1; |
620 | | - } |
| 642 | + LOGV("%s discontinuity (formatChange=%d)", |
| 643 | + audio ? "audio" : "video", formatChange); |
621 | 644 |
|
622 | | - sp<AMessage> extra; |
623 | | - if (accessUnit->meta()->findMessage("extra", &extra) |
624 | | - && extra != NULL) { |
625 | | - int64_t resumeAtMediaTimeUs; |
626 | | - if (extra->findInt64( |
627 | | - "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) { |
628 | | - LOGI("suppressing rendering of %s until %lld us", |
629 | | - audio ? "audio" : "video", resumeAtMediaTimeUs); |
| 645 | + if (audio) { |
| 646 | + mSkipRenderingAudioUntilMediaTimeUs = -1; |
| 647 | + } else { |
| 648 | + mSkipRenderingVideoUntilMediaTimeUs = -1; |
| 649 | + } |
630 | 650 |
|
631 | | - if (audio) { |
632 | | - mSkipRenderingAudioUntilMediaTimeUs = |
633 | | - resumeAtMediaTimeUs; |
634 | | - } else { |
635 | | - mSkipRenderingVideoUntilMediaTimeUs = |
636 | | - resumeAtMediaTimeUs; |
| 651 | + sp<AMessage> extra; |
| 652 | + if (accessUnit->meta()->findMessage("extra", &extra) |
| 653 | + && extra != NULL) { |
| 654 | + int64_t resumeAtMediaTimeUs; |
| 655 | + if (extra->findInt64( |
| 656 | + "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) { |
| 657 | + LOGI("suppressing rendering of %s until %lld us", |
| 658 | + audio ? "audio" : "video", resumeAtMediaTimeUs); |
| 659 | + |
| 660 | + if (audio) { |
| 661 | + mSkipRenderingAudioUntilMediaTimeUs = |
| 662 | + resumeAtMediaTimeUs; |
| 663 | + } else { |
| 664 | + mSkipRenderingVideoUntilMediaTimeUs = |
| 665 | + resumeAtMediaTimeUs; |
| 666 | + } |
637 | 667 | } |
638 | 668 | } |
| 669 | + |
| 670 | + flushDecoder(audio, formatChange); |
639 | 671 | } |
640 | 672 |
|
641 | | - flushDecoder(audio, formatChange); |
| 673 | + reply->setInt32("err", err); |
| 674 | + reply->post(); |
| 675 | + return OK; |
642 | 676 | } |
643 | 677 |
|
644 | | - reply->setInt32("err", err); |
645 | | - reply->post(); |
646 | | - return OK; |
647 | | - } |
| 678 | + if (!audio) { |
| 679 | + ++mNumFramesTotal; |
| 680 | + } |
| 681 | + |
| 682 | + dropAccessUnit = false; |
| 683 | + if (!audio |
| 684 | + && mVideoLateByUs > 100000ll |
| 685 | + && mVideoIsAVC |
| 686 | + && !IsAVCReferenceFrame(accessUnit)) { |
| 687 | + dropAccessUnit = true; |
| 688 | + ++mNumFramesDropped; |
| 689 | + } |
| 690 | + } while (dropAccessUnit); |
648 | 691 |
|
649 | 692 | // LOGV("returned a valid buffer of %s data", audio ? "audio" : "video"); |
650 | 693 |
|
|
0 commit comments