Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions lib/ex_mp4/box/moov.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,21 @@ defmodule ExMP4.Box.Moov do

import ExMP4.Box.Utils, only: [parse_header: 1]

alias ExMP4.Box.{Mvex, Mvhd, Trak}
alias ExMP4.Box.{Mvex, Mvhd, Trak, UUID}

@type t :: %__MODULE__{
mvhd: Mvhd.t(),
trak: [Trak.t()],
mvex: Mvex.t() | nil
mvex: Mvex.t() | nil,
uuid: [UUID.t()]
}

defstruct mvhd: %Mvhd{}, trak: [], mvex: nil
defstruct mvhd: %Mvhd{}, trak: [], mvex: nil, uuid: []

defimpl ExMP4.Box do
def size(box) do
ExMP4.header_size() + ExMP4.Box.size(box.mvhd) + ExMP4.Box.size(box.trak) +
ExMP4.Box.size(box.mvex)
ExMP4.Box.size(box.mvex) + ExMP4.Box.size(box.uuid)
end

def parse(box, data), do: do_parse(box, data)
Expand All @@ -28,7 +29,8 @@ defmodule ExMP4.Box.Moov do
<<size(box)::32, "moov">>,
ExMP4.Box.serialize(box.mvhd),
ExMP4.Box.serialize(box.trak),
ExMP4.Box.serialize(box.mvex)
ExMP4.Box.serialize(box.mvex),
ExMP4.Box.serialize(box.uuid)
]
end

Expand All @@ -49,6 +51,10 @@ defmodule ExMP4.Box.Moov do
box = %{box | mvex: ExMP4.Box.parse(%Mvex{}, box_data)}
{box, rest}

{"uuid", box_data, rest} ->
box = %{box | uuid: box.uuid ++ [ExMP4.Box.parse(%UUID{}, box_data)]}
{box, rest}

{_box_name, _box_data, rest} ->
# box = %{box | mdia: ExMP4.Box.parse(%Mdia{}, box_data)}
{box, rest}
Expand Down
2 changes: 1 addition & 1 deletion lib/ex_mp4/box/trun.ex
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ defmodule ExMP4.Box.Trun do
{first_sample_flags, rest} = parse_entry(flags &&& 0x4, rest)

