defmodule Membrane.RTP.H265.FU.Header do
@moduledoc """
Defines a structure representing Fragmentation Unit (FU) header
which is defined in [RFC7798](https://tools.ietf.org/html/rfc7798#page-30)
```
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E| FuType |
+---------------+
```
"""
alias Membrane.RTP.H265.NAL
@typedoc """
MUST be set to true only in the first packet in a sequence.
"""
@type start_flag :: boolean()
@typedoc """
MUST be set to true only in the last packet in a sequence.
"""
@type end_flag :: boolean()
@enforce_keys [:type]
defstruct start_bit: false, end_bit: false, type: 0
@type t :: %__MODULE__{
start_bit: start_flag(),
end_bit: end_flag(),
type: NAL.Header.type()
}
defguardp valid_frame_boundary(start, finish) when start != 1 or finish != 1
@doc """
Parses Fragmentation Unit Header
It will fail if the Start bit and End bit are both set to one in the
same Fragmentation Unit Header, because a fragmented NAL unit
MUST NOT be transmitted in one FU.
"""
@spec parse(data :: binary()) :: {:error, :packet_malformed} | {:ok, {t(), nal :: binary()}}
def parse(<<start::1, finish::1, nal_type::6, rest::binary>>)
when nal_type in 0..63 and valid_frame_boundary(start, finish) do
header = %__MODULE__{
start_bit: start == 1,
end_bit: finish == 1,
type: nal_type
}
{:ok, {header, rest}}
end
def parse(_binary), do: {:error, :packet_malformed}
@doc """
Adds FU header
"""
@spec add_header(binary(), 0 | 1, 0 | 1, NAL.Header.type()) :: binary()
def add_header(payload, start_bit, end_bit, type),
do: <<start_bit::1, end_bit::1, type::6>> <> payload
end