-
Notifications
You must be signed in to change notification settings - Fork 2
/
decoder_configuration_record.ex
56 lines (48 loc) · 1.61 KB
/
decoder_configuration_record.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
defmodule Membrane.H264.FFmpeg.Parser.DecoderConfiguration do
@moduledoc """
Utility functions for parsing AVC Configuration Record
"""
@enforce_keys [
:sps,
:pps,
:avc_profile_indication,
:avc_level,
:profile_compatibility,
:length_size
]
defstruct @enforce_keys
@type t() :: %__MODULE__{
sps: [binary()],
pps: [binary()],
avc_profile_indication: non_neg_integer(),
profile_compatibility: non_neg_integer(),
avc_level: non_neg_integer(),
length_size: non_neg_integer()
}
@spec parse(binary()) :: {:ok, t()} | {:error, any()}
def parse(
<<1::8, avc_profile_indication::8, profile_compatibility::8, avc_level::8, 0b111111::6,
length_size::2, 0b111::3, rest::bitstring>>
) do
{sps, rest} = parse_sps(rest)
{pps, _rest} = parse_pps(rest)
%__MODULE__{
sps: sps,
pps: pps,
avc_profile_indication: avc_profile_indication,
profile_compatibility: profile_compatibility,
avc_level: avc_level,
length_size: length_size
}
|> then(&{:ok, &1})
end
def parse(_data), do: {:error, :unknown_pattern}
defp parse_sps(<<num_of_sps::5, rest::bitstring>>) do
do_parse_array(num_of_sps, rest)
end
defp parse_pps(<<num_of_pps::8, rest::bitstring>>), do: do_parse_array(num_of_pps, rest)
defp do_parse_array(amount, rest, acc \\ [])
defp do_parse_array(0, rest, acc), do: {Enum.reverse(acc), rest}
defp do_parse_array(remaining, <<size::16, data::binary-size(size), rest::bitstring>>, acc),
do: do_parse_array(remaining - 1, rest, [data | acc])
end