lib/membrane_h264_plugin/h265/nalu_parser.ex

defmodule Membrane.H265.NALuParser do
  @moduledoc """
  This module is an extension to `Membrane.H26x.NALuParser` and contains
  H265 specific functions.
  """

  use Membrane.H26x.NALuParser

  require Membrane.H265.NALuTypes

  alias Membrane.H265.NALuParser.Schemes
  alias Membrane.H265.NALuTypes
  alias Membrane.H26x.NALuParser.SchemeParser

  @impl true
  def get_nalu_header_and_body(<<nalu_header::binary-size(2), nalu_body::binary>>),
    do: {nalu_header, nalu_body}

  @impl true
  def parse_nalu_header(nalu_header, state) do
    SchemeParser.parse_with_scheme(nalu_header, Schemes.NALuHeader, state)
  end

  @impl true
  def get_nalu_type(nal_unit_type), do: NALuTypes.get_type(nal_unit_type)

  @impl true
  def parse_proper_nalu_type(nalu_body, nalu_type, state) do
    try do
      {parsed_fields, state} = do_parse_proper_nalu_type(nalu_body, nalu_type, state)
      {:ok, parsed_fields, state}
    catch
      # We throw the scheme parser state since we do need the parsed fields for
      # acess unit splitter even if the parameter sets are not present
      state ->
        {:error, state}
    end
  end

  defp do_parse_proper_nalu_type(nalu_body, nalu_type, state) do
    # delete prevention emulation 3 bytes
    nalu_body = :binary.split(nalu_body, <<0, 0, 3>>, [:global]) |> Enum.join(<<0, 0>>)

    case nalu_type do
      :vps ->
        SchemeParser.parse_with_scheme(nalu_body, Schemes.VPS, state)

      :sps ->
        SchemeParser.parse_with_scheme(nalu_body, Schemes.SPS, state)

      :pps ->
        SchemeParser.parse_with_scheme(nalu_body, Schemes.PPS, state)

      type ->
        if NALuTypes.is_vcl_nalu_type(type) do
          SchemeParser.parse_with_scheme(nalu_body, Schemes.Slice, state)
        else
          {SchemeParser.get_local_state(state), state}
        end
    end
  end
end