Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

H265NalUnitFragment: Mask nuhTempIdPlus1 correctly #1073

Merged

Conversation

edmonds
Copy link
Contributor

@edmonds edmonds commented Dec 18, 2023

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:

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.

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.
Copy link
Owner

@paullouisageneau paullouisageneau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, thank you for the fix!

@paullouisageneau paullouisageneau merged commit 5b1fbd7 into paullouisageneau:master Dec 21, 2023
11 checks passed
@edmonds edmonds deleted the h265nalu-tid-mask-fix branch December 21, 2023 15:35
paullouisageneau added a commit that referenced this pull request Jan 7, 2024
H265NalUnitFragment: Mask `nuhTempIdPlus1` correctly
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants