lib/turbojpeg/filter.ex

defmodule Turbojpeg.Filter do
  @moduledoc """
  Membrane filter converting raw video frames to JPEG.
  """
  use Membrane.Filter

  alias Membrane.Buffer
  alias Membrane.RawVideo
  alias Membrane.RemoteStream

  def_input_pad :input,
    flow_control: :auto,
    accepted_format: %RawVideo{pixel_format: pix_fmt} when pix_fmt in [:I420, :I422, :I444]

  # TODO: implement JPEG stream format
  def_output_pad :output, flow_control: :auto, accepted_format: RemoteStream

  def_options quality: [
                spec: Turbojpeg.quality(),
                default: 75,
                description: "Jpeg encoding quality"
              ]

  @impl true
  def handle_init(_ctx, options) do
    {[], Map.from_struct(options)}
  end

  @impl true
  def handle_stream_format(:input, _stream_format, _ctx, state) do
    {[stream_format: {:output, %RemoteStream{type: :bytestream}}], state}
  end

  @impl true
  def handle_buffer(:input, %Buffer{payload: payload} = buffer, ctx, state) do
    %{stream_format: stream_format} = ctx.pads.input
    %{width: width, height: height, pixel_format: pix_fmt} = stream_format

    case Turbojpeg.yuv_to_jpeg(payload, width, height, state.quality, pix_fmt) do
      {:ok, jpeg} ->
        {[buffer: {:output, %Buffer{buffer | payload: jpeg}}], state}

      error ->
        raise """
        could not create JPEG image
        #{inspect(error)}
        """
    end
  end
end