Current section
Files
Jump to
Current section
Files
lib/media_codecs/h265/nalu.ex
defmodule MediaCodecs.H265.NALU do
@moduledoc """
Struct describing an h265 nalu.
"""
alias __MODULE__.{VPS, SPS, PPS, Slice}
@type nalu_type ::
:trail_n
| :trail_r
| :tsa_n
| :tsa_r
| :stsa_n
| :stsa_r
| :radl_n
| :radl_r
| :rasl_n
| :rasl_r
| :bla_w_lp
| :bla_w_radl
| :bla_n_lp
| :idr_w_radl
| :idr_n_lp
| :cra
| :aud
| :eos
| :eob
| :fd
| :prefix_sei
| :suffix_sei
| :reserved_irap
| :reserved_nvcl
| :unspecified
@type t :: %__MODULE__{
type: nalu_type(),
nuh_layer_id: non_neg_integer(),
nuh_temporal_id_plus1: non_neg_integer(),
content: struct() | nil
}
@irap [:idr_n_lp, :idr_w_radl, :cra, :bla_n_lp, :bla_w_radl]
defstruct [:type, :nuh_layer_id, :nuh_temporal_id_plus1, :content]
@doc """
Parses the NALU header.
"""
@spec parse_header(nalu :: binary()) :: t()
def parse_header(nalu) do
{type, nuh_layer_id, nuh_temporal_id_plus1} = header(nalu)
%__MODULE__{
nuh_layer_id: nuh_layer_id,
type: nalu_type(type),
nuh_temporal_id_plus1: nuh_temporal_id_plus1
}
end
@doc """
Gets NALu type.
"""
@spec type(nalu :: binary()) :: nalu_type()
def type(nalu) do
{type, _, _} = header(nalu)
nalu_type(type)
end
@doc """
Parses a NALU bitstring and returns a NALU struct.
An optional keyword can be provided to completely parse the NAL unit:
- `:sps` - provide the parsed sps NAL unit. Needed for slice parsing.
- `:pps` - provide the parsed pps NAL unit. Needed for slice parsing.
"""
@spec parse(nalu :: binary(), keyword()) :: t()
def parse(nalu, opts \\ []) do
{int_type, nuh_layer_id, nuh_temporal_id_plus1} = header(nalu)
type = nalu_type(int_type)
parsed_nalu = %__MODULE__{
type: type,
nuh_layer_id: nuh_layer_id,
nuh_temporal_id_plus1: nuh_temporal_id_plus1
}
case type do
:vps ->
%{parsed_nalu | content: VPS.parse(nalu)}
:sps ->
%{parsed_nalu | content: SPS.parse(nalu)}
:pps ->
%{parsed_nalu | content: PPS.parse(nalu)}
_type when int_type < 32 ->
%{parsed_nalu | content: Slice.parse(nalu, opts[:sps], opts[:pps])}
_ ->
parsed_nalu
end
end
@doc """
Checks if the NALU is a keyframe (IRAP NALU).
iex> MediaCodecs.H265.NALU.keyframe?(%MediaCodecs.H265.NALU{type: :idr_n_lp})
true
iex> MediaCodecs.H265.NALU.keyframe?(%MediaCodecs.H265.NALU{type: :sps})
false
"""
@spec keyframe?(nalu :: binary() | t()) :: boolean()
def keyframe?(%__MODULE__{type: type}), do: type in @irap
def keyframe?(nalu) do
{type, _, _} = header(nalu)
type >= 16 and type <= 23
end
@doc """
Checks if the NALU is a Video Coding Layer (VCL) NALU.
"""
@spec vcl?(nalu :: binary()) :: boolean()
def vcl?(nalu) do
{type, _, _} = header(nalu)
type < 32
end
defp header(<<_::1, type::6, nuh_layer_id::6, temporal_id::3, _nal_body::binary>>) do
{type, nuh_layer_id, temporal_id}
end
defp nalu_type(0), do: :trail_n
defp nalu_type(1), do: :trail_r
defp nalu_type(2), do: :tsa_n
defp nalu_type(3), do: :tsa_r
defp nalu_type(4), do: :stsa_n
defp nalu_type(5), do: :stsa_r
defp nalu_type(6), do: :radl_n
defp nalu_type(7), do: :radl_r
defp nalu_type(8), do: :rasl_n
defp nalu_type(9), do: :rasl_r
defp nalu_type(16), do: :bla_w_lp
defp nalu_type(17), do: :bla_w_radl
defp nalu_type(18), do: :bla_n_lp
defp nalu_type(19), do: :idr_w_radl
defp nalu_type(20), do: :idr_n_lp
defp nalu_type(21), do: :cra
defp nalu_type(32), do: :vps
defp nalu_type(33), do: :sps
defp nalu_type(34), do: :pps
defp nalu_type(35), do: :aud
defp nalu_type(36), do: :eos
defp nalu_type(37), do: :eob
defp nalu_type(38), do: :fd
defp nalu_type(39), do: :prefix_sei
defp nalu_type(40), do: :suffix_sei
defp nalu_type(t) when t in 10..15 or t in 24..31, do: :reserved_non_irap
defp nalu_type(t) when t in 22..23, do: :reserved_irap
defp nalu_type(t) when t in 41..47, do: :reserved_nvcl
defp nalu_type(_type), do: :unspecified
end