Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for requesting keyframes #199

3 changes: 3 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ workflows:
build:
jobs:
- elixir/build_test:
cache-version: 2
filters: &filters
tags:
only: /v.*/
- elixir/test:
cache-version: 2
filters:
<<: *filters
- elixir/lint:
cache-version: 2
filters:
<<: *filters
- elixir/hex_publish:
Expand Down
43 changes: 29 additions & 14 deletions lib/membrane/live_compositor/live_compositor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -597,21 +597,10 @@ defmodule Membrane.LiveCompositor do
Request.UnregisterInput,
Request.UnregisterOutput,
Request.UpdateVideoOutput,
Request.UpdateAudioOutput
Request.UpdateAudioOutput,
Request.KeyframeRequest
] do
response =
IntoRequest.into_request(req)
|> ApiClient.send_request(state.lc_port)

case response do
{:error, exception} ->
Membrane.Logger.error(
"LiveCompositor failed to send a request: #{inspect(req)}.\nException: #{inspect(exception)}."
)

{:ok, _result} ->
nil
end
response = handle_request(req, state.lc_port)

{[notify_parent: {:request_result, req, response}], state}
end
Expand Down Expand Up @@ -685,6 +674,13 @@ defmodule Membrane.LiveCompositor do
{[notify_parent: {:output_registered, pad_ref, state.context}], state}
end

@impl true
def handle_child_notification(:keyframe_request, {:output_processor, pad_id}, _ctx, state) do
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine, but I would probably send Request.KeyframeRequest from the output processor

handle_request(%Request.KeyframeRequest{output_id: pad_id}, state.lc_port)

{[], state}
end

@impl true
def handle_child_notification(msg, child, _ctx, state) do
Membrane.Logger.debug(
Expand Down Expand Up @@ -767,4 +763,23 @@ defmodule Membrane.LiveCompositor do
defp output_group_id(output_id) do
"output_group_#{output_id}"
end

@spec handle_request(Request.t(), :inet.port_number()) :: ApiClient.request_result()
defp handle_request(req, lc_port) do
response =
IntoRequest.into_request(req)
|> ApiClient.send_request(lc_port)

case response do
{:error, exception} ->
Membrane.Logger.error(
"LiveCompositor failed to send a request: #{inspect(req)}.\nException: #{inspect(exception)}."
)

{:ok, _result} ->
nil
end

response
end
end
20 changes: 19 additions & 1 deletion lib/membrane/live_compositor/output_processor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ defmodule Membrane.LiveCompositor.VideoOutputProcessor do

@impl true
def handle_init(_ctx, opt) do
{[], %{output_stream_format: opt.output_stream_format}}
{[],
%{
output_stream_format: opt.output_stream_format
}}
end

@impl true
Expand All @@ -31,6 +34,21 @@ defmodule Membrane.LiveCompositor.VideoOutputProcessor do
def handle_stream_format(_pad, _stream_format, _ctx, state) do
{[stream_format: {:output, state.output_stream_format}], state}
end

@impl true
def handle_event(:input, event, _ctx, state) do
{[event: {:output, event}], state}
end

@impl true
def handle_event(:output, %Membrane.KeyframeRequestEvent{}, _ctx, state) do
{[notify_parent: :keyframe_request], state}
end

@impl true
def handle_event(:output, event, _ctx, state) do
{[event: {:input, event}], state}
end
end

defmodule Membrane.LiveCompositor.AudioOutputProcessor do
Expand Down
25 changes: 25 additions & 0 deletions lib/membrane/live_compositor/request.ex
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,30 @@ defmodule Membrane.LiveCompositor.Request do
end
end

defmodule KeyframeRequest do
@moduledoc """
Request to trigger additional keyframe generation for a specified output.
"""

@enforce_keys [:output_id]
defstruct @enforce_keys

@typedoc """
- `:output_id` - Id of the output for which additional keyframe should be generated.
"""
@type t :: %__MODULE__{
output_id: Membrane.LiveCompositor.output_id()
}
end

defimpl ApiClient.IntoRequest, for: KeyframeRequest do
@spec into_request(KeyframeRequest.t()) :: ApiClient.request()
def into_request(request) do
encoded_id = URI.encode_www_form(request.output_id)
{:post, "/api/output/#{encoded_id}/request_keyframe", %{}}
end
end

@type t ::
RegisterImage.t()
| RegisterShader.t()
Expand All @@ -295,6 +319,7 @@ defmodule Membrane.LiveCompositor.Request do
| UnregisterOutput.t()
| UpdateVideoOutput.t()
| UpdateAudioOutput.t()
| KeyframeRequest.t()

@type result :: {:request_result, t(), {:ok, any()} | {:error, any()}}
end
Loading