Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fd28aa4e authored by Kim Sungyeon's avatar Kim Sungyeon Committed by Byeongjo Park
Browse files

VT: Push incomplete packets unconditionally into decoder



[Problem] DUT is showing worse video quality then REF.
[Cause] DUT dropped most of incompleted FU packets.
        so that, decoder can not reference a part of incompleted FU pkts.
[Solution] DUT will not drop video packets even those are
           incompleted.

Bug: 183578712

Signed-off-by: default avatarKim Sungyeon <sy85.kim@samsung.com>
Change-Id: Id425a44f3384d7645fa09a4cce6b55cd8f9163d9
parent 5095374c
Loading
Loading
Loading
Loading
+40 −60
Original line number Diff line number Diff line
@@ -203,29 +203,30 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addNALUnit(
    }

    if (isFirstLineBroken) {
        if (isSecondLineBroken) {
        int64_t totalDiffTimeMs = RtpToMs(diffTimeRtp + jitterTimeRtp, clockRate);
            ALOGE("buffer too late... \t RTP diff from exp =%lld \t MS diff from stamp = %lld\t\t"
        String8 info;
        info.appendFormat("RTP diff from exp =%lld \t MS diff from stamp = %lld\t\t"
                    "Seq# %d \t ExpSeq# %d \t"
                    "JitterMs %d + (%d + %d * %.3f)",
                    (long long)diffTimeRtp, (long long)totalDiffTimeMs,
                    buffer->int32Data(), mNextExpectedSeqNo,
                    jitterTimeMs, tryJbTimeMs, dynamicJbTimeMs, JITTER_MULTIPLE);
        if (isSecondLineBroken) {
            ALOGE("%s", info.string());
            printNowTimeMs(startTimeMs, nowTimeMs, playedTimeMs);
            printRTPTime(rtpTime, playedTimeRtp, expiredTimeRtp, isExpired);

            mNextExpectedSeqNo = pickProperSeq(queue, firstRTPTime, playedTimeRtp, jitterTimeRtp);
        }  else {
            ALOGW("=== WARNING === buffer arrived after %d + %d = %d ms === WARNING === ",
                    jitterTimeMs, tryJbTimeMs, jitterTimeMs + tryJbTimeMs);
            ALOGW("%s", info.string());
        }
    }

    if (mNextExpectedSeqNoValid) {
        int32_t size = queue->size();
        mNextExpectedSeqNo = pickStartSeq(queue, firstRTPTime, playedTimeRtp, jitterTimeRtp);
        int32_t cntRemove = deleteUnitUnderSeq(queue, mNextExpectedSeqNo);

        if (cntRemove > 0) {
            int32_t size = queue->size();
            source->noticeAbandonBuffer(cntRemove);
            ALOGW("delete %d of %d buffers", cntRemove, size);
        }
@@ -445,7 +446,6 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit(
    uint32_t rtpTimeStartAt;
    CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTimeStartAt));
    uint32_t startSeqNo = buffer->int32Data();
    bool pFrame = nalType == 0x1;

    if (data[1] & 0x40) {
        // Huh? End bit also set on the first buffer.
@@ -455,8 +455,6 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit(
        complete = true;
    } else {
        List<sp<ABuffer> >::iterator it = ++queue->begin();
        int32_t connected = 1;
        bool snapped = false;
        while (it != queue->end()) {
            ALOGV("sequence length %zu", totalCount);

@@ -467,33 +465,26 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit(

            if ((uint32_t)buffer->int32Data() != expectedSeqNo) {
                ALOGD("sequence not complete, expected seqNo %u, got %u, nalType %u",
                     expectedSeqNo, (unsigned)buffer->int32Data(), nalType);
                snapped = true;

                if (!pFrame) {
                    return WRONG_SEQUENCE_NUMBER;
                }
            }

            if (!snapped) {
                connected++;
                     expectedSeqNo, (uint32_t)buffer->int32Data(), nalType);
            }

            uint32_t rtpTime;
            CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
            if (size < 2
                    || data[0] != indicator
            if (size < 2) {
                ALOGV("Ignoring malformed FU buffer.");
                it = queue->erase(it);
                continue;
            }
            if (data[0] != indicator
                    || (data[1] & 0x1f) != nalType
                    || (data[1] & 0x80)
                    || rtpTime != rtpTimeStartAt) {
                ALOGV("Ignoring malformed FU buffer.");

                // Delete the whole start of the FU.

                mNextExpectedSeqNo = expectedSeqNo + 1;
                deleteUnitUnderSeq(queue, mNextExpectedSeqNo);

                return MALFORMED_PACKET;
                // Assembler already have given enough time by jitter buffer
                ALOGD("Seems another frame. Incomplete frame [%d ~ %d) \t %d FUs",
                        startSeqNo, expectedSeqNo, (int)queue->distance(queue->begin(), it));
                expectedSeqNo = (uint32_t)buffer->int32Data();
                complete = true;
                break;
            }

            totalSize += size - 2;
@@ -502,14 +493,6 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit(
            expectedSeqNo = (uint32_t)buffer->int32Data() + 1;

            if (data[1] & 0x40) {
                if (pFrame && !recycleUnit(startSeqNo, expectedSeqNo,
                            connected, totalCount, 0.5f)) {
                    mNextExpectedSeqNo = expectedSeqNo;
                    deleteUnitUnderSeq(queue, mNextExpectedSeqNo);

                    return MALFORMED_PACKET;
                }

                // This is the last fragment.
                complete = true;
                break;
@@ -625,35 +608,32 @@ void AAVCAssembler::submitAccessUnit() {
    msg->post();
}

int32_t AAVCAssembler::pickProperSeq(const Queue *queue,
int32_t AAVCAssembler::pickStartSeq(const Queue *queue,
        uint32_t first, int64_t play, int64_t jit) {
    // pick the first sequence number has the start bit.
    sp<ABuffer> buffer = *(queue->begin());
    int32_t nextSeqNo = buffer->int32Data();
    int32_t firstSeqNo = buffer->int32Data();

    Queue::const_iterator it = queue->begin();
    while (it != queue->end()) {
        int64_t rtpTime = findRTPTime(first, *it);
        // if pkt in time exists, that should be the next pivot
    // This only works for FU-A type & non-start sequence
    unsigned nalType = buffer->data()[0] & 0x1f;
    if (nalType != 28 || buffer->data()[1] & 0x80) {
        return firstSeqNo;
    }

    for (auto it : *queue) {
        const uint8_t *data = it->data();
        int64_t rtpTime = findRTPTime(first, it);
        if (rtpTime + jit >= play) {
            nextSeqNo = (*it)->int32Data();
            break;
        }
        it++;
        if ((data[1] & 0x80)) {
            const int32_t seqNo = it->int32Data();
            ALOGE("finding [HEAD] pkt. \t Seq# (%d ~ )[%d", firstSeqNo, seqNo);
            firstSeqNo = seqNo;
            break;
        }
    return nextSeqNo;
    }

bool AAVCAssembler::recycleUnit(uint32_t start, uint32_t end, uint32_t connected,
        size_t avail, float goodRatio) {
    float total = end - start;
    float valid = connected;
    float exist = avail;
    bool isRecycle = (valid / total) >= goodRatio;

    ALOGV("checking p-frame losses.. recvBufs %f valid %f diff %f recycle? %d",
            exist, valid, total, isRecycle);

    return isRecycle;
    return firstSeqNo;
}

int32_t AAVCAssembler::deleteUnitUnderSeq(Queue *queue, uint32_t seq) {
+2 −3
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@

#include <utils/List.h>
#include <utils/RefBase.h>
#include <utils/String8.h>

namespace android {

@@ -64,9 +65,7 @@ private:

    void submitAccessUnit();

    int32_t pickProperSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
    bool recycleUnit(uint32_t start, uint32_t end, uint32_t connected,
            size_t avail, float goodRatio);
    int32_t pickStartSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
    int32_t deleteUnitUnderSeq(Queue *q, uint32_t seq);

    DISALLOW_EVIL_CONSTRUCTORS(AAVCAssembler);
+40 −59
Original line number Diff line number Diff line
@@ -213,29 +213,30 @@ ARTPAssembler::AssemblyStatus AHEVCAssembler::addNALUnit(
    }

    if (isFirstLineBroken) {
        if (isSecondLineBroken) {
        int64_t totalDiffTimeMs = RtpToMs(diffTimeRtp + jitterTimeRtp, clockRate);
            ALOGE("buffer too late... \t RTP diff from exp =%lld \t MS diff from stamp = %lld\t\t"
        String8 info;
        info.appendFormat("RTP diff from exp =%lld \t MS diff from stamp = %lld\t\t"
                    "Seq# %d \t ExpSeq# %d \t"
                    "JitterMs %d + (%d + %d * %.3f)",
                    (long long)diffTimeRtp, (long long)totalDiffTimeMs,
                    buffer->int32Data(), mNextExpectedSeqNo,
                    jitterTimeMs, tryJbTimeMs, dynamicJbTimeMs, JITTER_MULTIPLE);
        if (isSecondLineBroken) {
            ALOGE("%s", info.string());
            printNowTimeMs(startTimeMs, nowTimeMs, playedTimeMs);
            printRTPTime(rtpTime, playedTimeRtp, expiredTimeRtp, isExpired);

            mNextExpectedSeqNo = pickProperSeq(queue, firstRTPTime, playedTimeRtp, jitterTimeRtp);
        }  else {
            ALOGW("=== WARNING === buffer arrived after %d + %d = %d ms === WARNING === ",
                    jitterTimeMs, tryJbTimeMs, jitterTimeMs + tryJbTimeMs);
            ALOGW("%s", info.string());
        }
    }

    if (mNextExpectedSeqNoValid) {
        int32_t size = queue->size();
        mNextExpectedSeqNo = pickStartSeq(queue, firstRTPTime, playedTimeRtp, jitterTimeRtp);
        int32_t cntRemove = deleteUnitUnderSeq(queue, mNextExpectedSeqNo);

        if (cntRemove > 0) {
            int32_t size = queue->size();
            source->noticeAbandonBuffer(cntRemove);
            ALOGW("delete %d of %d buffers", cntRemove, size);
        }
@@ -470,7 +471,6 @@ ARTPAssembler::AssemblyStatus AHEVCAssembler::addFragmentedNALUnit(
    uint32_t rtpTimeStartAt;
    CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTimeStartAt));
    uint32_t startSeqNo = buffer->int32Data();
    bool pFrame = (nalType < 0x10);

    if (data[2] & 0x40) {
        // Huh? End bit also set on the first buffer.
@@ -480,8 +480,6 @@ ARTPAssembler::AssemblyStatus AHEVCAssembler::addFragmentedNALUnit(
        complete = true;
    } else {
        List<sp<ABuffer> >::iterator it = ++queue->begin();
        int32_t connected = 1;
        bool snapped = false;
        while (it != queue->end()) {
            ALOGV("sequence length %zu", totalCount);

@@ -492,33 +490,26 @@ ARTPAssembler::AssemblyStatus AHEVCAssembler::addFragmentedNALUnit(

            if ((uint32_t)buffer->int32Data() != expectedSeqNo) {
                ALOGV("sequence not complete, expected seqNo %u, got %u, nalType %u",
                     expectedSeqNo, (uint32_t)buffer->int32Data(), nalType);
                snapped = true;

                if (!pFrame) {
                    return WRONG_SEQUENCE_NUMBER;
                }
            }

            if (!snapped) {
                connected++;
                     expectedSeqNo, (unsigned)buffer->int32Data(), nalType);
            }

            uint32_t rtpTime;
            CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
            if (size < 3
                    || ((data[0] >> 1) & H265_NALU_MASK) != indicator
            if (size < 3) {
                ALOGV("Ignoring malformed FU buffer.");
                it = queue->erase(it);
                continue;
            }
            if (((data[0] >> 1) & H265_NALU_MASK) != indicator
                    || (data[2] & H265_NALU_MASK) != nalType
                    || (data[2] & 0x80)
                    || rtpTime != rtpTimeStartAt) {
                ALOGV("Ignoring malformed FU buffer.");

                // Delete the whole start of the FU.

                mNextExpectedSeqNo = expectedSeqNo + 1;
                deleteUnitUnderSeq(queue, mNextExpectedSeqNo);

                return MALFORMED_PACKET;
                // Assembler already have given enough time by jitter buffer
                ALOGD("Seems another frame. Incomplete frame [%d ~ %d) \t %d FUs",
                        startSeqNo, expectedSeqNo, (int)queue->distance(queue->begin(), it));
                expectedSeqNo = (uint32_t)buffer->int32Data();
                complete = true;
                break;
            }

            totalSize += size - 3;
@@ -527,13 +518,6 @@ ARTPAssembler::AssemblyStatus AHEVCAssembler::addFragmentedNALUnit(
            expectedSeqNo = (uint32_t)buffer->int32Data() + 1;

            if (data[2] & 0x40) {
                if (pFrame && !recycleUnit(startSeqNo, expectedSeqNo,
                        connected, totalCount, 0.5f)) {
                    mNextExpectedSeqNo = expectedSeqNo;
                    deleteUnitUnderSeq(queue, mNextExpectedSeqNo);

                    return MALFORMED_PACKET;
                }
                // This is the last fragment.
                complete = true;
                break;
@@ -639,35 +623,32 @@ void AHEVCAssembler::submitAccessUnit() {
    msg->post();
}

int32_t AHEVCAssembler::pickProperSeq(const Queue *queue,
int32_t AHEVCAssembler::pickStartSeq(const Queue *queue,
        uint32_t first, int64_t play, int64_t jit) {
    // pick the first sequence number has the start bit.
    sp<ABuffer> buffer = *(queue->begin());
    int32_t nextSeqNo = buffer->int32Data();
    int32_t firstSeqNo = buffer->int32Data();

    Queue::const_iterator it = queue->begin();
    while (it != queue->end()) {
        int64_t rtpTime = findRTPTime(first, *it);
        // if pkt in time exists, that should be the next pivot
    // This only works for FU-A type & non-start sequence
    unsigned nalType = buffer->data()[0] & 0x1f;
    if (nalType != 28 || buffer->data()[2] & 0x80) {
        return firstSeqNo;
    }

    for (auto it : *queue) {
        const uint8_t *data = it->data();
        int64_t rtpTime = findRTPTime(first, it);
        if (rtpTime + jit >= play) {
            nextSeqNo = (*it)->int32Data();
            break;
        }
        it++;
        if ((data[2] & 0x80)) {
            const int32_t seqNo = it->int32Data();
            ALOGE("finding [HEAD] pkt. \t Seq# (%d ~ )[%d", firstSeqNo, seqNo);
            firstSeqNo = seqNo;
            break;
        }
    return nextSeqNo;
    }

bool AHEVCAssembler::recycleUnit(uint32_t start, uint32_t end,  uint32_t connected,
         size_t avail, float goodRatio) {
    float total = end - start;
    float valid = connected;
    float exist = avail;
    bool isRecycle = (valid / total) >= goodRatio;

    ALOGV("checking p-frame losses.. recvBufs %f valid %f diff %f recycle? %d",
            exist, valid, total, isRecycle);

    return isRecycle;
    return firstSeqNo;
}

int32_t AHEVCAssembler::deleteUnitUnderSeq(Queue *queue, uint32_t seq) {
+2 −3
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@

#include <utils/List.h>
#include <utils/RefBase.h>
#include <utils/String8.h>

namespace android {

@@ -65,9 +66,7 @@ private:

    void submitAccessUnit();

    int32_t pickProperSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
    bool recycleUnit(uint32_t start, uint32_t end, uint32_t connected,
             size_t avail, float goodRatio);
    int32_t pickStartSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
    int32_t deleteUnitUnderSeq(Queue *queue, uint32_t seq);

    DISALLOW_EVIL_CONSTRUCTORS(AHEVCAssembler);