lib/membrane/video_compositor/scene.ex

defmodule Membrane.VideoCompositor.Scene do
  @moduledoc """
  Structure representing a top level specification of what is Video Compositor
  supposed to render.
  """

  alias Membrane.Pad
  alias Membrane.VideoCompositor.Scene
  alias Membrane.VideoCompositor.VideoConfig

  @enforce_keys [:video_configs]
  defstruct @enforce_keys

  @typedoc """
  Specify how output frame should look like.

  If input pad isn't specified in `video_configs` it won't be used in composition.
  """
  @type t :: %__MODULE__{
          video_configs: %{Pad.ref() => VideoConfig.t()}
        }

  @spec empty() :: t()
  def empty() do
    %Scene{video_configs: %{}}
  end

  @spec pads(t()) :: MapSet.t()
  def pads(%__MODULE__{video_configs: video_configs}) do
    video_configs
    |> MapSet.new(fn {pad, _video_config} -> pad end)
  end

  @spec validate(t(), MapSet.t(), boolean()) :: :ok
  def validate(
        scene = %__MODULE__{video_configs: video_configs},
        input_pads,
        check_empty? \\ true
      ) do
    scene_pads = Scene.pads(scene)

    if check_empty? and video_configs == %{} do
      raise """
      The scene must contain at least one video config.
      Scene: #{inspect(scene)}
      Input pads: #{inspect(MapSet.to_list(input_pads))}
      """
    end

    unless MapSet.subset?(scene_pads, input_pads) do
      raise """
      The scene must include references only to VideoCompositor input pads.
      Scene: #{inspect(scene)}
      Scene pads: #{inspect(MapSet.to_list(scene_pads))}
      Input pads: #{inspect(MapSet.to_list(input_pads))}
      """
    end

    _checked_video_configs =
      video_configs
      |> Map.to_list()
      |> Enum.map(fn {pad, video_config} ->
        case video_config do
          %VideoConfig{} ->
            :ok

          _else ->
            raise """
            The scene must include only #{inspect(VideoConfig)} structs.
            Scene: #{inspect(scene)}
            Video config for pad: #{inspect(pad)} has improper config: #{inspect(video_config)}
            """
        end
      end)

    :ok
  end
end