Skip to content

Commit 813f611

Browse files
committed
Add enforce_transcoding to output options
1 parent 2e33430 commit 813f611

File tree

9 files changed

+66
-44
lines changed

9 files changed

+66
-44
lines changed

lib/boombox.ex

+46-20
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ defmodule Boombox do
99

1010
alias Membrane.RTP
1111

12+
@type enforce_transcoding_value() :: boolean() | :audio | :video
13+
1214
@type webrtc_signaling :: Membrane.WebRTC.Signaling.t() | String.t()
1315
@type in_stream_opts :: [
1416
{:audio, :binary | boolean()}
@@ -64,6 +66,7 @@ defmodule Boombox do
6466
| {:address, :inet.ip_address() | String.t()}
6567
| {:port, :inet.port_number()}
6668
| {:target, String.t()}
69+
| {:enforce_transcoding, enforce_transcoding_value()}
6770
]
6871

6972
@type input ::
@@ -79,18 +82,19 @@ defmodule Boombox do
7982
@type output ::
8083
(path_or_uri :: String.t())
8184
| {:mp4, location :: String.t()}
85+
| {:mp4, location :: String.t(), [{:enforce_transcoding, enforce_transcoding_value()}]}
8286
| {:webrtc, webrtc_signaling()}
87+
| {:webrtc, webrtc_signaling(), [{:enforce_transcoding, enforce_transcoding_value()}]}
8388
| {:whip, uri :: String.t(), [{:token, String.t()} | {bandit_option :: atom(), term()}]}
8489
| {:hls, location :: String.t()}
90+
| {:hls, location :: String.t(), [{:enforce_transcoding, enforce_transcoding_value()}]}
8591
| {:rtp, out_rtp_opts()}
8692
| {:stream, out_stream_opts()}
8793

8894
@typep procs :: %{pipeline: pid(), supervisor: pid()}
8995
@typep opts_map :: %{
9096
input: input(),
91-
output: output(),
92-
enforce_video_transcoding?: boolean(),
93-
enforce_audio_transcoding?: boolean()
97+
output: output()
9498
}
9599

96100
@doc """
@@ -123,25 +127,15 @@ defmodule Boombox do
123127
"""
124128
@spec run(Enumerable.t() | nil,
125129
input: input(),
126-
output: output(),
127-
enforce_video_transcoding?: boolean(),
128-
enforce_audio_transcoding?: boolean()
130+
output: output()
129131
) :: :ok | Enumerable.t()
130132
@endpoint_opts [:input, :output]
131133
def run(stream \\ nil, opts) do
132134
opts =
133135
opts
134-
|> Keyword.validate!(
135-
@endpoint_opts ++
136-
[
137-
enforce_video_transcoding?: false,
138-
enforce_audio_transcoding?: false
139-
]
140-
)
141-
|> Map.new(fn
142-
{key, value} when key in @endpoint_opts -> {key, parse_endpoint_opt!(key, value)}
143-
{key, value} -> {key, value}
144-
end)
136+
|> Keyword.validate!(@endpoint_opts)
137+
|> Map.new(fn {key, value} -> {key, parse_endpoint_opt!(key, value)} end)
138+
|> resolve_enforce_transcoding()
145139

146140
:ok = maybe_log_transcoding_related_warning(opts)
147141

@@ -224,12 +218,21 @@ defmodule Boombox do
224218
{:mp4, location} when is_binary(location) and direction == :output ->
225219
{:mp4, location}
226220

221+
{:mp4, location, _opts} when is_binary(location) and direction == :output ->
222+
value
223+
227224
{:webrtc, %Membrane.WebRTC.Signaling{}} ->
228225
value
229226

227+
{:webrtc, %Membrane.WebRTC.Signaling{}, _opts} when direction == :output ->
228+
value
229+
230230
{:webrtc, uri} when is_binary(uri) ->
231231
value
232232

233+
{:webrtc, uri, _opts} when is_binary(uri) and direction == :output ->
234+
value
235+
233236
{:whip, uri} when is_binary(uri) ->
234237
parse_endpoint_opt!(direction, {:whip, uri, []})
235238

@@ -244,6 +247,10 @@ defmodule Boombox do
244247
{:hls, location} when direction == :output and is_binary(location) ->
245248
value
246249

250+
{:hls, location, opts}
251+
when direction == :output and is_binary(location) and is_list(opts) ->
252+
value
253+
247254
{:rtsp, location} when direction == :input and is_binary(location) ->
248255
value
249256

@@ -268,12 +275,12 @@ defmodule Boombox do
268275
@spec maybe_log_transcoding_related_warning(opts_map()) :: :ok
269276
def maybe_log_transcoding_related_warning(opts) do
270277
if is_webrtc_endpoint(opts.output) and not is_webrtc_endpoint(opts.input) and
271-
not opts.enforce_video_transcoding? do
278+
opts.enforce_transcoding not in [true, :video] do
272279
Logger.warning("""
273280
Boombox output protocol is WebRTC, while Boombox input doesn't support keyframe requests. This \
274281
might lead to issues with the output video if the output stream isn't sent only by localhost. You \
275-
can solve this by setting `:enforce_audio_transcoding?` option to `true`, but be aware that it \
276-
will increase Boombox CPU usage.
282+
can solve this by setting `:enforce_transcoding` output option to `true` or `:video`, but be aware \
283+
that it will increase Boombox CPU usage.
277284
""")
278285
end
279286

