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
51 changes: 51 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Elixir ci

on:
push:
branches:
- master
pull_request:

env:
MIX_ENV: test

jobs:
test:
runs-on: ubuntu-latest

strategy:
matrix:
include:
- otp_version: 25.3
elixir_version: 1.16

- otp_version: 27.2
elixir_version: 1.18

steps:
- uses: actions/checkout@v3

- uses: erlef/setup-beam@v1
with:
elixir-version: ${{ matrix.elixir_version }}
otp-version: ${{ matrix.otp_version }}

- name: Install dependencies
run: mix deps.get
- name: Compile dependencies
run: mix deps.compile
- name: Run tests
run: mix test --warnings-as-errors
- name: Run Credo
run: mix credo --strict

format:
runs-on: ubuntu-latest
name: mix format
steps:
- uses: actions/checkout@v4
- uses: erlef/setup-beam@v1
with:
otp-version: 27.2
elixir-version: 1.18
- run: mix format --check-formatted
2 changes: 1 addition & 1 deletion lib/hlx/track.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ defmodule HLX.Track do
"""

alias ExMP4.Box
alias MediaCodecs.{MPEG4, H264, H265}
alias MediaCodecs.AV1.OBU
alias MediaCodecs.{H264, H265, MPEG4}

@codecs [:h264, :h265, :hevc, :aac, :av1]

Expand Down
10 changes: 5 additions & 5 deletions lib/hlx/writer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ defmodule HLX.Writer do

queues =
Map.new(independant_variants, fn variant ->
extra_variants = if variant.id == lead_variant_id, do: dependant_variants, else: []
extra_variants = (variant.id == lead_variant_id && dependant_variants) || []
{variant.id, create_queues(writer, variant, extra_variants)}
end)

Expand Down Expand Up @@ -266,6 +266,7 @@ defmodule HLX.Writer do
end

defp do_add_variant(%{config: config} = writer, name, options) do
# credo:disable-for-next-line
# TODO: validate options
muxer_options = [segment_type: config[:segment_type]]

Expand Down Expand Up @@ -449,10 +450,9 @@ defmodule HLX.Writer do

rendition_reports =
if preload_hint? do
Enum.reduce(rendition_reports, [], fn
%{uri: ^id}, acc -> acc
report, acc -> [%{report | uri: "#{report.uri}.m3u8"} | acc]
end)
rendition_reports
|> Enum.reject(&(&1.uri == id))
|> Enum.map(&%{&1 | uri: &1.uri <> ".m3u8"})
else
[]
end
Expand Down
68 changes: 37 additions & 31 deletions lib/hlx/writer/variant.ex
Original file line number Diff line number Diff line change
Expand Up @@ -172,37 +172,8 @@ defmodule HLX.Writer.Variant do

_ ->
referenced_renditions = Map.values(referenced_renditions)

referenced_codecs =
referenced_renditions
|> List.flatten()
|> Stream.flat_map(&TracksMuxer.tracks(&1.tracks_muxer))
|> Enum.map(& &1.mime)

tracks = TracksMuxer.tracks(variant.tracks_muxer)

codecs =
tracks
|> Stream.map(& &1.mime)
|> Stream.concat(referenced_codecs)
|> Stream.uniq()
|> Enum.join(",")

resolution =
Enum.find_value(tracks, fn
%{width: nil} -> nil
%{width: width, height: height} -> {width, height}
end)

{avg_bitrates, max_bitrates} =
Stream.map(referenced_renditions, fn variants ->
variants
|> Stream.map(&bandwidth/1)
|> Enum.unzip()
|> then(fn {a, m} -> {Enum.max(a), Enum.max(m)} end)
end)
|> Enum.unzip()

{codecs, resolution} = codecs_resolution(variant, referenced_renditions)
{avg_bitrates, max_bitrates} = avg_max_bandwidths(referenced_renditions)
{avg_band, max_band} = bandwidth(variant)

%{
Expand Down Expand Up @@ -239,6 +210,16 @@ defmodule HLX.Writer.Variant do
}
end

defp avg_max_bandwidths(renditions) do
Stream.map(renditions, fn variants ->
variants
|> Stream.map(&bandwidth/1)
|> Enum.unzip()
|> then(fn {a, m} -> {Enum.max(a), Enum.max(m)} end)
end)
|> Enum.unzip()
end

defp bandwidth(%{playlist: playlist}), do: MediaPlaylist.bandwidth(playlist)

defp calculate_timestamp(%{base_timestamp: nil}), do: nil
Expand All @@ -255,4 +236,29 @@ defmodule HLX.Writer.Variant do
duration = div((first_dts - base_dts) * 1000, timescale)
DateTime.from_unix!(variant.base_timestamp + duration, :millisecond)
end

defp codecs_resolution(variant, referenced_renditions) do
referenced_codecs =
referenced_renditions
|> List.flatten()
|> Stream.flat_map(&TracksMuxer.tracks(&1.tracks_muxer))
|> Enum.map(& &1.mime)

tracks = TracksMuxer.tracks(variant.tracks_muxer)

codecs =
tracks
|> Stream.map(& &1.mime)
|> Stream.concat(referenced_codecs)
|> Stream.uniq()
|> Enum.join(",")

resolution =
Enum.find_value(tracks, fn
%{width: nil} -> nil
%{width: width, height: height} -> {width, height}
end)

{codecs, resolution}
end
end
5 changes: 3 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ defmodule HLX.MixProject do
[
app: :hlx,
version: @version,
elixir: "~> 1.15",
elixir: "~> 1.16",
start_permanent: Mix.env() == :prod,
deps: deps(),

Expand Down Expand Up @@ -36,7 +36,8 @@ defmodule HLX.MixProject do
{:ex_m3u8, "~> 0.15.0"},
{:mpeg_ts, "~> 3.3.5"},
{:qex, "~> 0.5.1"},
{:ex_doc, ">= 0.0.0", only: :dev, runtime: false}
{:ex_doc, ">= 0.0.0", only: :dev, runtime: false},
{:credo, "~> 1.7", only: [:dev, :test], runtime: false}
]
end

Expand Down
4 changes: 4 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
%{
"bunch": {:hex, :bunch, "1.6.1", "5393d827a64d5f846092703441ea50e65bc09f37fd8e320878f13e63d410aec7", [:mix], [], "hexpm", "286cc3add551628b30605efbe2fca4e38cc1bea89bcd0a1a7226920b3364fe4a"},
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
"coerce": {:hex, :coerce, "1.0.2", "5ef791040c92baaa5dd344887563faaeac6e6742573a167493294f8af3672bbe", [:mix], [], "hexpm", "0b3451c729571234fdac478636c298e71d1f2ce1243abed5fa43fa3181b980eb"},
"credo": {:hex, :credo, "1.7.15", "283da72eeb2fd3ccf7248f4941a0527efb97afa224bcdef30b4b580bc8258e1c", [: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", "291e8645ea3fea7481829f1e1eb0881b8395db212821338e577a90bf225c5607"},
"earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"},
"ex_doc": {:hex, :ex_doc, "0.39.3", "519c6bc7e84a2918b737aec7ef48b96aa4698342927d080437f61395d361dcee", [: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", "0590955cf7ad3b625780ee1c1ea627c28a78948c6c0a9b0322bd976a079996e1"},
"ex_m3u8": {:hex, :ex_m3u8, "0.15.4", "66f6ec7e4fb7372c48032db1c2d4a3e6c2bbbde2d1d9a1098986e3caa0ab7a55", [:mix], [{:nimble_parsec, "~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:typed_struct, "~> 0.3.0", [hex: :typed_struct, repo: "hexpm", optional: false]}], "hexpm", "ec03aa516919e0c8ec202da55f609b763bd7960195a3388900090fcad270c873"},
"ex_mp4": {:hex, :ex_mp4, "0.14.1", "6152b9b981d5d6d5069d8dccd3d60f4f4be135f758f9b4bae039018119fdf089", [:mix], [{:media_codecs, "~> 0.10.0", [hex: :media_codecs, repo: "hexpm", optional: true]}, {:ratio, "~> 4.0", [hex: :ratio, repo: "hexpm", optional: false]}, {:table_rex, "~> 4.0", [hex: :table_rex, repo: "hexpm", optional: true]}], "hexpm", "f9f9630406371d19691673acea83f378b96e5c1961eb28436aa5d8ded148188c"},
"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"},
"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"},
Expand Down
5 changes: 3 additions & 2 deletions test/hlx/writer_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ defmodule HLX.WriterTest do
id: 2,
type: :audio,
codec: :aac,
timescale: 44800
timescale: 44_800
}

setup do
Expand Down Expand Up @@ -95,6 +95,7 @@ defmodule HLX.WriterTest do
assert String.ends_with?(segment.uri, extension)
end

# credo:disable-for-next-line
# TODO: check the actual segment data
end

Expand Down Expand Up @@ -375,7 +376,7 @@ defmodule HLX.WriterTest do
partial_segments = Enum.filter(playlist.timeline, &is_struct(&1, ExM3U8.Tags.Part))

assert length(segments) == 4
assert length(partial_segments) > 0
assert partial_segments != []

# rendition reports
uri = if name == "video", do: "audio.m3u8", else: "video.m3u8"
Expand Down
Loading