分片的NAL单元(FU-A分片)
2017-03-07 11:57
459 查看
下面贴出安卓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 4000 //即是开始也是结束,说明并没有进行分片,这就是一个完整的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; }
相关文章推荐
- H265(HEVC) nal 单元头介绍及rtp发送中的fu分组发送详解
- H265(HEVC) nal 单元头介绍及rtp发送中的fu分组发送详解
- H265(HEVC) nal 单元头介绍及rtp发送中的fu分组发送详解
- H265(HEVC) nal 单元头介绍及rtp发送中的fu分组发送详解
- H265(HEVC) nal 单元头介绍及rtp发送中的fu分组发送详解
- H265(HEVC) nal 单元头介绍及rtp发送中的fu分组发送详解
- H265(HEVC) nal 单元头介绍及rtp发送中的fu分组发送详解
- H265(HEVC) nal 单元头介绍及rtp发送中的fu分组发送详解
- H.264中的NAL单元类型 nal_unit_type
- 从 H264 码流中解析出 nal 单元
- 单个NAL单元的处理
- H.264 NAL 单元分段和重组
- 关于I帧,P帧,B帧和NAL单元的联系。还有slice片和NAL与各帧之间的关系
- H.264中的NAL单元类型 nal_unit_type
- H.264中的NAL单元类型 nal_unit_type
- NALU(NAL单元)
- H.264的NAL单元及码流结构
- H.264中的NAL单元类型 nal_unit_type
- NAL单元的各种类型介绍
- H.264中的NAL单元类型 nal_unit_type