Skip to content

Commit d7589cc

Browse files
committed
Apply review suggestions
1 parent dbd0b7e commit d7589cc

5 files changed

Lines changed: 108 additions & 97 deletions

File tree

lib/transcoder.ex

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -170,20 +170,22 @@ defmodule Membrane.Transcoder do
170170
|> Map.from_struct()
171171
|> Map.merge(%{
172172
input_stream_format: nil,
173-
use_vulkan?: should_use_vulkan?(opts.native_acceleration)
173+
use_hardware_acceleration?: should_use_hardware_acceleration?(opts.native_acceleration)
174174
})
175175

176176
{[spec: spec], state}
177177
end
178178

179-
defp should_use_vulkan?(:if_available), do: vulkan_available?()
180-
defp should_use_vulkan?(_native_acceleration), do: false
179+
defp should_use_hardware_acceleration?(:if_available), do: vulkan_available?()
180+
defp should_use_hardware_acceleration?(_native_acceleration), do: false
181181

182182
@doc """
183-
Returns `true` if Vulkan hardware acceleration is available on this machine.
183+
Returns `true` if the optional `membrane_vk_video_plugin` dependency is installed
184+
and its modules can be loaded in the current runtime.
184185
185-
Use this to guard code that sets `native_acceleration: :if_available`, for example
186-
to print a diagnostic or pick a different pipeline branch.
186+
Note: a `true` result only confirms the plugin is loadable - it does not guarantee that the
187+
host actually exposes Vulkan Video extensions with H.264 encode/decode capabilities. The
188+
underlying plugin may still fail at runtime if the GPU/driver does not support them.
187189
"""
188190
@spec vulkan_available?() :: boolean()
189191
def vulkan_available?() do
@@ -219,7 +221,7 @@ defmodule Membrane.Transcoder do
219221
format,
220222
state.output_stream_format,
221223
state.transcoding_policy,
222-
state.use_vulkan?
224+
state.use_hardware_acceleration?
223225
)
224226
|> get_child(:output_funnel)
225227

@@ -264,15 +266,32 @@ defmodule Membrane.Transcoder do
264266
end
265267
end
266268

267-
defp plug_transcoding(builder, input_format, output_format, transcoding_policy, _use_vulkan?)
269+
defp plug_transcoding(
270+
builder,
271+
input_format,
272+
output_format,
273+
transcoding_policy,
274+
_use_hardware_acceleration?
275+
)
268276
when Audio.is_audio_format(input_format) do
269277
builder
270278
|> Audio.plug_audio_transcoding(input_format, output_format, transcoding_policy)
271279
end
272280

273-
defp plug_transcoding(builder, input_format, output_format, transcoding_policy, use_vulkan?)
281+
defp plug_transcoding(
282+
builder,
283+
input_format,
284+
output_format,
285+
transcoding_policy,
286+
use_hardware_acceleration?
287+
)
274288
when Video.is_video_format(input_format) do
275289
builder
276-
|> Video.plug_video_transcoding(input_format, output_format, transcoding_policy, use_vulkan?)
290+
|> Video.plug_video_transcoding(
291+
input_format,
292+
output_format,
293+
transcoding_policy,
294+
use_hardware_acceleration?
295+
)
277296
end
278297
end

lib/transcoder/video.ex

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,15 @@ defmodule Membrane.Transcoder.Video do
4141
input_format,
4242
output_format,
4343
transcoding_policy,
44-
use_vulkan?
44+
use_hardware_acceleration?
4545
)
4646
when is_video_format(input_format) and is_video_format(output_format) do
4747
do_plug_video_transcoding(
4848
builder,
4949
input_format,
5050
output_format,
5151
transcoding_policy,
52-
use_vulkan?
52+
use_hardware_acceleration?
5353
)
5454
end
5555

@@ -58,15 +58,15 @@ defmodule Membrane.Transcoder.Video do
5858
%RemoteStream{content_format: h26x},
5959
output_format,
6060
transcoding_policy,
61-
use_vulkan?
61+
use_hardware_acceleration?
6262
)
6363
when h26x in [H264, H265] do
6464
do_plug_video_transcoding(
6565
builder,
6666
struct!(h26x),
6767
output_format,
6868
transcoding_policy,
69-
use_vulkan?
69+
use_hardware_acceleration?
7070
)
7171
end
7272

