diff --git a/lib/membrane_mp4/container/parse_helper.ex b/lib/membrane_mp4/container/parse_helper.ex index 5c32a35..5a3c264 100644 --- a/lib/membrane_mp4/container/parse_helper.ex +++ b/lib/membrane_mp4/container/parse_helper.ex @@ -63,10 +63,10 @@ defmodule Membrane.MP4.Container.ParseHelper do end defp parse_field(data, {name, {type, store: context_name, when: condition}}, context) do - {flag, key} = condition + {flag_value, key, mask} = condition context_object = Map.get(context, key, 0) - if (flag &&& context_object) == flag do + if (mask &&& context_object) == flag_value do parse_field(data, {name, {type, store: context_name}}, context) else {:ok, {[], data}, context} @@ -81,10 +81,11 @@ defmodule Membrane.MP4.Container.ParseHelper do end defp parse_field(data, {name, {type, when: condition}}, context) do - {flag, key} = condition + {flag_value, key, mask} = condition + context_object = Map.get(context, key, 0) - if (flag &&& context_object) == flag do + if (mask &&& context_object) == flag_value do parse_field(data, {name, type}, context) else {:ok, {[], data}, context} diff --git a/lib/membrane_mp4/container/schema.ex b/lib/membrane_mp4/container/schema.ex index d0483d4..1ad7e53 100644 --- a/lib/membrane_mp4/container/schema.ex +++ b/lib/membrane_mp4/container/schema.ex @@ -10,7 +10,7 @@ defmodule Membrane.MP4.Container.Schema do """ @full_box [ - version: :uint8, + version: {:uint8, store: :version}, flags: {:uint24, store: :fo_flags} ] @@ -70,10 +70,13 @@ defmodule Membrane.MP4.Container.Schema do fields: @full_box ++ [ - creation_time: :uint32, - modification_time: :uint32, + creation_time: {:uint32, when: {0, :version}}, + creation_time: {:uint64, when: {1, :version}}, + modification_time: {:uint32, when: {0, :version}}, + modification_time: {:uint64, when: {1, :version}}, timescale: :uint32, - duration: :uint32, + duration: {:uint32, when: {0, :version}}, + duration: {:uint64, when: {1, :version}}, rate: :fp16d16, volume: :fp8d8, reserved: <<0::size(80)>>, @@ -101,11 +104,14 @@ defmodule Membrane.MP4.Container.Schema do fields: @full_box ++ [ - creation_time: :uint32, - modification_time: :uint32, + creation_time: {:uint32, when: {0, :version}}, + creation_time: {:uint64, when: {1, :version}}, + modification_time: {:uint32, when: {0, :version}}, + modification_time: {:uint64, when: {1, :version}}, track_id: :uint32, reserved: <<0::32>>, - duration: :uint32, + duration: {:uint32, when: {0, :version}}, + duration: {:uint64, when: {1, :version}}, reserved: <<0::64>>, layer: :int16, alternate_group: :int16, @@ -130,10 +136,13 @@ defmodule Membrane.MP4.Container.Schema do fields: @full_box ++ [ - creation_time: :uint32, - modification_time: :uint32, + creation_time: {:uint32, when: {0, :version}}, + creation_time: {:uint64, when: {1, :version}}, + modification_time: {:uint32, when: {0, :version}}, + modification_time: {:uint64, when: {1, :version}}, timescale: :uint32, - duration: :uint32, + duration: {:uint32, when: {0, :version}}, + duration: {:uint64, when: {1, :version}}, reserved: <<0::1>>, language: :uint15, reserved: <<0::16>> @@ -325,6 +334,19 @@ defmodule Membrane.MP4.Container.Schema do chunk_offset: :uint32 ]} ] + ], + co64: [ + version: 0, + fields: + @full_box ++ + [ + entry_count: :uint32, + entry_list: + {:list, + [ + chunk_offset: :uint64 + ]} + ] ] ] ] @@ -426,7 +448,7 @@ defmodule Membrane.MP4.Container.Schema do sample_duration: :uint32, sample_size: :uint32, sample_flags: :bin32, - sample_offset: {:uint32, when: {0x800, :fo_flags}} + sample_offset: {:uint32, when: {0x800, :fo_flags, 0x800}} ]} ] ] diff --git a/lib/membrane_mp4/container/schema_parser.ex b/lib/membrane_mp4/container/schema_parser.ex index a3410af..75450e4 100644 --- a/lib/membrane_mp4/container/schema_parser.ex +++ b/lib/membrane_mp4/container/schema_parser.ex @@ -62,10 +62,18 @@ defmodule Membrane.MP4.Container.Schema.Parser do {name, type} end + defp parse_field({name, {type, store: context_name, when: {flag, context_name, mask}}}) + when is_atom(name) do + {name, type} = parse_field({name, type}) + type = {type, store: context_name, when: {flag, context_name, mask}} + {name, type} + end + defp parse_field({name, {type, store: context_name, when: {flag, context_name}}}) when is_atom(name) do {name, type} = parse_field({name, type}) - type = {type, store: context_name, when: {flag, context_name}} + default_mask = 0xFFFF_FFFF_FFFF_FFFF + type = {type, store: context_name, when: {flag, context_name, default_mask}} {name, type} end @@ -75,9 +83,16 @@ defmodule Membrane.MP4.Container.Schema.Parser do {name, type} end + defp parse_field({name, {type, when: {flag, context_name, mask}}}) when is_atom(name) do + {name, type} = parse_field({name, type}) + type = {type, when: {flag, context_name, mask}} + {name, type} + end + defp parse_field({name, {type, when: {flag, context_name}}}) when is_atom(name) do {name, type} = parse_field({name, type}) - type = {type, when: {flag, context_name}} + default_mask = 0xFFFF_FFFF_FFFF_FFFF + type = {type, when: {flag, context_name, default_mask}} {name, type} end diff --git a/lib/membrane_mp4/container/serialize_helper.ex b/lib/membrane_mp4/container/serialize_helper.ex index bd75899..d9647ac 100644 --- a/lib/membrane_mp4/container/serialize_helper.ex +++ b/lib/membrane_mp4/container/serialize_helper.ex @@ -65,10 +65,10 @@ defmodule Membrane.MP4.Container.SerializeHelper do end defp serialize_field(term, {type, store: context_name, when: condition}, context) do - {flag, key} = condition + {flag_value, key, mask} = condition context_object = Map.get(context, key) - if context_object != nil and (flag &&& context_object) == flag do + if context_object != nil and (mask &&& context_object) == flag_value do serialize_field(term, {type, store: context_name}, context) else {{:ok, <<>>}, context} @@ -81,10 +81,10 @@ defmodule Membrane.MP4.Container.SerializeHelper do end defp serialize_field(term, {type, when: condition}, context) do - {flag, key} = condition + {flag_value, key, mask} = condition context_object = Map.get(context, key, 0) - if (flag &&& context_object) == flag do + if (mask &&& context_object) == flag_value do serialize_field(term, type, context) else {{:ok, <<>>}, context} diff --git a/lib/membrane_mp4/movie_box/sample_table_box.ex b/lib/membrane_mp4/movie_box/sample_table_box.ex index 59a1af1..eea4942 100644 --- a/lib/membrane_mp4/movie_box/sample_table_box.ex +++ b/lib/membrane_mp4/movie_box/sample_table_box.ex @@ -240,7 +240,7 @@ defmodule Membrane.MP4.MovieBox.SampleTableBox do sample_description: unpack_sample_description(boxes[:stsd]), sample_count: boxes[:stsz].fields.sample_count, sample_sizes: unpack_sample_sizes(boxes[:stsz]), - chunk_offsets: unpack_chunk_offsets(boxes[:stco]), + chunk_offsets: unpack_chunk_offsets(boxes[:stco] || boxes[:co64]), decoding_deltas: boxes[:stts].fields.entry_list, composition_offsets: get_composition_offsets(boxes), samples_per_chunk: boxes[:stsc].fields.entry_list,