分片的NAL单元(FU-A分片)

  下面贴出安卓N版本AAVCAssembler::addFragmentedNALUnit原文
  

ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit(
        List<sp<ABuffer> > *queue) {
    CHECK(!queue->empty());

    //queue里存放的第一个buffer表示的是NAL单元第一个分片,后续的buffer是NAL单元后续的分片
    sp<ABuffer> buffer = *queue->begin();
    const uint8_t *data = buffer->data();
    size_t size = buffer->size();

    CHECK(size > 0);
    //data[0]指示这个buffer是NAL单元分片,由indicator & 0x1f,也即由
    //indicator & 00011111计算得到的值,该值必为28
    //data[0]也即第一个字节称为FU indicator
    unsigned indicator = data[0];
    CHECK((indicator & 0x1f) == 28);

    if (size < 2) {
        //一个NAL单元分片最小的长度是2个字节,第一个字节data[0]是FU indicator
        //第二个字节data[1]是FU header
        //如果小于最小的长度2(以字节为单位),则将分片单元从queue里删除,并将处理的序列号自增1
        //即将mNextExpectedSeqNo的值自增1
        ALOGV("Ignoring malformed FU buffer (size = %zu)", size);

        queue->erase(queue->begin());
        ++mNextExpectedSeqNo;
        return MALFORMED_PACKET;
    }

    //data[1]是FU header,结构如下:
    //S: 1 bit 当设置成1,开始位指示分片NAL单元的开始。当跟随的FU荷载不是分片NAL单元荷载的开始,开始位设为0。
    //E: 1 bit 当设置成1, 结束位指示分片NAL单元的结束,即, 荷载的最后字节也是分片NAL单元的最后一个字节。当跟随的FU荷载不是分片NAL单元的最后分片,结束位设置为0。
    //R: 1 bit 保留位必须设置为0,接收者必须忽略该位。
    //Type: 5 bits NAL单元在RTP包的荷载类型 

    if (!(data[1] & 0x80)) {
        //计算开始位:
        //data[1] & 0x80 即 data[1] & 1000 0000
        //queue里的第一个buffer必须是NAL分片单元的开始,否则进行错误处理
        //错误处理的流程是将该buffer表示的NAL分片单元从queue里删除,然后将处理的序列号mNextExpectedSeqNo自增1,返回错误码MALFORMED_PACKET
        // Start bit not set on the first buffer.

        ALOGV("Start bit not set on first buffer");

        queue->erase(queue->begin());
        ++mNextExpectedSeqNo;
        return MALFORMED_PACKET;
    }

    //代码执行到这里说明跳过了前面的if语句块,也就是该buffer表示的NAL分片单元是对单个NAL单元进行分片后的第一个分片
    //即data[1] & 0x80 的值为1
    //然后计算该分片单元所属的单个NAL单元在RTP包的荷载类型nalType = data[1] & 0x1f 也即 nalType = data[1] & 0001 1111
    uint32_t nalType = data[1] & 0x1f;
    uint32_t nri = (data[0] >> 5) & 3;

    //计算下一个需要被处理的序列号expectedSeqNo,为后续的循环处理将这些分片单元组成一个完整的NAL单元做好准备,因为在前面已经判定了queue里的第一个buffer表示的分片是NAL单元分片的开始
    //计算得到要被处理的分片单元的范围totalSize,也即去掉了该buffer的前两个字节,分别是FU indicator和FU header
    //totalCount表示当前处理得到的分片数,目前已经得到了分片的开始,所以totalCount初始值为1,每当处理一个分片,该值自增1
    //布尔变量complete表示将所有的分片组合成一个完整的NAL单元是否完成,完成的标志是最后一个分片被处理,这个时候布尔变量complete设置为true,初始值设置为false
    uint32_t expectedSeqNo = (uint32_t)buffer->int32Data() + 1;
    size_t totalSize = size - 2;
    size_t totalCount = 1;
    bool complete = false;

    //从当前该buffer第二字节data[1]也即FU header里计算得到结束位标志
    //data[1] & 0x40 即 data[1] & 0100 0000
    if (data[1] & 0x40) {
        //目前正在处理的buffer已经成功判定开始位为1了,现在结束位也为1
        //即是开始也是结束,说明并没有进行分片,这就是一个完整的NAL单元,将布尔变量complete设置位true
        // Huh? End bit also set on the first buffer.

        ALOGV("Grrr. This isn't fragmented at all.");

        complete = true;
    } else {
        //进入到else分支说明不止有一个分片
        //下面循环处理queue里所有可能的和开始分片属于同一个NAL单元的分片

        //将迭代器it指向queue里第二个buffer,第一个buffer在前面的代码已经被处理过了
        List<sp<ABuffer> >::iterator it = ++queue->begin();
        while (it != queue->end()) {
            //开始循环处理queue里所有的buffer
            ALOGV("sequence length %zu", totalCount);

            //得到当前处理queue里一个buffer的引用
            const sp<ABuffer> &buffer = *it;

            //得到该buffer的数据开始位的指针和数据的大小(以字节位单位)
            const uint8_t *data = buffer->data();
            size_t size = buffer->size();

            //当前buufer的序列号由buffer->int32Data()计算得到
            //该值必须等于当前需要被处理的序列号expectedSeqNo,否则返回错误码WRONG_SEQUENCE_NUMBER
            if ((uint32_t)buffer->int32Data() != expectedSeqNo) {
                ALOGV("sequence not complete, expected seqNo %d, got %d",
                     expectedSeqNo, (uint32_t)buffer->int32Data());

                return WRONG_SEQUENCE_NUMBER;
            }

            if (size < 2
                    || data[0] != indicator
                    || (data[1] & 0x1f) != nalType
                    || (data[1] & 0x80)) {
                ALOGV("Ignoring malformed FU buffer.");

                //同第一个buffer表示的分片单元一样,data[0]是FU indicator,data[1]是FU header 
                //所有的同属一个NAL单元的分片的FU indicator必须相同
                //所有的同属一个NAL单元的分片的在RTP包的荷载类型也必须形同,由data[1] & 0x1f计算得到
                //除了开始分片的开始位(由data[1] & 0x80计算得到)可以设置为1外,其他任何分片的开始位都不能设置为1
                //如果上述条件任何一个条件不满足则整个queue里的buffer全部删除,然后将需要被处理的下一个序列号的值mNextExpectedSeqNo设置为当前处理的序列号expectedSeqNo加1,并返回错误码MALFORMED_PACKET  
                // Delete the whole start of the FU.

                it = queue->begin();
                for (size_t i = 0; i <= totalCount; ++i) {
                    it = queue->erase(it);
                }

                mNextExpectedSeqNo = expectedSeqNo + 1;

                return MALFORMED_PACKET;
            }

            //将当前分片大小(去掉前两个字节FU indicator和FU header)加到totalSize里
            //将totalCount的值自增1,表示又处理了一个分片
            //将需要处理的下一个序列号expectedSeqNo自增1
            totalSize += size - 2;
            ++totalCount;
            expectedSeqNo = expectedSeqNo + 1;

            if (data[1] & 0x40) {
                //判断该分片的结束位data[1] & 0x40 即 data[1] & 0100 0000
                //如果结束位被设置为1,说明是最后一个分片了。将结束标志complete设置为true,并用break跳出循环,不再处理queue里后续的buffer
                // This is the last fragment.
                complete = true;
                break;
            }

            //迭代it指针,处理queue里下一个buffer
            ++it;
        }
    }

    if (!complete) {
        //循环处理完queue里buffer后,结束标志complete如果仍为false,说明没有找到结束分片,返回错误码NOT_ENOUGH_DATA
        return NOT_ENOUGH_DATA;
    }

    //代码执行到这里说明结束标识complete的值为true,整个收集所有同属一个NAL单元的工作已经完成
    //将expectedSeqNo表示的需要处理的下一个序列号的值赋值给mNextExpectedSeqNo
    mNextExpectedSeqNo = expectedSeqNo;

    // We found all the fragments that make up the complete NAL unit.

    // Leave room for the header. So far totalSize did not include the
    // header byte.
    //下面需要将这些分片组合成一个完整的NAL单元,将totalSize加1,为header留一个字节
    ++totalSize;

    //创建一个buffer来容纳这些同属一个NAL单元的分片,并将时间戳等信息添加到该buffer里
    sp<ABuffer> unit = new ABuffer(totalSize);
    CopyTimes(unit, *queue->begin());

    //为该NAL单元构造头部,采用了以下技巧,
    unit->data()[0] = (nri << 5) | nalType;

    size_t offset = 1;
    List<sp<ABuffer> >::iterator it = queue->begin();
    for (size_t i = 0; i < totalCount; ++i) {
        //将queue里totalCount个同属一个NAL单元的分片的数据部分拷贝到unit所指向的buffer里
        const sp<ABuffer> &buffer = *it;

        ALOGV("piece #%zu/%zu", i + 1, totalCount);
#if !LOG_NDEBUG
        hexdump(buffer->data(), buffer->size());
#endif

        memcpy(unit->data() + offset, buffer->data() + 2, buffer->size() - 2);
        offset += buffer->size() - 2;

        it = queue->erase(it);
    }

    //设置unit指向的buffer的数据范围
    unit->setRange(0, totalSize);

    //调用addSingleNALUnit对该单个NAL单元进行处理
    addSingleNALUnit(unit);

    ALOGV("successfully assembled a NAL unit from fragments.");

    return OK;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值