Current section

Files

Jump to
membrane_transcoder_plugin lib transcoder video.ex
Raw

lib/transcoder/video.ex

defmodule Membrane.Transcoder.Video do
@moduledoc false
import Membrane.ChildrenSpec
require Membrane.Logger
alias Membrane.{ChildrenSpec, H264, H265, RawVideo, RemoteStream, VP8}
@type video_stream_format :: VP8.t() | H264.t() | H265.t() | RawVideo.t()
defguard is_video_format(format)
when is_struct(format) and
(format.__struct__ in [VP8, H264, H265, RawVideo] or
(format.__struct__ == RemoteStream and format.content_format == VP8 and
format.type == :packetized))
@spec plug_video_transcoding(
ChildrenSpec.builder(),
video_stream_format(),
video_stream_format(),
boolean()
) :: ChildrenSpec.builder()
def plug_video_transcoding(builder, input_format, output_format, enforce_transcoding?)
when is_video_format(input_format) and is_video_format(output_format) do
do_plug_video_transcoding(builder, input_format, output_format, enforce_transcoding?)
end
defp do_plug_video_transcoding(
builder,
%h26x{},
%h26x{} = output_format,
false = _enforce_transcoding?
)
when h26x in [H264, H265] do
parser =
h26x
|> Module.concat(Parser)
|> struct!(
output_stream_structure: stream_structure_type(output_format),
output_alignment: output_format.alignment
)
builder |> child(:h264_parser, parser)
end
defp do_plug_video_transcoding(
builder,
%format_module{},
%format_module{},
false = _enforce_transcoding?
) do
Membrane.Logger.debug("""
This bin will only forward buffers, as the input stream format is the same type as the output stream format.
""")
builder
end
defp do_plug_video_transcoding(builder, input_format, output_format, _enforce_transcoding?) do
builder
|> maybe_plug_parser_and_decoder(input_format)
|> maybe_plug_encoder_and_parser(output_format)
end
defp maybe_plug_parser_and_decoder(builder, %H264{}) do
builder
|> child(:h264_input_parser, %H264.Parser{
output_stream_structure: :annexb,
output_alignment: :au
})
|> child(:h264_decoder, %H264.FFmpeg.Decoder{})
end
defp maybe_plug_parser_and_decoder(builder, %H265{}) do
builder
|> child(:h265_input_parser, %H265.Parser{
output_stream_structure: :annexb,
output_alignment: :au
})
|> child(:h265_decoder, %H265.FFmpeg.Decoder{})
end
defp maybe_plug_parser_and_decoder(builder, %VP8{}) do
builder |> child(:vp8_decoder, %VP8.Decoder{})
end
defp maybe_plug_parser_and_decoder(builder, %RemoteStream{
content_format: VP8,
type: :packetized
}) do
builder |> child(:vp8_decoder, %VP8.Decoder{})
end
defp maybe_plug_parser_and_decoder(builder, %RawVideo{}) do
builder
end
defp maybe_plug_encoder_and_parser(builder, %H264{} = h264) do
builder
|> child(:h264_encoder, %H264.FFmpeg.Encoder{preset: :ultrafast})
|> child(:h264_output_parser, %H264.Parser{
output_stream_structure: stream_structure_type(h264),
output_alignment: h264.alignment
})
end
defp maybe_plug_encoder_and_parser(builder, %H265{} = h265) do
builder
|> child(:h265_encoder, %H265.FFmpeg.Encoder{preset: :ultrafast})
|> child(:h265_output_parser, %H265.Parser{
output_stream_structure: stream_structure_type(h265),
output_alignment: h265.alignment
})
end
defp maybe_plug_encoder_and_parser(builder, %VP8{}) do
builder |> child(:vp8_encoder, %VP8.Encoder{})
end
defp maybe_plug_encoder_and_parser(builder, %RawVideo{}) do
builder
end
defp stream_structure_type(%h26x{stream_structure: stream_structure})
when h26x in [H264, H265] do
case stream_structure do
type when type in [:annexb, :avc1, :avc3, :hvc1, :hev1] -> type
{type, _dcr} when type in [:avc1, :avc3, :hvc1, :hev1] -> type
end
end
end