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 = send_req(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

send_req(%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 send_req(Request.t(), :inet.port_number()) :: ApiClient.request_result()
defp send_req(req, lc_port) do
WojciechBarczynski marked this conversation as resolved.
Show resolved Hide resolved
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
22 changes: 21 additions & 1 deletion lib/membrane/live_compositor/output_processor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ defmodule Membrane.LiveCompositor.VideoOutputProcessor do

use Membrane.Filter

require Membrane.Logger

WojciechBarczynski marked this conversation as resolved.
Show resolved Hide resolved
def_options output_stream_format: [
spec: Membrane.H264.t()
]
Expand All @@ -19,7 +21,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 +36,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