Skip to content

Commit 7c58255

Browse files
authored
Add support for version1 boxes. (#109)
* Add support for version1 boxes. Add parsing of co64 box * Fix chunk offsets (#110) * bump to v0.34.2
1 parent e3a7721 commit 7c58255

File tree

15 files changed

+306
-88
lines changed

15 files changed

+306
-88
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ The package can be installed by adding `membrane_mp4_plugin` to your list of dep
1212
```elixir
1313
defp deps do
1414
[
15-
{:membrane_mp4_plugin, "~> 0.34.1"}
15+
{:membrane_mp4_plugin, "~> 0.34.2"}
1616
]
1717
end
1818
```

lib/membrane_mp4/container/header.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ defmodule Membrane.MP4.Container.Header do
44
55
The `content_size` field is equal to the box size minus the size of the header (8 bytes).
66
"""
7+
use Bunch.Access
78

89
@enforce_keys [:name, :content_size, :header_size]
910

lib/membrane_mp4/container/parse_helper.ex

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,24 @@ defmodule Membrane.MP4.Container.ParseHelper do
1818

1919
def parse_boxes(data, schema, context, acc) do
2020
withl header_content:
21-
{:ok, %{name: name, content_size: content_size}, rest} <- Header.parse(data),
21+
{:ok, %{name: name, content_size: content_size, header_size: header_size}, rest} <-
22+
Header.parse(data),
2223
header_content: <<content::binary-size(content_size), data::binary>> <- rest,
2324
do: box_schema = schema[name],
2425
known?: true <- box_schema && not box_schema.black_box?,
2526
try:
2627
{:ok, {fields, rest}, context} <- parse_fields(content, box_schema.fields, context),
2728
try:
2829
{:ok, children, <<>>, context} <- parse_boxes(rest, box_schema.children, context, []) do
29-
box = %{fields: fields, children: children}
30+
box = %{fields: fields, children: children, size: content_size, header_size: header_size}
3031
parse_boxes(data, schema, context, [{name, box} | acc])
3132
else
3233
header_content: _error ->
3334
# more data needed
3435
{:ok, Enum.reverse(acc), data, context}
3536

3637
known?: _ ->
37-
box = %{content: content}
38+
box = %{content: content, size: content_size, header_size: header_size}
3839
parse_boxes(data, schema, context, [{name, box} | acc])
3940

4041
try: {:error, context} ->
@@ -62,11 +63,24 @@ defmodule Membrane.MP4.Container.ParseHelper do
6263
end
6364
end
6465

65-
defp parse_field(data, {name, {type, store: context_name, when: condition}}, context) do
66-
{flag, key} = condition
66+
defp parse_field(data, {name, {type, store: context_name, when: {key, [mask: mask]}}}, context) do
6767
context_object = Map.get(context, key, 0)
6868

69-
if (flag &&& context_object) == flag do
69+
if (mask &&& context_object) == mask do
70+
parse_field(data, {name, {type, store: context_name}}, context)
71+
else
72+
{:ok, {[], data}, context}
73+
end
74+
end
75+
76+
defp parse_field(
77+
data,
78+
{name, {type, store: context_name, when: {key, [value: value]}}},
79+
context
80+
) do
81+
context_object = Map.get(context, key, 0)
82+
83+
if context_object == value do
7084
parse_field(data, {name, {type, store: context_name}}, context)
7185
else
7286
{:ok, {[], data}, context}
@@ -80,11 +94,20 @@ defmodule Membrane.MP4.Container.ParseHelper do
8094
{:ok, result, context}
8195
end
8296

83-
defp parse_field(data, {name, {type, when: condition}}, context) do
84-
{flag, key} = condition
97+
defp parse_field(data, {name, {type, when: {key, [mask: mask]}}}, context) do
98+
context_object = Map.get(context, key, 0)
99+
100+
if (mask &&& context_object) == mask do
101+
parse_field(data, {name, type}, context)
102+
else
103+
{:ok, {[], data}, context}
104+
end
105+
end
106+
107+
defp parse_field(data, {name, {type, when: {key, [value: value]}}}, context) do
85108
context_object = Map.get(context, key, 0)
86109

87-
if (flag &&& context_object) == flag do
110+
if context_object == value do
88111
parse_field(data, {name, type}, context)
89112
else
90113
{:ok, {[], data}, context}

lib/membrane_mp4/container/schema.ex

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ defmodule Membrane.MP4.Container.Schema do
1010
"""
1111

1212
@full_box [
13-
version: :uint8,
13+
version: {:uint8, store: :version},
1414
flags: {:uint24, store: :fo_flags}
1515
]
1616

@@ -70,10 +70,13 @@ defmodule Membrane.MP4.Container.Schema do
7070
fields:
7171
@full_box ++
7272
[
73-
creation_time: :uint32,
74-
modification_time: :uint32,
73+
creation_time: {:uint32, when: {:version, value: 0}},
74+
creation_time: {:uint64, when: {:version, value: 1}},
75+
modification_time: {:uint32, when: {:version, value: 0}},
76+
modification_time: {:uint64, when: {:version, value: 1}},
7577
timescale: :uint32,
76-
duration: :uint32,
78+
duration: {:uint32, when: {:version, value: 0}},
79+
duration: {:uint64, when: {:version, value: 1}},
7780
rate: :fp16d16,
7881
volume: :fp8d8,
7982
reserved: <<0::size(80)>>,
@@ -101,11 +104,14 @@ defmodule Membrane.MP4.Container.Schema do
101104
fields:
102105
@full_box ++
103106
[
104-
creation_time: :uint32,
105-
modification_time: :uint32,
107+
creation_time: {:uint32, when: {:version, value: 0}},
108+
creation_time: {:uint64, when: {:version, value: 1}},
109+
modification_time: {:uint32, when: {:version, value: 0}},
110+
modification_time: {:uint64, when: {:version, value: 1}},
106111
track_id: :uint32,
107112
reserved: <<0::32>>,
108-
duration: :uint32,
113+
duration: {:uint32, when: {:version, value: 0}},
114+
duration: {:uint64, when: {:version, value: 1}},
109115
reserved: <<0::64>>,
110116
layer: :int16,
111117
alternate_group: :int16,
@@ -130,10 +136,13 @@ defmodule Membrane.MP4.Container.Schema do
130136
fields:
131137
@full_box ++
132138
[
133-
creation_time: :uint32,
134-
modification_time: :uint32,
139+
creation_time: {:uint32, when: {:version, value: 0}},
140+
creation_time: {:uint64, when: {:version, value: 1}},
141+
modification_time: {:uint32, when: {:version, value: 0}},
142+
modification_time: {:uint64, when: {:version, value: 1}},
135143
timescale: :uint32,
136-
duration: :uint32,
144+
duration: {:uint32, when: {:version, value: 0}},
145+
duration: {:uint64, when: {:version, value: 1}},
137146
reserved: <<0::1>>,
138147
language: :uint15,
139148
reserved: <<0::16>>
@@ -280,7 +289,7 @@ defmodule Membrane.MP4.Container.Schema do
280289
{:list,
281290
[
282291
sample_count: :uint32,
283-
sample_offset: :uint32
292+
sample_composition_offset: :uint32
284293
]}
285294
]
286295
],
@@ -325,6 +334,19 @@ defmodule Membrane.MP4.Container.Schema do
325334
chunk_offset: :uint32
326335
]}
327336
]
337+
],
338+
co64: [
339+
version: 0,
340+
fields:
341+
@full_box ++
342+
[
343+
entry_count: :uint32,
344+
entry_list:
345+
{:list,
346+
[
347+
chunk_offset: :uint64
348+
]}
349+
]
328350
]
329351
]
330352
]
@@ -426,7 +448,8 @@ defmodule Membrane.MP4.Container.Schema do
426448
sample_duration: :uint32,
427449
sample_size: :uint32,
428450
sample_flags: :bin32,
429-
sample_offset: {:uint32, when: {0x800, :fo_flags}}
451+
sample_composition_offset:
452+
{:uint32, when: {:fo_flags, mask: 0x800}}
430453
]}
431454
]
432455
]