@@ -413,4 +420,23 @@ defmodule Boombox do
413420
raise ArgumentError, "Invalid transport: #{inspect(transport)}"
414421
end
415422
end
423+
424+
defp resolve_enforce_transcoding(opts) do
425+
maybe_keyword =
426+
opts.output
427+
|> Tuple.to_list()
428+
|> List.last()
429+
430+
enforce_transcoding =
431+
Keyword.keyword?(maybe_keyword) && Keyword.get(maybe_keyword, :enforce_transcoding, false)
432+
433+
opts
434+
|> Map.put(:enforce_transcoding, enforce_transcoding)
435+
|> Map.update!(:output, fn
436+
{:webrtc, signaling, _opts} -> {:webrtc, signaling}
437+
{:hls, location, _opts} -> {:hls, location}
438+
{:mp4, location, _opts} -> {:mp4, location}
439+
other -> other
440+
end)
441+
end
416442
end

lib/boombox/elixir_stream.ex

+2-3
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ defmodule Boombox.ElixirStream do
5757
{:audio, builder} ->
5858
builder
5959
|> child(:mp4_audio_transcoder, %Membrane.Transcoder{
60-
output_stream_format: Membrane.RawAudio,
61-
enforce_transcoding?: state.enforce_audio_transcoding?
60+
output_stream_format: Membrane.RawAudio
6261
})
6362
|> maybe_plug_resampler(options)
6463
|> via_in(Pad.ref(:input, :audio))
@@ -68,7 +67,7 @@ defmodule Boombox.ElixirStream do
6867
builder
6968
|> child(:elixir_stream_video_transcoder, %Membrane.Transcoder{
7069
output_stream_format: Membrane.RawVideo,
71-
enforce_transcoding?: state.enforce_video_transcoding?
70+
enforce_transcoding?: state.enforce_transcoding in [true, :video]
7271
})
7372
|> child(:elixir_stream_rgb_converter, %Membrane.FFmpeg.SWScale.Converter{
7473
format: :RGB

lib/boombox/hls.ex

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ defmodule Boombox.HLS do
4646
builder
4747
|> child(:hls_audio_transcoder, %Membrane.Transcoder{
4848
output_stream_format: Membrane.AAC,
49-
enforce_transcoding?: state.enforce_audio_transcoding?
49+
enforce_transcoding?: state.enforce_transcoding in [true, :audio]
5050
})
5151
|> via_in(Pad.ref(:input, :audio),
5252
options: [encoding: :AAC, segment_duration: Time.milliseconds(2000)]
@@ -57,7 +57,7 @@ defmodule Boombox.HLS do
5757
builder
5858
|> child(:hls_video_transcoder, %Membrane.Transcoder{
5959
output_stream_format: %H264{alignment: :au, stream_structure: :avc3},
60-
enforce_transcoding?: state.enforce_video_transcoding?
60+
enforce_transcoding?: state.enforce_transcoding in [true, :video]
6161
})
6262
|> via_in(Pad.ref(:input, :video),
6363
options: [encoding: :H264, segment_duration: Time.milliseconds(2000)]

lib/boombox/mp4.ex

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ defmodule Boombox.MP4 do
6868
builder
6969
|> child(:mp4_audio_transcoder, %Membrane.Transcoder{
7070
output_stream_format: Membrane.AAC,
71-
enforce_transcoding?: state.enforce_audio_transcoding?
71+
enforce_transcoding?: state.enforce_transcoding in [true, :audio]
7272
})
7373
|> child(:mp4_out_aac_parser, %Membrane.AAC.Parser{
7474
out_encapsulation: :none,
@@ -93,7 +93,7 @@ defmodule Boombox.MP4 do
9393
_not_h26x ->
9494
%H264{stream_structure: :avc3, alignment: :au}
9595
end,
96-
enforce_transcoding?: state.enforce_video_transcoding?
96+
enforce_transcoding?: state.enforce_transcoding in [true, :video]
9797
})
9898
|> via_in(Pad.ref(:input, :video))
9999
|> get_child(:mp4_muxer)

lib/boombox/pipeline.ex

+3-6
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@ defmodule Boombox.Pipeline do
5858
:input,
5959
:output,
6060
:parent,
61-
:enforce_video_transcoding?,
62-
:enforce_audio_transcoding?
61+
:enforce_transcoding
6362
]
6463

6564
defstruct @enforce_keys ++
@@ -103,8 +102,7 @@ defmodule Boombox.Pipeline do
103102
rtsp_state: Boombox.RTSP.state() | nil,
104103
parent: pid(),
105104
output_webrtc_state: Boombox.WebRTC.output_webrtc_state() | nil,
106-
enforce_video_transcoding?: boolean(),
107-
enforce_audio_transcoding?: boolean()
105+
enforce_transcoding: Boombox.enforce_transcoding_value()
108106
}
109107
end
110108

@@ -114,8 +112,7 @@ defmodule Boombox.Pipeline do
114112
input: opts.input,
115113
output: opts.output,
116114
parent: opts.parent,
117-
enforce_audio_transcoding?: opts.enforce_audio_transcoding?,
118-
enforce_video_transcoding?: opts.enforce_video_transcoding?,
115+
enforce_transcoding: opts.enforce_transcoding,
119116
status: :init
120117
}
121118

lib/boombox/rtp.ex

+4-4
Original file line numberDiff line numberDiff line change
@@ -143,24 +143,24 @@ defmodule Boombox.RTP do
143143
:H264 ->
144144
{%Membrane.H264{stream_structure: :annexb, alignment: :nalu},
145145
%Membrane.H264.Parser{output_stream_structure: :annexb, output_alignment: :nalu},
146-
Membrane.RTP.H264.Payloader, state.enforce_video_transcoding?}
146+
Membrane.RTP.H264.Payloader, state.enforce_transcoding in [true, :video]}
147147