{entries, <<>>} =
Enum.reduce(1..sample_count, {[], rest}, fn _idx, {entries, data} ->
Enum.reduce(1..sample_count//1, {[], rest}, fn _idx, {entries, data} ->
{sample_duration, rest} = parse_entry(flags &&& 0x100, data)
{sample_size, rest} = parse_entry(flags &&& 0x200, rest)
{sample_flags, rest} = parse_entry(flags &&& 0x400, rest)
Expand Down
24 changes: 22 additions & 2 deletions lib/ex_mp4/box/uuid.ex
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
defmodule ExMP4.Box.UUID do
@moduledoc """
Module describing a UUID box.

A `uuid` box is a user extension box, the following fields are available:
* `type` - The 16 bytes extended type (`usertype`) identifying the box.
* `data` - The raw payload of the box.
"""

@type t :: %__MODULE__{
type: binary(),
type: <<_::128>>,
data: binary()
}

defstruct [:type, :data]
defstruct type: nil, data: <<>>

@doc """
Create a new UUID box.

`type` must be a 16 bytes binary.
"""
@spec new(<<_::128>>, binary()) :: t()
def new(type, data \\ <<>>)

def new(<<_::binary-size(16)>> = type, data) when is_binary(data) do
%__MODULE__{type: type, data: data}
end

def new(type, _data) do
raise ArgumentError, "uuid type must be a 16 bytes binary, got: #{inspect(type)}"
end

defimpl ExMP4.Box do
def size(box) do
Expand Down
10 changes: 7 additions & 3 deletions lib/ex_mp4/fwriter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ defmodule ExMP4.FWriter do
creation_time: DateTime.t(),
modification_time: DateTime.t(),
duration: integer() | boolean(),
moof_base_offset: boolean()
moof_base_offset: boolean(),
uuid: [Box.UUID.t()]
]

@type writer_options :: any()
Expand Down Expand Up @@ -67,6 +68,7 @@ defmodule ExMP4.FWriter do
If an integer, it's the total duration in the `movie` timescale and it'll be set in the `mehd` box.
* `moof_base_offset` - if `true`, it indicates that the `base‐data‐offset` for the track fragments
is the position of the first byte of the enclosing Movie Fragment Box. Defaults to: `false`.
* `uuid` - A list of `ExMP4.Box.UUID` boxes to include in the `moov` box. Defaults to: `[]`.

The last argument is an optional module implementing `ExMP4.FragDataWriter`.
"""
Expand Down Expand Up @@ -260,7 +262,8 @@ defmodule ExMP4.FWriter do
modification_time: utc_date,
duration: false,
moof_base_offset: false,
sidx: false
sidx: false,
uuid: []
)
end

Expand Down Expand Up @@ -289,7 +292,8 @@ defmodule ExMP4.FWriter do
mvex: %Box.Mvex{
mehd: mehd_box,
trex: Enum.map(tracks, & &1.trex)
}
},
uuid: opts[:uuid]
}

writer_state = writer.writer_mod.write_init_header(writer.writer_state, [ftyp_box, movie_box])
Expand Down
6 changes: 5 additions & 1 deletion lib/ex_mp4/reader.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ defmodule ExMP4.Reader do
* `major_brand`
* `minor_version`
* `compatible_brands`
* `uuid` - List of `uuid` boxes (`ExMP4.Box.UUID`) found in the `moov` box.


## Examples
Expand Down Expand Up @@ -73,6 +74,7 @@ defmodule ExMP4.Reader do
progressive?: boolean(),
creation_time: DateTime.t(),
modification_time: DateTime.t(),
uuid: [Box.UUID.t()],

# private fields
reader_mod: module(),
Expand All @@ -94,6 +96,7 @@ defmodule ExMP4.Reader do
:reader_mod,
:reader_state,
:tracks,
uuid: [],
location: 0
]

Expand Down Expand Up @@ -280,7 +283,8 @@ defmodule ExMP4.Reader do
modification_time: moov.mvhd.modification_time,
fragmented?: not is_nil(moov.mvex),
progressive?: is_nil(reader.progressive?),
tracks: tracks
tracks: tracks,
uuid: moov.uuid
}
end

Expand Down
14 changes: 11 additions & 3 deletions lib/ex_mp4/writer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -186,16 +186,23 @@ defmodule ExMP4.Writer do

@doc """
Write the trailer and close the stream.

The following options can be provided:
* `creation_time` - Set the creation time. Defaults to: now.
* `modification_time` - Set the modification time. Defaults to: now.
* `uuid` - A list of `ExMP4.Box.UUID` boxes to include in the `moov` box. Defaults to: `[]`.
"""
@spec write_trailer(t()) :: :ok
def write_trailer(%{fast_start: fast_start} = writer, opts \\ []) do
[
creation_time: creation_time,
modification_time: modification_time
modification_time: modification_time,
uuid: uuid
] =
Keyword.validate!(opts,
creation_time: DateTime.utc_now(:second),
modification_time: DateTime.utc_now(:second)
modification_time: DateTime.utc_now(:second),
uuid: []
)
|> Enum.sort()

Expand All @@ -218,7 +225,8 @@ defmodule ExMP4.Writer do
creation_time: creation_time,
modification_time: modification_time
},
trak: trak
trak: trak,
uuid: uuid
}

after_ftyp = {:bof, writer.ftyp_size}
Expand Down
22 changes: 11 additions & 11 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
%{
"benchee": {:hex, :benchee, "1.5.0", "4d812c31d54b0ec0167e91278e7de3f596324a78a096fd3d0bea68bb0c513b10", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.1", [hex: :statistex, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "5b075393aea81b8ae74eadd1c28b1d87e8a63696c649d8293db7c4df3eb67535"},
"benchee": {:hex, :benchee, "1.5.1", "b95cbc36c4b98969a5c592a246e171041eb683c56bad1cb4f49a3b081ba66087", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.1", [hex: :statistex, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a539301f8dfd4efc5c5123bfb9d47ebde20092a863a5b5b16c2a60d2243dfce7"},
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
"credo": {:hex, :credo, "1.7.13", "126a0697df6b7b71cd18c81bc92335297839a806b6f62b61d417500d1070ff4e", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "47641e6d2bbff1e241e87695b29f617f1a8f912adea34296fb10ecc3d7e9e84f"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
"dialyxir": {:hex, :dialyxir, "1.4.6", "7cca478334bf8307e968664343cbdb432ee95b4b68a9cba95bdabb0ad5bdfd9a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "8cf5615c5cd4c2da6c501faae642839c8405b49f8aa057ad4ae401cb808ef64d"},
"earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"},
"erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"},
"ex_doc": {:hex, :ex_doc, "0.39.1", "e19d356a1ba1e8f8cfc79ce1c3f83884b6abfcb79329d435d4bbb3e97ccc286e", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "8abf0ed3e3ca87c0847dfc4168ceab5bedfe881692f1b7c45f4a11b232806865"},
"credo": {:hex, :credo, "1.7.19", "cc52129665fc7c15143d47838fda0f9cd6dac9ceced7bf4da6f85fcbfe64b12a", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "2d8bc95d5a7bb99dd2613621d4f08c6a3575c3fd4b62e6a2b48a100352a557b8"},
"deep_merge": {:hex, :deep_merge, "1.0.2", "476aa7ea61c54de96220051b998d893869069094da65b96101aebf79416f8a1e", [:mix], [], "hexpm", "737a53cdc9758fedbb608bdc213969e65729466c4ef3cd8e8726d0335dff116c"},
"dialyxir": {:hex, :dialyxir, "1.4.8", "7ef671a8aff9948b091d8c30f09467fbb16e77305cda451bce48109a0f5e021c", [:mix], [{:erlex, ">= 0.2.8", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "cbd5a851571e5dfeb32aaf2e840bfa98b7864cb3071bf2ef5d95d1276b12e072"},
"earmark_parser": {:hex, :earmark_parser, "1.4.46", "67607a0532e810c6f630a515c548d0b24949643f168cc556303bee4cf96105c7", [:mix], [], "hexpm", "9c44636e8a1c68c62f526b2dcd85d941dbbcee7ab82cf64ba06ce28bef8e89f5"},
"erlex": {:hex, :erlex, "0.2.9", "7debbbaa9f4f368b8cd648983e0f1d7963028508e9c59e9d4ed504e94ef52a55", [:mix], [], "hexpm", "8cfffc0ec7159e6d73de2ab28a588064de80f88b2798d5cbe4482cbbc200178b"},
"ex_doc": {:hex, :ex_doc, "0.40.4", "66f2e42bf588594d5a8aab31cad87f2ddad09d0da1b1a2f379340ec2c2e497cb", [:mix], [{:earmark_parser, "~> 1.4.46", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "6222b9e423d76584ee34df2c82a5ed72c2d53dc153f7f483ad28b378694186cc"},
"file_system": {:hex, :file_system, "1.1.1", "31864f4685b0148f25bd3fbef2b1228457c0c89024ad67f7a81a3ffbc0bbad3a", [:mix], [], "hexpm", "7a15ff97dfe526aeefb090a7a9d3d03aa907e100e262a0f8f7746b78f8f87a5d"},
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
"makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"},
"jason": {:hex, :jason, "1.4.5", "2e3a008590b0b8d7388c20293e9dcc9cf3e5d642fd2a114e4cbbb52e595d940a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b0c823996102bcd0239b3c2444eb00409b72f6a140c1950bc8b457d836b30684"},
"makeup": {:hex, :makeup, "1.2.3", "c3ef0ff83acf305384acba0f70bff87d8732502baa1eb3eb081d8c154fbe18f5", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "15970751b7021c2bcd7ed56a54b3def23affd3969fb7c214dffdf28e97ce6f76"},
"makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"},
"makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"},
"makeup_erlang": {:hex, :makeup_erlang, "1.1.0", "835f7e60792e08824cda445639555d7bf1bbbddb1b60b306e33cb6f6db24dc74", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "1cd6780fb1dd1a03979abaed0fe82712b0625118fd5257d3ebbf73f960c73c3c"},
"media_codecs": {:hex, :media_codecs, "0.10.0", "dcc64779c3b287202fd8083fe49bf11b37f7b6bbd8edf3a9bd756370ee4417c5", [:mix], [], "hexpm", "8ea233ae378acfae3ab95a90f6f5c99711d55f15d0c5fac244d46b42f6a9ca04"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"},
"statistex": {:hex, :statistex, "1.1.0", "7fec1eb2f580a0d2c1a05ed27396a084ab064a40cfc84246dbfb0c72a5c761e5", [:mix], [], "hexpm", "f5950ea26ad43246ba2cce54324ac394a4e7408fdcf98b8e230f503a0cba9cf5"},
"statistex": {:hex, :statistex, "1.1.1", "73612aa7f79e53c30569be065fd121e380f1cf57bc4c2da5b41be9246da18df9", [:mix], [], "hexpm", "310c4b49b34adf683de3103639006bed233ab54c08a4add65a531448e653857c"},
"table_rex": {:hex, :table_rex, "4.1.0", "fbaa8b1ce154c9772012bf445bfb86b587430fb96f3b12022d3f35ee4a68c918", [:mix], [], "hexpm", "95932701df195d43bc2d1c6531178fc8338aa8f38c80f098504d529c43bc2601"},
}
28 changes: 28 additions & 0 deletions test/ex_mp4/box_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,32 @@ defmodule ExMP4.BoxTest do
assert Box.serialize(styp) |> IO.iodata_to_binary() == expected
assert Box.parse(%Box.Styp{}, :binary.part(expected, 8, 16)) == styp
end

test "serialize and parse uuid" do
type = <<0::128>>
uuid = Box.UUID.new(type, "some data")

expected = <<33::32, "uuid", type::binary, "some data">>

assert Box.size(uuid) == 33
assert Box.serialize(uuid) |> IO.iodata_to_binary() == expected
assert Box.parse(%Box.UUID{}, :binary.part(expected, 8, 25)) == uuid
end

test "uuid type must be 16 bytes" do
assert_raise ArgumentError, fn -> Box.UUID.new("short", "data") end
end

test "parse and serialize moov with uuid boxes" do
assert {:ok, <<_size::32, "moov", rest::binary>>} = File.read("test/fixtures/moov.bin")

moov = Box.parse(%Box.Moov{}, rest)
uuids = [Box.UUID.new(<<1::128>>, "first"), Box.UUID.new(<<2::128>>, "second")]
moov = %{moov | uuid: uuids}

data = Box.serialize(moov) |> IO.iodata_to_binary()
assert <<size::32, "moov", rest::binary>> = data
assert size == Box.size(moov)
assert Box.parse(%Box.Moov{}, rest) == moov
end
end
29 changes: 28 additions & 1 deletion test/ex_mp4/fwriter_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule ExMP4.FWriterTest do

import ExMP4.Support.Utils

alias ExMP4.{FWriter, Sample}
alias ExMP4.{Box, FWriter, Sample}

@moduletag :tmp_dir

Expand Down Expand Up @@ -72,6 +72,33 @@ defmodule ExMP4.FWriterTest do
assert :ok = ExMP4.Reader.close(reader)
end

test "write fragmented mp4 with uuid boxes", %{tmp_dir: tmp_dir} do
filepath = Path.join(tmp_dir, "out.mp4")
uuids = [Box.UUID.new(<<1::128>>, "data")]

assert {:ok, writer} =
FWriter.new(filepath, [video_track(), audio_track()], uuid: uuids, duration: true)

video_samples = for idx <- 0..4, do: video_sample(idx)

assert :ok =
writer
|> FWriter.create_fragment()
|> then(&Enum.reduce(video_samples, &1, fn s, w -> FWriter.write_sample(w, s) end))
|> FWriter.flush_fragment()
|> FWriter.close()

assert {:ok, reader} = ExMP4.Reader.new(filepath)
assert reader.uuid == uuids
assert reader.duration == 3500

for idx <- 0..4 do
assert Enum.at(video_samples, idx) == ExMP4.Reader.read_sample(reader, 1, idx)
end

assert :ok = ExMP4.Reader.close(reader)
end

test "write fragmented mp4 (base is moof)", %{tmp_dir: tmp_dir} do
filepath = Path.join(tmp_dir, "out.mp4")

Expand Down
30 changes: 29 additions & 1 deletion test/ex_mp4/writer_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule ExMP4.WriterTest do

import ExMP4.Support.Utils

alias ExMP4.{Sample, Writer}
alias ExMP4.{Box, Sample, Writer}

@moduletag :tmp_dir

Expand Down Expand Up @@ -97,6 +97,34 @@ defmodule ExMP4.WriterTest do
assert <<_ftyp::binary-size(32), _moov_size::binary-size(4), "moov", _rest::binary>> = data
end

for fast_start <- [false, true] do
test "write mp4 with uuid boxes (fast_start: #{fast_start})", %{tmp_dir: tmp_dir} do
filepath = Path.join(tmp_dir, "out.mp4")
uuids = [Box.UUID.new(<<1::128>>, "data"), Box.UUID.new(<<2::128>>)]

assert :ok =
filepath
|> Writer.new!(fast_start: unquote(fast_start))
|> Writer.write_header()
|> Writer.add_tracks([video_track(), audio_track()])
|> then(&Enum.into(Enum.concat(video_samples(), audio_samples()), &1))
|> Writer.write_trailer(uuid: uuids)

assert {:ok, reader} = ExMP4.Reader.new(filepath)
assert reader.uuid == uuids

for {sample, idx} <- Enum.with_index(video_samples()) do
assert sample == ExMP4.Reader.read_sample(reader, 1, idx)
end

for {sample, idx} <- Enum.with_index(audio_samples()) do
assert sample == ExMP4.Reader.read_sample(reader, 2, idx)
end

assert :ok = ExMP4.Reader.close(reader)
end
end

defp video_samples do
[
{0, 2000, 1000, true},
Expand Down
Loading