Packages
membrane_hls_plugin
3.0.2
3.0.10
3.0.9
3.0.8
3.0.7
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
2.1.9
2.1.8
2.1.7
2.1.6
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.16
2.0.15
2.0.14
2.0.13
2.0.12
2.0.11
2.0.10
2.0.9
2.0.8
2.0.7
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.1.12
1.1.11
1.1.10
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.0
Adaptive live streaming (HLS) plugin for the Membrane Framework.
Current section
Files
Jump to
Current section
Files
lib/membrane/hls/ts_sink.ex
defmodule Membrane.HLS.TSSink do
use Membrane.Sink
def_input_pad(:input,
accepted_format: Membrane.RemoteStream
)
def_options(
track_id: [
spec: String.t(),
description: "ID of the track."
],
build_stream: [
spec: (map() -> HLS.VariantStream.t() | HLS.AlternativeRendition.t()),
description: "Build the stream with the given stream format"
],
target_segment_duration: [
spec: Membrane.Time.t()
]
)
@impl true
def handle_init(_context, opts) do
{[], %{opts: opts}}
end
@impl true
def handle_stream_format(:input, format, _ctx, state) do
track_id = state.opts.track_id
target_segment_duration =
Membrane.Time.as_seconds(state.opts.target_segment_duration, :exact)
|> Ratio.ceil()
{stream, legacy_codecs} =
case state.opts.build_stream.(format) do
{aac_format, stream} ->
info = %{
mp4a: %{
aot_id: Membrane.AAC.profile_to_aot_id(aac_format.profile),
channels: Membrane.AAC.channels_to_channel_config_id(aac_format.channels),
frequency: aac_format.sample_rate
}
}
{stream, Membrane.HLS.serialize_codecs(info)}
stream ->
{stream, List.wrap(Map.get(stream, :codecs))}
end
Membrane.HLS.maybe_warn_deprecated_stream_fields(track_id, stream)
{derived_codecs, derived_complete?} = derive_codecs_from_ts_format(format)
{codecs, codecs_complete?} =
cond do
derived_complete? -> {derived_codecs, true}
derived_codecs == [] and legacy_codecs != [] -> {legacy_codecs, true}
true -> {derived_codecs, false}
end
add_track_opts = [
codecs: codecs,
codecs_complete?: codecs_complete?,
stream: stream,
segment_extension: ".ts",
target_segment_duration: target_segment_duration
]
{[notify_parent: {:packager_add_track, track_id, add_track_opts}], state}
end
@impl true
def handle_buffer(:input, buffer, _ctx, state) do
duration =
buffer.metadata.duration
|> Membrane.Time.as_seconds()
|> Ratio.to_float()
actions = [
notify_parent:
{:packager_put_segment, state.opts.track_id, buffer.payload, duration, buffer.pts,
Map.get(buffer, :dts)}
]
{actions, state}
end
defp derive_codecs_from_ts_format(%Membrane.RemoteStream{content_format: content_format})
when is_struct(content_format, Membrane.MPEG.TS.StreamFormat) do
streams = Map.get(content_format, :elementary_streams, [])
if streams == [] do
{[], false}
else
codecs =
streams
|> Enum.flat_map(fn stream ->
stream
|> Map.get(:upstream_format)
|> serialize_upstream_codec()
end)
|> Enum.uniq()
complete? =
Enum.all?(streams, fn stream ->
stream
|> Map.get(:upstream_format)
|> codec_known?()
end)
{codecs, complete?}
end
end
defp derive_codecs_from_ts_format(_format), do: {[], false}
defp codec_known?(%Membrane.AAC{}), do: true
defp codec_known?(_other), do: false
defp serialize_upstream_codec(%Membrane.AAC{} = format) do
info = %{
mp4a: %{
aot_id: Membrane.AAC.profile_to_aot_id(format.profile),
channels: Membrane.AAC.channels_to_channel_config_id(format.channels),
frequency: format.sample_rate
}
}
Membrane.HLS.serialize_codecs(info)
end
defp serialize_upstream_codec(_format), do: []
end