148148
:AAC ->
149149
{%Membrane.AAC{encapsulation: :none},
150150
%Membrane.AAC.Parser{out_encapsulation: :none},
151151
%Membrane.RTP.AAC.Payloader{
152152
mode: track_config.encoding_specific_params.aac_bitrate_mode,
153153
frames_per_packet: 1
154-
}, state.enforce_video_transcoding?}
154+
}, state.enforce_transcoding in [true, :video]}
155155

156156
:OPUS ->
157157
{Membrane.Opus, %Membrane.Opus.Parser{delimitation: :undelimit},
158-
Membrane.RTP.Opus.Payloader, state.enforce_audio_transcoding}
158+
Membrane.RTP.Opus.Payloader, state.enforce_transcoding in [true, :audio]}
159159

160160
:H265 ->
161161
{%Membrane.H265{stream_structure: :annexb, alignment: :nalu},
162162
%Membrane.H265.Parser{output_stream_structure: :annexb, output_alignment: :nalu},
163-
Membrane.RTP.H265.Payloader, state.enforce_audio_transcoding}
163+
Membrane.RTP.H265.Payloader, state.enforce_transcoding in [true, :audio]}
164164
end
165165

166166
builder

lib/boombox/utils/cli.ex

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ defmodule Boombox.Utils.CLI do
2424
sps: {:string, :binary},
2525
vps: {:string, :binary},
2626
whip: {:string, :string},
27-
token: {:string, :string}
27+
token: {:string, :string},
28+
enforce_transcoding: {:string, :atom}
2829
]
2930

3031
@spec parse_argv([String.t()]) ::

lib/boombox/webrtc.ex

+4-3
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ defmodule Boombox.WebRTC do
149149
builder
150150
|> child(:mp4_audio_transcoder, %Membrane.Transcoder{
151151
output_stream_format: Membrane.Opus,
152-
enforce_transcoding?: state.enforce_audio_transcoding?
152+
enforce_transcoding?: state.enforce_transcoding in [true, :audio]
153153
})
154154
|> child(:webrtc_out_audio_realtimer, Membrane.Realtimer)
155155
|> via_in(Pad.ref(:input, tracks.audio), options: [kind: :audio])
@@ -159,6 +159,7 @@ defmodule Boombox.WebRTC do
159159
negotiated_codecs = state.output_webrtc_state.negotiated_video_codecs
160160
vp8_negotiated? = :vp8 in negotiated_codecs
161161
h264_negotiated? = :h264 in negotiated_codecs
162+
enforce_transcoding? = state.enforce_transcoding in [true, :video]
162163

163164
builder
164165
|> child(:webrtc_out_video_realtimer, Membrane.Realtimer)
@@ -168,9 +169,9 @@ defmodule Boombox.WebRTC do
168169
&1,
169170
vp8_negotiated?,
170171
h264_negotiated?,
171-
state.enforce_video_transcoding?
172+
enforce_transcoding?
172173
),
173-
enforce_transcoding?: state.enforce_video_transcoding?
174+
enforce_transcoding?: enforce_transcoding?
174175
})
175176
|> via_in(Pad.ref(:input, tracks.video), options: [kind: :video])
176177
|> get_child(:webrtc_output)

test/browser_test.exs

+1-3
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,7 @@ defmodule Boombox.BrowserTest do
118118
Task.async(fn ->
119119
Boombox.run(
120120
input: {:webrtc, "ws://localhost:8829"},
121-
output: {:webrtc, "ws://localhost:8830"},
122-
enforce_video_transcoding?: transcoding?,
123-
enforce_audio_transcoding?: transcoding?
121+
output: {:webrtc, "ws://localhost:8830", enforce_transcoding: transcoding?}
124122
)
125123
end)
126124

0 commit comments

Comments
 (0)