Current section

Files

Jump to
membrane_vpx_plugin lib membrane_vpx decoder vpx_decoder.ex
Raw

lib/membrane_vpx/decoder/vpx_decoder.ex

defmodule Membrane.VPx.Decoder do
@moduledoc false
alias Membrane.{Buffer, RawVideo, RemoteStream, VP8, VP9}
alias Membrane.Element.CallbackContext
alias Membrane.VPx.Decoder.Native
defmodule State do
@moduledoc false
@type t :: %__MODULE__{
codec: :vp8 | :vp9,
width: pos_integer() | nil,
height: pos_integer() | nil,
framerate: {pos_integer(), pos_integer()} | nil,
decoder_ref: reference() | nil
}
@enforce_keys [:codec, :width, :height, :framerate]
defstruct @enforce_keys ++
[
decoder_ref: nil
]
end
@type callback_return :: {[Membrane.Element.Action.t()], State.t()}
@spec handle_init(CallbackContext.t(), VP8.Decoder.t() | VP9.Decoder.t(), :vp8 | :vp9) ::
callback_return()
def handle_init(_ctx, opts, codec) do
state_fields =
opts
|> Map.take([:width, :height, :framerate])
|> Map.put(:codec, codec)
{[], struct(State, state_fields)}
end
@spec handle_setup(CallbackContext.t(), State.t()) :: callback_return()
def handle_setup(_ctx, state) do
native = Native.create!(state.codec)
{[], %{state | decoder_ref: native}}
end
@spec handle_stream_format(:input, term(), CallbackContext.t(), State.t()) :: callback_return()
def handle_stream_format(:input, _stream_format, _ctx, state) do
{[], state}
end
@spec handle_buffer(:input, Membrane.Buffer.t(), CallbackContext.t(), State.t()) ::
callback_return()
def handle_buffer(:input, %Buffer{payload: payload, pts: pts}, ctx, state) do
{:ok, [decoded_frame], pixel_format} = Native.decode_frame(payload, state.decoder_ref)
stream_format_action =
if ctx.pads.output.stream_format == nil do
output_stream_format =
get_output_stream_format(ctx.pads.input.stream_format, pixel_format, state)
[stream_format: {:output, output_stream_format}]
else
[]
end
{stream_format_action ++ [buffer: {:output, %Buffer{payload: decoded_frame, pts: pts}}],
state}
end
@spec get_output_stream_format(
RemoteStream.t() | VP8.t() | VP9.t(),
RawVideo.pixel_format(),
State.t()
) :: RawVideo.t()
defp get_output_stream_format(input_stream_format, pixel_format, state) do
{width, height, framerate} =
case input_stream_format do
%RemoteStream{} ->
{
state.width || raise("Width not provided"),
state.height || raise("Height not provided"),
state.framerate
}
%{width: width, height: height} ->
{
width,
height,
state.framerate
}
end
%RawVideo{
width: width,
height: height,
framerate: framerate,
pixel_format: pixel_format,
aligned: true
}
end
end