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

Commit 27dfa5e4 authored by Kim Sungyeon's avatar Kim Sungyeon Committed by Josh Hou
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 e61c7294
Loading
Loading
Loading
Loading
+40 −60
Original line number Original line Diff line number Diff line
@@ -203,29 +203,30 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addNALUnit(
    }
    }


    if (isFirstLineBroken) {
    if (isFirstLineBroken) {
        if (isSecondLineBroken) {
        int64_t totalDiffTimeMs = RtpToMs(diffTimeRtp + jitterTimeRtp, clockRate);
        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"
                    "Seq# %d \t ExpSeq# %d \t"
                    "JitterMs %d + (%d + %d * %.3f)",
                    "JitterMs %d + (%d + %d * %.3f)",
                    (long long)diffTimeRtp, (long long)totalDiffTimeMs,
                    (long long)diffTimeRtp, (long long)totalDiffTimeMs,
                    buffer->int32Data(), mNextExpectedSeqNo,
                    buffer->int32Data(), mNextExpectedSeqNo,
                    jitterTimeMs, tryJbTimeMs, dynamicJbTimeMs, JITTER_MULTIPLE);
                    jitterTimeMs, tryJbTimeMs, dynamicJbTimeMs, JITTER_MULTIPLE);
        if (isSecondLineBroken) {
            ALOGE("%s", info.string());
            printNowTimeMs(startTimeMs, nowTimeMs, playedTimeMs);
            printNowTimeMs(startTimeMs, nowTimeMs, playedTimeMs);
            printRTPTime(rtpTime, playedTimeRtp, expiredTimeRtp, isExpired);
            printRTPTime(rtpTime, playedTimeRtp, expiredTimeRtp, isExpired);


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


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


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


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


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


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

                if (!pFrame) {
                    return WRONG_SEQUENCE_NUMBER;
                }
            }

            if (!snapped) {
                connected++;
            }
            }


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

                ALOGD("Seems another frame. Incomplete frame [%d ~ %d) \t %d FUs",
                // Delete the whole start of the FU.
                        startSeqNo, expectedSeqNo, (int)queue->distance(queue->begin(), it));

                expectedSeqNo = (uint32_t)buffer->int32Data();
                mNextExpectedSeqNo = expectedSeqNo + 1;
                complete = true;
                deleteUnitUnderSeq(queue, mNextExpectedSeqNo);
                break;

                return MALFORMED_PACKET;
            }
            }


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


            if (data[1] & 0x40) {
            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.
                // This is the last fragment.
                complete = true;
                complete = true;
                break;
                break;
@@ -625,35 +608,32 @@ void AAVCAssembler::submitAccessUnit() {
    msg->post();
    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) {
        uint32_t first, int64_t play, int64_t jit) {
    // pick the first sequence number has the start bit.
    sp<ABuffer> buffer = *(queue->begin());
    sp<ABuffer> buffer = *(queue->begin());
    int32_t nextSeqNo = buffer->int32Data();
    int32_t firstSeqNo = buffer->int32Data();


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

    for (auto it : *queue) {
        const uint8_t *data = it->data();
        int64_t rtpTime = findRTPTime(first, it);
        if (rtpTime + jit >= play) {
        if (rtpTime + jit >= play) {
            nextSeqNo = (*it)->int32Data();
            break;
            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;
    }
    }

    return firstSeqNo;
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;
}
}


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


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


namespace android {
namespace android {


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


    void submitAccessUnit();
    void submitAccessUnit();


    int32_t pickProperSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
    int32_t pickStartSeq(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 deleteUnitUnderSeq(Queue *q, uint32_t seq);
    int32_t deleteUnitUnderSeq(Queue *q, uint32_t seq);


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


    if (isFirstLineBroken) {
    if (isFirstLineBroken) {
        if (isSecondLineBroken) {
        int64_t totalDiffTimeMs = RtpToMs(diffTimeRtp + jitterTimeRtp, clockRate);
        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"
                    "Seq# %d \t ExpSeq# %d \t"
                    "JitterMs %d + (%d + %d * %.3f)",
                    "JitterMs %d + (%d + %d * %.3f)",
                    (long long)diffTimeRtp, (long long)totalDiffTimeMs,
                    (long long)diffTimeRtp, (long long)totalDiffTimeMs,
                    buffer->int32Data(), mNextExpectedSeqNo,
                    buffer->int32Data(), mNextExpectedSeqNo,
                    jitterTimeMs, tryJbTimeMs, dynamicJbTimeMs, JITTER_MULTIPLE);
                    jitterTimeMs, tryJbTimeMs, dynamicJbTimeMs, JITTER_MULTIPLE);
        if (isSecondLineBroken) {
            ALOGE("%s", info.string());
            printNowTimeMs(startTimeMs, nowTimeMs, playedTimeMs);
            printNowTimeMs(startTimeMs, nowTimeMs, playedTimeMs);
            printRTPTime(rtpTime, playedTimeRtp, expiredTimeRtp, isExpired);
            printRTPTime(rtpTime, playedTimeRtp, expiredTimeRtp, isExpired);


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


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


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


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


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


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

                if (!pFrame) {
                    return WRONG_SEQUENCE_NUMBER;
                }
            }

            if (!snapped) {
                connected++;
            }
            }


            uint32_t rtpTime;
            uint32_t rtpTime;
            CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
            CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
            if (size < 3
            if (size < 3) {
                    || ((data[0] >> 1) & H265_NALU_MASK) != indicator
                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] & H265_NALU_MASK) != nalType
                    || (data[2] & 0x80)
                    || (data[2] & 0x80)
                    || rtpTime != rtpTimeStartAt) {
                    || rtpTime != rtpTimeStartAt) {
                ALOGV("Ignoring malformed FU buffer.");
                // Assembler already have given enough time by jitter buffer

                ALOGD("Seems another frame. Incomplete frame [%d ~ %d) \t %d FUs",
                // Delete the whole start of the FU.
                        startSeqNo, expectedSeqNo, (int)queue->distance(queue->begin(), it));

                expectedSeqNo = (uint32_t)buffer->int32Data();
                mNextExpectedSeqNo = expectedSeqNo + 1;
                complete = true;
                deleteUnitUnderSeq(queue, mNextExpectedSeqNo);
                break;

                return MALFORMED_PACKET;
            }
            }


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


            if (data[2] & 0x40) {
            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.
                // This is the last fragment.
                complete = true;
                complete = true;
                break;
                break;
@@ -639,35 +623,32 @@ void AHEVCAssembler::submitAccessUnit() {
    msg->post();
    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) {
        uint32_t first, int64_t play, int64_t jit) {
    // pick the first sequence number has the start bit.
    sp<ABuffer> buffer = *(queue->begin());
    sp<ABuffer> buffer = *(queue->begin());
    int32_t nextSeqNo = buffer->int32Data();
    int32_t firstSeqNo = buffer->int32Data();


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

    for (auto it : *queue) {
        const uint8_t *data = it->data();
        int64_t rtpTime = findRTPTime(first, it);
        if (rtpTime + jit >= play) {
        if (rtpTime + jit >= play) {
            nextSeqNo = (*it)->int32Data();
            break;
            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;
    }
    }

    return firstSeqNo;
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;
}
}


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


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


namespace android {
namespace android {


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


    void submitAccessUnit();
    void submitAccessUnit();


    int32_t pickProperSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
    int32_t pickStartSeq(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 deleteUnitUnderSeq(Queue *queue, uint32_t seq);
    int32_t deleteUnitUnderSeq(Queue *queue, uint32_t seq);


    DISALLOW_EVIL_CONSTRUCTORS(AHEVCAssembler);
    DISALLOW_EVIL_CONSTRUCTORS(AHEVCAssembler);