Skip to content

Commit 2ff2591

Browse files
committed
Implement transcoding_policy option
1 parent 2ae23dd commit 2ff2591

File tree

4 files changed

+83
-32
lines changed

4 files changed

+83
-32
lines changed

lib/transcoder.ex

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,27 @@ defmodule Membrane.Transcoder do
6969
and is supposed to return the desired output stream format or its module.
7070
"""
7171
],
72-
force_transcoding?: [
73-
spec: boolean() | (stream_format() -> boolean()),
74-
default: false,
72+
transcoding_policy: [
73+
spec: :always | :if_needed | :never,
74+
default: :if_needed,
7575
description: """
76-
If set to `true`, the input media stream will be decoded and encoded, even
77-
if the input stream format and the output stream format are the same type.
76+
Specifies, when transcoding should be appliead.
7877
7978
Can be either:
80-
* a boolean,
81-
* a function that receives the input stream format and returns a boolean.
79+
* an atom: `:always`, `:if_needed` (default) or `:never`,
80+
* a function that receives the input stream format and returns an atom.
81+
82+
If set to `:always`, the input media stream will be decoded and encoded, even
83+
if the input stream format and the output stream format are the same type.
84+
85+
If set to `:if_needed`, the input media stream will be transcoded only if the input
86+
stream format and the output stream format are different types.
87+
This is the default behavior.
88+
89+
If set to `:never`, the input media stream won't be neither deocded nor transcoded.
90+
Changing alignment, encapsulation or stream structure is still possible. This option
91+
is helpful when you want to ensure that #{inspect(__MODULE__)} will not use too much
92+
of resources, e.g. CPU or memory.
8293
"""
8394
]
8495

@@ -109,16 +120,16 @@ defmodule Membrane.Transcoder do
109120
|> resolve_output_stream_format()
110121

111122
state =
112-
with %{force_transcoding?: f} when is_function(f) <- state do
113-
%{state | force_transcoding?: f.(format)}
123+
with %{transcoding_policy: f} when is_function(f) <- state do
124+
%{state | transcoding_policy: f.(format)}
114125
end
115126

116127
spec =
117128
get_child(:connector)
118129
|> plug_transcoding(
119130
format,
120131
state.output_stream_format,
121-
state.force_transcoding?
132+
state.transcoding_policy
122133
)
123134
|> get_child(:output_funnel)
124135

@@ -160,15 +171,15 @@ defmodule Membrane.Transcoder do
160171
end
161172
end
162173

163-
defp plug_transcoding(builder, input_format, output_format, force_transcoding?)
174+
defp plug_transcoding(builder, input_format, output_format, transcoding_policy)
164175
when Audio.is_audio_format(input_format) do
165176
builder
166-
|> Audio.plug_audio_transcoding(input_format, output_format, force_transcoding?)
177+
|> Audio.plug_audio_transcoding(input_format, output_format, transcoding_policy)
167178
end
168179

169-
defp plug_transcoding(builder, input_format, output_format, force_transcoding?)
180+
defp plug_transcoding(builder, input_format, output_format, transcoding_policy)
170181
when Video.is_video_format(input_format) do
171182
builder
172-
|> Video.plug_video_transcoding(input_format, output_format, force_transcoding?)
183+
|> Video.plug_video_transcoding(input_format, output_format, transcoding_policy)
173184
end
174185
end

lib/transcoder/audio.ex

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,18 @@ defmodule Membrane.Transcoder.Audio do
3535
audio_stream_format(),
3636
boolean()
3737
) :: ChildrenSpec.builder()
38-
def plug_audio_transcoding(builder, input_format, output_format, force_transcoding?)
38+
def plug_audio_transcoding(builder, input_format, output_format, transcoding_policy)
3939
when is_audio_format(input_format) and is_audio_format(output_format) do
40-
do_plug_audio_transcoding(builder, input_format, output_format, force_transcoding?)
40+
do_plug_audio_transcoding(builder, input_format, output_format, transcoding_policy)
4141
end
4242

4343
defp do_plug_audio_transcoding(
4444
builder,
4545
%format_module{},
4646
%format_module{},
47-
false = _force_transcoding?
48-
) do
47+
transcoding_policy
48+
)
49+
when transcoding_policy in [:if_needed, :never] do
4950
Membrane.Logger.debug("""
5051
This bin will only forward buffers, as the input stream format is the same as the output stream format.
5152
""")
@@ -57,12 +58,20 @@ defmodule Membrane.Transcoder.Audio do
5758
builder,
5859
%RemoteStream{content_format: Opus},
5960
%Opus{},
60-
false = _force_transcoding?
61-
) do
61+
transcoding_policy
62+
)
63+
when transcoding_policy in [:if_needed, :never] do
6264
builder |> child(:opus_parser, Opus.Parser)
6365
end
6466

65-
defp do_plug_audio_transcoding(builder, input_format, output_format, _force_transcoding?) do
67+
defp do_plug_audio_transcoding(_builder, input_format, output_format, :never) do
68+
raise """
69+
Cannot convert input format #{inspect(input_format)} to output format #{inspect(output_format)} \
70+
with :transcoding_policy option set to :never.
71+
"""
72+
end
73+
74+
defp do_plug_audio_transcoding(builder, input_format, output_format, _transcoding_policy) do
6675
builder
6776
|> maybe_plug_parser(input_format)
6877
|> maybe_plug_decoder(input_format)

lib/transcoder/video.ex

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@ defmodule Membrane.Transcoder.Video do
1919
video_stream_format(),
2020
boolean()
2121
) :: ChildrenSpec.builder()
22-
def plug_video_transcoding(builder, input_format, output_format, force_transcoding?)
22+
def plug_video_transcoding(builder, input_format, output_format, transcoding_policy)
2323
when is_video_format(input_format) and is_video_format(output_format) do
24-
do_plug_video_transcoding(builder, input_format, output_format, force_transcoding?)
24+
do_plug_video_transcoding(builder, input_format, output_format, transcoding_policy)
2525
end
2626

2727
defp do_plug_video_transcoding(
2828
builder,
2929
%h26x{},
3030
%h26x{} = output_format,
31-
false = _force_transcoding?
31+
transcoding_policy
3232
)
33-
when h26x in [H264, H265] do
33+
when h26x in [H264, H265] and transcoding_policy in [:if_needed, :never] do
3434
parser =
3535
h26x
3636
|> Module.concat(Parser)
@@ -46,16 +46,24 @@ defmodule Membrane.Transcoder.Video do
4646
builder,
4747
%format_module{},
4848
%format_module{},
49-
false = _force_transcoding?
50-
) do
49+
transcoding_policy
50+
)
51+
when transcoding_policy in [:if_needed, :never] do
5152
Membrane.Logger.debug("""
5253
This bin will only forward buffers, as the input stream format is the same type as the output stream format.
5354
""")
5455

5556
builder
5657
end
5758

58-
defp do_plug_video_transcoding(builder, input_format, output_format, _force_transcoding?) do
59+
defp do_plug_video_transcoding(_builder, input_format, output_format, :never) do
60+
raise """
61+
Cannot convert input format #{inspect(input_format)} to output format #{inspect(output_format)} \
62+
with :transcoding_policy option set to :never.
63+
"""
64+
end
65+
66+
defp do_plug_video_transcoding(builder, input_format, output_format, _transcoding_policy) do
5967
builder
6068
|> maybe_plug_parser_and_decoder(input_format)
6169
|> maybe_plug_encoder_and_parser(output_format)

test/integration_test.exs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,14 @@ defmodule Membrane.Transcoder.IntegrationTest do
6767
do: {[stream_format: {:output, state.format}], state}
6868
end
6969

70-
test "if encoder and decoder are spawned or not, depending on the value of `force_transcoding?` option" do
70+
test "if encoder and decoder are spawned or not, depending on the value of `transcoding_policy` option" do
7171
for format <- [%AAC{channels: 1}, %H264{alignment: :au, stream_structure: :annexb}],
72-
force_transcoding? <- [true, false] do
72+
transcoding_policy <- [:always, :if_needed, :never] do
7373
spec =
7474
child(:source, %FormatSource{format: format})
7575
|> child(:transcoder, %Membrane.Transcoder{
7676
output_stream_format: format,
77-
force_transcoding?: force_transcoding?
77+
transcoding_policy: transcoding_policy
7878
})
7979
|> child(:sink, Testing.Sink)
8080

@@ -89,7 +89,7 @@ defmodule Membrane.Transcoder.IntegrationTest do
8989
|> Enum.each(fn child_name ->
9090
get_child_result = Testing.Pipeline.get_child_pid(pipeline, [:transcoder, child_name])
9191

92-
if force_transcoding? do
92+
if transcoding_policy == :always do
9393
assert {:ok, child_pid} = get_child_result
9494
assert is_pid(child_pid)
9595
else
@@ -100,4 +100,27 @@ defmodule Membrane.Transcoder.IntegrationTest do
100100
Testing.Pipeline.terminate(pipeline)
101101
end
102102
end
103+
104+
@tag :xd
105+
test "if transcoder raises `transcoding_policy` is set to `:never` and formats don't match" do
106+
spec =
107+
child(:source, %FormatSource{format: %H264{alignment: :au, stream_structure: :annexb}})
108+
|> child(:transcoder, %Membrane.Transcoder{
109+
output_stream_format: VP8,
110+
transcoding_policy: :never
111+
})
112+
|> child(:sink, Testing.Sink)
113+
114+
{:ok, pipeline, supervisor} = Testing.Pipeline.start_supervised()
115+
# supervisor_ref = Process.monitor(supervisor)
116+
pipeline_ref = Process.monitor(pipeline)
117+
118+
Testing.Pipeline.execute_actions(pipeline, spec: spec)
119+
120+
assert_receive {:DOWN, ^pipeline_ref, :process, _pid,
121+
{:membrane_child_crash, :transcoder,
122+
{%RuntimeError{}, _transcoder_stacktrace}}}
123+
124+
# assert_receive {:DOWN, ^supervisor_ref, :process, _pid, _reason}
125+
end
103126
end

0 commit comments

Comments
 (0)