rtp对h264 nalu fu-a的处理

1.FU-A的分片格式

数据比较大的H264视频包,被RTP分片发送。12字节的RTP头后面跟随的就是FU-A分片:

FU indicator有以下格式

+---------------+
 |0|1|2|3|4|5|6|7|
 +-+-+-+-+-+-+-+-+
 |F|NRI|  Type   |
 +---------------+
 FU指示字节的类型域 Type=28表示FU-A。。NRI域的值必须根据分片NAL单元的NRI域的值设置

F: forbidden_zero_bit 在H.264规范中规定这一位必须为0

NRI: 2个bit,取00~11似乎指示这个NALU的重要性

type:5个bit 这个NALU单元的类型

0 没有定义

1-23 NAL单元 单个NAL单元包   (即一个RTP包仅由一个完整的NALU组成,)

24 STAP-A 单一时间的组合包     (多个NALU单元组成一个RTP包)

25 STAP-B 单一时间的组合包

26 MTAP16 多个时间的组合包

27 MTAP24 多个时间的组合包

28 FU-A 分片的单元       (一个NALU单元封装成多个RTP包)

29 FU-B 分片的单元

30-31 没有定义

FU header的格式如下:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R|  Type   |
+---------------+
S: 1 bit
当设置成1,开始位指示分片NAL单元的开始。当跟随的FU荷载不是分片NAL单元荷载的开始,开始位设为0。
E: 1 bit
当设置成1, 结束位指示分片NAL单元的结束,即, 荷载的最后字节也是分片NAL单元的最后一个字节。当跟随的FU荷载不是分片NAL单元的最后分片,结束位设置为0。
R: 1 bit
保留位必须设置为0,接收者必须忽略该位。
Type: 5 bits

结合live555代码分析如下

void H264FUAFragmenter::doGetNextFrame() {
  if (fNumValidDataBytes == 1) {
    // We have no NAL unit data currently in the buffer.  Read a new one:
    fInputSource->getNextFrame(&fInputBuffer[1], fInputBufferSize - 1,
                   afterGettingFrame, this,
                   FramedSource::handleClosure, this);
  } else {
    // We have NAL unit data in the buffer.  There are three cases to consider:
    // 1. There is a new NAL unit in the buffer, and it's small enough to deliver
    //    to the RTP sink (as is).
    // 2. There is a new NAL unit in the buffer, but it's too large to deliver to
    //    the RTP sink in its entirety.  Deliver the first fragment of this data,
    //    as a FU-A packet, with one extra preceding header byte.
    // 3. There is a NAL unit in the buffer, and we've already delivered some
    //    fragment(s) of this.  Deliver the next fragment of this data,
    //    as a FU-A packet, with two extra preceding header bytes.
 
    if (fMaxSize < fMaxOutputPacketSize) { // shouldn't happen
      envir() << "H264FUAFragmenter::doGetNextFrame(): fMaxSize ("
          << fMaxSize << ") is smaller than expected\n";
    } else {
      fMaxSize = fMaxOutputPacketSize;
    }
    fLastFragmentCompletedNALUnit = True; // by default
    if (fCurDataOffset == 1) { // case 1 or 2
      if (fNumValidDataBytes - 1 <= fMaxSize) { // case 1
    memmove(fTo, &fInputBuffer[1], fNumValidDataBytes - 1);
    fFrameSize = fNumValidDataBytes - 1;
    fCurDataOffset = fNumValidDataBytes;
      } else { // case 2
    // We need to send the NAL unit data as FU-A packets.  Deliver the first
    // packet now.  Note that we add FU indicator and FU header bytes to the front
    // of the packet (reusing the existing NAL header byte for the FU header).
    fInputBuffer[0] = (fInputBuffer[1] & 0xE0) | 28; // FU indicator
    fInputBuffer[1] = 0x80 | (fInputBuffer[1] & 0x1F); // FU header (with S bit)
    memmove(fTo, fInputBuffer, fMaxSize);
    fFrameSize = fMaxSize;
    fCurDataOffset += fMaxSize - 1;
    fLastFragmentCompletedNALUnit = False;
      }
    } else { // case 3
      // We are sending this NAL unit data as FU-A packets.  We've already sent the
      // first packet (fragment).  Now, send the next fragment.  Note that we add
      // FU indicator and FU header bytes to the front.  (We reuse these bytes that
      // we already sent for the first fragment, but clear the S bit, and add the E
      // bit if this is the last fragment.)
      fInputBuffer[fCurDataOffset-2] = fInputBuffer[0]; // FU indicator
      fInputBuffer[fCurDataOffset-1] = fInputBuffer[1]&~0x80; // FU header (no S bit)
      unsigned numBytesToSend = 2 + fNumValidDataBytes - fCurDataOffset;
      if (numBytesToSend > fMaxSize) {
    // We can't send all of the remaining data this time:
    numBytesToSend = fMaxSize;
    fLastFragmentCompletedNALUnit = False;
      } else {
    // This is the last fragment:
    fInputBuffer[fCurDataOffset-1] |= 0x40; // set the E bit in the FU header
    fNumTruncatedBytes = fSaveNumTruncatedBytes;
      }
      memmove(fTo, &fInputBuffer[fCurDataOffset-2], numBytesToSend);
      fFrameSize = numBytesToSend;
      fCurDataOffset += numBytesToSend - 2;
    }
 
    if (fCurDataOffset >= fNumValidDataBytes) {
      // We're done with this data.  Reset the pointers for receiving new data:
      fNumValidDataBytes = fCurDataOffset = 1;
    }
 
    // Complete delivery to the client:
    FramedSource::afterGetting(this);
  }
}


原文:https://blog.csdn.net/occupy8/article/details/47067323 

猜你喜欢

转载自blog.csdn.net/DittyChen/article/details/87970382
今日推荐