@@ -75,7 +75,7 @@ defmodule Membrane.Transcoder.Video do
7575
%H264{},
7676
%H264{} = output_format,
7777
transcoding_policy,
78-
_use_vulkan?
78+
_use_hardware_acceleration?
7979
)
8080
when transcoding_policy in [:if_needed, :never] do
8181
builder
@@ -90,7 +90,7 @@ defmodule Membrane.Transcoder.Video do
9090
%H265{},
9191
%H265{} = output_format,
9292
transcoding_policy,
93-
_use_vulkan?
93+
_use_hardware_acceleration?
9494
)
9595
when transcoding_policy in [:if_needed, :never] do
9696
builder
@@ -127,7 +127,7 @@ defmodule Membrane.Transcoder.Video do
127127
%format_module{},
128128
%format_module{},
129129
transcoding_policy,
130-
_use_vulkan?
130+
_use_hardware_acceleration?
131131
)
132132
when transcoding_policy in [:if_needed, :never] do
133133
Membrane.Logger.debug("""
@@ -137,12 +137,18 @@ defmodule Membrane.Transcoder.Video do
137137
builder
138138
end
139139

140-
defp do_plug_video_transcoding(_builder, input_format, output_format, :never, _use_vulkan?),
141-
do:
142-
raise("""
143-
Cannot convert input format #{inspect(input_format)} to output format #{inspect(output_format)} \
144-
with :transcoding_policy option set to :never.
145-
""")
140+
defp do_plug_video_transcoding(
141+
_builder,
142+
input_format,
143+
output_format,
144+
:never,
145+
_use_hardware_acceleration?
146+
),
147+
do:
148+
raise("""
149+
Cannot convert input format #{inspect(input_format)} to output format #{inspect(output_format)} \
150+
with :transcoding_policy option set to :never.
151+
""")
146152

147153
defp do_plug_video_transcoding(builder, input_format, output_format, _transcoding_policy, true) do
148154
builder

mix.exs

Lines changed: 29 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -35,53 +35,36 @@ defmodule Membrane.Transcoder.Plugin.Mixfile do
3535
defp elixirc_paths(:test), do: ["lib", "test/support"]
3636
defp elixirc_paths(_env), do: ["lib"]
3737

38-
defp vulkan_available? do
39-
System.get_env("MEMBRANE_VK_VIDEO") == "1" or
40-
match?(
41-
{_, 0},
42-
System.cmd("pkg-config", ["--exists", "vulkan"], stderr_to_stdout: true)
43-
)
44-
rescue
45-
_ -> false
46-
end
47-
4838
defp deps do
49-
vk_dep =
50-
if vulkan_available?() do
51-
[{:membrane_vk_video_plugin, "~> 0.2.0", optional: true}]
52-
else
53-
[]
54-
end
55-
56-
vk_dep ++
57-
[
58-
{:membrane_core, "~> 1.2 and >= 1.2.1"},
59-
{:membrane_opus_plugin, "~> 0.20.3"},
60-
{:membrane_aac_plugin, "~> 0.19.0"},
61-
{:membrane_aac_fdk_plugin, "~> 0.18.0"},
62-
{:membrane_vpx_plugin, "~> 0.4.0"},
63-
{:membrane_h26x_plugin, "~> 0.10.0"},
64-
{:membrane_h264_ffmpeg_plugin, "~> 0.32.0"},
65-
{:membrane_h265_ffmpeg_plugin, "~> 0.4.2"},
66-
{:membrane_ffmpeg_swresample_plugin, "~> 0.20.0"},
67-
{:membrane_ffmpeg_swscale_plugin, "~> 0.16.2"},
68-
{:membrane_timestamp_queue, "~> 0.2.2"},
69-
{:membrane_h264_format, "~> 0.6.1"},
70-
{:membrane_h265_format, "~> 0.2.0"},
71-
{:membrane_vp8_format, "~> 0.5.0"},
72-
{:membrane_opus_format, "~> 0.3.0"},
73-
{:membrane_aac_format, "~> 0.8.0"},
74-
{:membrane_funnel_plugin, "~> 0.9.1"},
75-
{:membrane_mpegaudio_format, "~> 0.3.0"},
76-
{:membrane_mp3_mad_plugin, "~> 0.18.4"},
77-
{:membrane_mp3_lame_plugin, "~> 0.18.3"},
78-
{:ex_doc, ">= 0.0.0", only: :dev, runtime: false},
79-
{:dialyxir, ">= 0.0.0", only: :dev, runtime: false},
80-
{:credo, ">= 0.0.0", only: :dev, runtime: false},
81-
{:membrane_file_plugin, "~> 0.17.2", only: :test},
82-
{:membrane_raw_audio_parser_plugin, "~> 0.4.0", only: :test},
83-
{:membrane_ivf_plugin, "~> 0.8.0", only: :test}
84-
]
39+
[
40+
{:membrane_vk_video_plugin, "~> 0.2.0", optional: true},
41+
{:membrane_core, "~> 1.2 and >= 1.2.1"},
42+
{:membrane_opus_plugin, "~> 0.20.3"},
43+
{:membrane_aac_plugin, "~> 0.19.0"},
44+
{:membrane_aac_fdk_plugin, "~> 0.18.0"},
45+
{:membrane_vpx_plugin, "~> 0.4.0"},
46+
{:membrane_h26x_plugin, "~> 0.10.0"},
47+
{:membrane_h264_ffmpeg_plugin, "~> 0.32.0"},
48+
{:membrane_h265_ffmpeg_plugin, "~> 0.4.2"},
49+
{:membrane_ffmpeg_swresample_plugin, "~> 0.20.0"},
50+
{:membrane_ffmpeg_swscale_plugin, "~> 0.16.2"},
51+
{:membrane_timestamp_queue, "~> 0.2.2"},
52+
{:membrane_h264_format, "~> 0.6.1"},
53+
{:membrane_h265_format, "~> 0.2.0"},
54+
{:membrane_vp8_format, "~> 0.5.0"},
55+
{:membrane_opus_format, "~> 0.3.0"},
56+
{:membrane_aac_format, "~> 0.8.0"},
57+
{:membrane_funnel_plugin, "~> 0.9.1"},
58+
{:membrane_mpegaudio_format, "~> 0.3.0"},
59+
{:membrane_mp3_mad_plugin, "~> 0.18.4"},
60+
{:membrane_mp3_lame_plugin, "~> 0.18.3"},
61+
{:ex_doc, ">= 0.0.0", only: :dev, runtime: false},
62+
{:dialyxir, ">= 0.0.0", only: :dev, runtime: false},
63+
{:credo, ">= 0.0.0", only: :dev, runtime: false},
64+
{:membrane_file_plugin, "~> 0.17.2", only: :test},
65+
{:membrane_raw_audio_parser_plugin, "~> 0.4.0", only: :test},
66+
{:membrane_ivf_plugin, "~> 0.8.0", only: :test}
67+
]
8568
end
8669

8770
defp dialyzer() do

mix.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"membrane_raw_audio_parser_plugin": {:hex, :membrane_raw_audio_parser_plugin, "0.4.0", "7a1e53b68a221d00e47fb5d3c7e29200dfe8f7bc0862e69000b61c6562093acc", [:mix], [{:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_raw_audio_format, "~> 0.12.0", [hex: :membrane_raw_audio_format, repo: "hexpm", optional: false]}], "hexpm", "ff8d3fba45b1c2814b68d49878f19d2c1ad1147b53f606b48b6b67068435dcd0"},
4646
"membrane_raw_video_format": {:hex, :membrane_raw_video_format, "0.4.3", "61b2f6afdffa43c25de5a433c3a3bed933144be0f753b6fc8c6a9f255382eaff", [:mix], [{:image, ">= 0.54.0", [hex: :image, repo: "hexpm", optional: true]}], "hexpm", "11739a7d956d037f3ee109f06f075f1a99fea000c778628ac58ed28637e4c637"},
4747
"membrane_timestamp_queue": {:hex, :membrane_timestamp_queue, "0.2.2", "1c831b2273d018a6548654aa9f7fa7c4b683f71d96ffe164934ef55f9d11f693", [:mix], [{:heap, "~> 2.0", [hex: :heap, repo: "hexpm", optional: false]}, {:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}], "hexpm", "7c830e760baaced0988421671cd2c83c7cda8d1bd2b61fd05332711675d1204f"},
48+
"membrane_vk_video_plugin": {:hex, :membrane_vk_video_plugin, "0.2.1", "7304ae294ca44279e8dcc5e3206ed31157467e9d65b12cb7e4db246fb1d58dd4", [:mix], [{:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_h264_format, "~> 0.6.1", [hex: :membrane_h264_format, repo: "hexpm", optional: false]}, {:membrane_raw_video_format, "~> 0.4.2", [hex: :membrane_raw_video_format, repo: "hexpm", optional: false]}, {:rustler, "~> 0.37.1", [hex: :rustler, repo: "hexpm", optional: false]}], "hexpm", "19bdae7d8bbcdc110d4aa991d5cb7154a743a985a30842cdc24012b402258682"},
4849
"membrane_vp8_format": {:hex, :membrane_vp8_format, "0.5.0", "a589c20bb9d97ddc9b717684d00cefc84e2500ce63a0c33c4b9618d9b2f9b2ea", [:mix], [], "hexpm", "d29e0dae4bebc6838e82e031c181fe626d168c687e4bc617c1d0772bdeed19d5"},
4950
"membrane_vp9_format": {:hex, :membrane_vp9_format, "0.5.0", "c6a4f2cbfc39dba5d80ad8287162c52b5cf6488676bd64435c1ac957bd16e66f", [:mix], [], "hexpm", "68752d8cbe7270ec222fc84a7d1553499f0d8ff86ef9d9e89f8955d49e20278e"},
5051
"membrane_vpx_plugin": {:hex, :membrane_vpx_plugin, "0.4.2", "781944d370845c0259eb2d5c2eb2209bece17dc49ac3e85c11ef1c4161c0afd1", [:mix], [{:membrane_core, "~> 1.0", [hex: :membrane_core, repo: "hexpm", optional: false]}, {:membrane_precompiled_dependency_provider, "~> 0.2.1", [hex: :membrane_precompiled_dependency_provider, repo: "hexpm", optional: false]}, {:membrane_raw_video_format, "~> 0.4.0", [hex: :membrane_raw_video_format, repo: "hexpm", optional: false]}, {:membrane_vp8_format, "~> 0.5.0", [hex: :membrane_vp8_format, repo: "hexpm", optional: false]}, {:membrane_vp9_format, "~> 0.5.0", [hex: :membrane_vp9_format, repo: "hexpm", optional: false]}, {:unifex, "~> 1.2", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "5621a389fe4fcd1c964b14d665025ec91127d1c9d848f38110000c25f8299c9d"},
@@ -58,6 +59,7 @@
5859
"qex": {:hex, :qex, "0.5.2", "a0c861a2de2380314c23ef592349824ca9016c5845380667ff1d9a22a8796f9b", [:mix], [], "hexpm", "6fb81bf3ae354a9abb471b9561538ea3e8540125d803b00f45cbccff52f00496"},
5960
"ratio": {:hex, :ratio, "4.0.1", "3044166f2fc6890aa53d3aef0c336f84b2bebb889dc57d5f95cc540daa1912f8", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:numbers, "~> 5.2.0", [hex: :numbers, repo: "hexpm", optional: false]}], "hexpm", "c60cbb3ccdff9ffa56e7d6d1654b5c70d9f90f4d753ab3a43a6bf40855b881ce"},
6061
"req": {:hex, :req, "0.5.17", "0096ddd5b0ed6f576a03dde4b158a0c727215b15d2795e59e0916c6971066ede", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0b8bc6ffdfebbc07968e59d3ff96d52f2202d0536f10fef4dc11dc02a2a43e39"},
62+
"rustler": {:hex, :rustler, "0.37.3", "5f4e6634d43b26f0a69834dd1d3ed4e1710b022a053bf4a670220c9540c92602", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "a6872c6f53dcf00486d1e7f9e046e20e01bf1654bdacc4193016c2e8002b32a2"},
6163
"shmex": {:hex, :shmex, "0.5.1", "81dd209093416bf6608e66882cb7e676089307448a1afd4fc906c1f7e5b94cf4", [:mix], [{:bunch_native, "~> 0.5.0", [hex: :bunch_native, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.0", [hex: :bundlex, repo: "hexpm", optional: false]}], "hexpm", "c29f8286891252f64c4e1dac40b217d960f7d58def597c4e606ff8fbe71ceb80"},
6264
"telemetry": {:hex, :telemetry, "1.4.1", "ab6de178e2b29b58e8256b92b382ea3f590a47152ca3651ea857a6cae05ac423", [:rebar3], [], "hexpm", "2172e05a27531d3d31dd9782841065c50dd5c3c7699d95266b2edd54c2dafa1c"},
6365
"unifex": {:hex, :unifex, "1.2.1", "6841c170a6e16509fac30b19e4e0a19937c33155a59088b50c15fc2c36251b6b", [:mix], [{:bunch, "~> 1.0", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.4", [hex: :bundlex, repo: "hexpm", optional: false]}, {:shmex, "~> 0.5.0", [hex: :shmex, repo: "hexpm", optional: false]}], "hexpm", "8c9d2e3c48df031e9995dd16865bab3df402c0295ba3a31f38274bb5314c7d37"},

test/integration_test.exs

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ defmodule Membrane.Transcoder.IntegrationTest do
3535
do: Map.put(input, :output_format, output)
3636

3737
@vk_video_cases for input <- @video_inputs,
38-
output <- @video_outputs,
39-
do: Map.put(input, :output_format, output)
38+
do: Map.put(input, :output_format, H264)
4039

4140
@test_cases @video_cases ++ @audio_cases
4241

@@ -80,38 +79,40 @@ defmodule Membrane.Transcoder.IntegrationTest do
8079

8180
Enum.map(@vk_video_cases, fn test_case ->
8281
@tag :vulkan
83-
test "if transcoder supports #{inspect(test_case.input_format)} input and #{inspect(test_case.output_format)} output with native acceleration" do
84-
pid = Testing.Pipeline.start_link_supervised!()
82+
test "transcoder produces identical output for #{inspect(test_case.input_format)} -> H264 with and without native acceleration" do
83+
sw_output = run_transcoder_to_file(unquote(Macro.escape(test_case)), :never)
84+
vk_output = run_transcoder_to_file(unquote(Macro.escape(test_case)), :if_available)
8585

86-
spec =
87-
child(%Membrane.File.Source{
88-
location: Path.join("./test/fixtures", unquote(test_case.input_file))
89-
})
90-
|> then(unquote(test_case.preprocess))
91-
|> child(%Membrane.Transcoder{
92-
output_stream_format: unquote(test_case.output_format),
93-
native_acceleration: :if_available
94-
})
95-
|> child(:sink, Testing.Sink)
86+
assert byte_size(sw_output) > 0
87+
assert :crypto.hash(:sha256, sw_output) == :crypto.hash(:sha256, vk_output)
88+
end
89+
end)
9690

97-
Testing.Pipeline.execute_actions(pid, spec: spec)
91+
defp run_transcoder_to_file(test_case, native_acceleration) do
92+
tmp_path =
93+
Path.join(System.tmp_dir!(), "vk_transcoder_#{:erlang.unique_integer([:positive])}")
9894

99-
case unquote(test_case.output_format) do
100-
{module, opts} when is_atom(module) ->
101-
assert_sink_stream_format(pid, :sink, %^module{} = received_format)
95+
pid = Testing.Pipeline.start_link_supervised!()
10296

103-
for {key, value} <- opts do
104-
assert Map.get(received_format, key) == value
105-
end
97+
spec =
98+
child(%Membrane.File.Source{
99+
location: Path.join("./test/fixtures", test_case.input_file)
100+
})
101+
|> then(test_case.preprocess)
102+
|> child(:transcoder, %Membrane.Transcoder{
103+
output_stream_format: test_case.output_format,
104+
native_acceleration: native_acceleration
105+
})
106+
|> child(:sink, %Membrane.File.Sink{location: tmp_path})
106107

107-
module when is_atom(module) ->
108-
assert_sink_stream_format(pid, :sink, received_format)
109-
assert received_format.__struct__ == module
110-
end
108+
Testing.Pipeline.execute_actions(pid, spec: spec)
109+
assert_end_of_stream(pid, :sink, :input, 30_000)
110+
Testing.Pipeline.terminate(pid)
111111

112-
Testing.Pipeline.terminate(pid)
113-
end
114-
end)
112+
bytes = File.read!(tmp_path)
113+
File.rm(tmp_path)
114+
bytes
115+
end
115116

116117
defmodule FormatSource do
117118
use Membrane.Source

0 commit comments

Comments
 (0)