Browse Source

H265NalUnitFragment: Mask `nuhTempIdPlus1` correctly

Previously, `H265NalUnitFragment::fragmentsFrom()` was masking the value
of nuhTempIdPlus1 against the value 0xE (0b1110) which was corrupting
the generated NALU fragments. This commit updates the `fragmentsFrom()`
method to mask against the value 0x7 (0b111) instead. However, it looks
like the masking in this method is redundant with the equivalent masking
that is done by `H265NalUnitHeader`'s setters.

According to [RFC 7798](https://datatracker.ietf.org/doc/html/rfc7798#section-1.1.4):

    1.1.4.  NAL Unit Header

       HEVC maintains the NAL unit concept of H.264 with modifications.
       HEVC uses a two-byte NAL unit header, as shown in Figure 1.  The
       payload of a NAL unit refers to the NAL unit excluding the NAL unit
       header.

                +---------------+---------------+
                |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                |F|   Type    |  LayerId  | TID |
                +-------------+-----------------+

       Figure 1: The Structure of the HEVC NAL Unit Header

    [...]

       TID: 3 bits
          nuh_temporal_id_plus1.  This field specifies the temporal
          identifier of the NAL unit plus 1.  The value of TemporalId is
          equal to TID minus 1.  A TID value of 0 is illegal to ensure that
          there is at least one bit in the NAL unit header equal to 1, so to
          enable independent considerations of start code emulations in the
          NAL unit header and in the NAL unit payload data.

The minimum value of the "TID" field is 1, because it will have 1
subtracted from it to recover the original HEVC "TemporalId" value.

Without this commit, the RTP fragments being generated by
libdatachannel's `H265RtpPacketizer` were being rejected by this
consistency check in libavformat:

https://github.com/FFmpeg/FFmpeg/blob/release/6.1/libavformat/rtpdec_hevc.c#L219-L223

With this commit, I can successfully relay HEVC video from ffmpeg
through a libdatachannel program (based on the media-sender and
media-receiver examples) and play it with ffplay.
Robert Edmonds 1 year ago
parent
commit
93a3fb987a
1 changed files with 1 additions and 1 deletions
  1. 1 1
      src/h265nalunit.cpp

+ 1 - 1
src/h265nalunit.cpp

@@ -38,7 +38,7 @@ H265NalUnitFragment::fragmentsFrom(shared_ptr<H265NalUnit> nalu, uint16_t maximu
 	maximumFragmentSize -= (H265_NAL_HEADER_SIZE + H265_FU_HEADER_SIZE);
 	maximumFragmentSize -= (H265_NAL_HEADER_SIZE + H265_FU_HEADER_SIZE);
 	auto f = nalu->forbiddenBit();
 	auto f = nalu->forbiddenBit();
 	uint8_t nuhLayerId = nalu->nuhLayerId() & 0x3F;        // 6 bits
 	uint8_t nuhLayerId = nalu->nuhLayerId() & 0x3F;        // 6 bits
-	uint8_t nuhTempIdPlus1 = nalu->nuhTempIdPlus1() & 0xE; // 3 bits
+	uint8_t nuhTempIdPlus1 = nalu->nuhTempIdPlus1() & 0x7; // 3 bits
 	uint8_t naluType = nalu->unitType() & 0x3F;            // 6 bits
 	uint8_t naluType = nalu->unitType() & 0x3F;            // 6 bits
 	auto payload = nalu->payload();
 	auto payload = nalu->payload();
 	vector<shared_ptr<H265NalUnitFragment>> result{};
 	vector<shared_ptr<H265NalUnitFragment>> result{};