lib/membrane_mp4/container/schema_parser.ex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ defmodule Membrane.MP4.Container.Schema.Parser do
6262
{name, type}
6363
end
6464

65-
defp parse_field({name, {type, store: context_name, when: {flag, context_name}}})
65+
defp parse_field({name, {type, store: context_name, when: {context_name, opts}}})
6666
when is_atom(name) do
6767
{name, type} = parse_field({name, type})
68-
type = {type, store: context_name, when: {flag, context_name}}
68+
type = {type, store: context_name, when: {context_name, opts}}
6969
{name, type}
7070
end
7171

@@ -75,9 +75,9 @@ defmodule Membrane.MP4.Container.Schema.Parser do
7575
{name, type}
7676
end
7777

78-
defp parse_field({name, {type, when: {flag, context_name}}}) when is_atom(name) do
78+
defp parse_field({name, {type, when: {context_name, opts}}}) when is_atom(name) do
7979
{name, type} = parse_field({name, type})
80-
type = {type, when: {flag, context_name}}
80+
type = {type, when: {context_name, opts}}
8181
{name, type}
8282
end
8383

lib/membrane_mp4/container/serialize_helper.ex

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,20 @@ defmodule Membrane.MP4.Container.SerializeHelper do
6464
end
6565
end
6666

67-
defp serialize_field(term, {type, store: context_name, when: condition}, context) do
68-
{flag, key} = condition
67+
defp serialize_field(term, {type, store: context_name, when: {key, [mask: mask]}}, context) do
6968
context_object = Map.get(context, key)
7069

71-
if context_object != nil and (flag &&& context_object) == flag do
70+
if context_object != nil and (mask &&& context_object) == mask do
71+
serialize_field(term, {type, store: context_name}, context)
72+
else
73+
{{:ok, <<>>}, context}
74+
end
75+
end
76+
77+
defp serialize_field(term, {type, store: context_name, when: {key, [value: value]}}, context) do
78+
context_object = Map.get(context, key)
79+
80+
if context_object != nil and context_object == value do
7281
serialize_field(term, {type, store: context_name}, context)
7382
else
7483
{{:ok, <<>>}, context}
@@ -80,11 +89,20 @@ defmodule Membrane.MP4.Container.SerializeHelper do
8089
serialize_field(term, type, context)
8190
end
8291

83-
defp serialize_field(term, {type, when: condition}, context) do
84-
{flag, key} = condition
92+
defp serialize_field(term, {type, when: {key, [mask: mask]}}, context) do
93+
context_object = Map.get(context, key, 0)
94+
95+
if (mask &&& context_object) == mask do
96+
serialize_field(term, type, context)
97+
else
98+
{{:ok, <<>>}, context}
99+
end
100+
end
101+
102+
defp serialize_field(term, {type, when: {key, [value: value]}}, context) do
85103
context_object = Map.get(context, key, 0)
86104

87-
if (flag &&& context_object) == flag do
105+
if context_object == value do
88106
serialize_field(term, type, context)
89107
else
90108
{{:ok, <<>>}, context}

0 commit comments

Comments
 (0)