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

Handle keyframe request it in the encoder and use x264 defaults #111

Merged
merged 10 commits into from
Jul 10, 2024
Merged
15 changes: 14 additions & 1 deletion c_src/membrane_h264_ffmpeg_plugin/encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ UNIFEX_TERM create(UnifexEnv *env, int width, int height, char *pix_fmt,

av_dict_set_int(&params, "sc_threshold", sc_threshold, 0);

av_dict_set(&params, "qcomp", "0.6", 0);
av_dict_set(&params, "me_range", "16", 0);
av_dict_set(&params, "qdiff", "4", 0);
av_dict_set(&params, "qmin", "0", 0);
av_dict_set(&params, "qmax", "69", 0);
av_dict_set(&params, "i_qfactor", "1.4", 0);
av_dict_set(&params, "f_pb_factor", "1.3", 0);
av_dict_set(&params, "partitions", "p8x8,b8x8,i8x8,i4x4", 0);
av_dict_set(&params, "subq", "2", 0);

if (avcodec_open2(state->codec_ctx, codec, &params) < 0) {
res = create_result_error(env, "codec_open");
goto exit_create;
Expand Down Expand Up @@ -153,7 +163,7 @@ static int get_frames(UnifexEnv *env, AVFrame *frame,
}

UNIFEX_TERM encode(UnifexEnv *env, UnifexPayload *payload, int64_t pts,
int use_shm, State *state) {
int use_shm, int keyframe_requested, State *state) {
UNIFEX_TERM res_term;
int res = 0;
int max_frames = 16, frame_cnt = 0;
Expand All @@ -165,6 +175,9 @@ UNIFEX_TERM encode(UnifexEnv *env, UnifexPayload *payload, int64_t pts,
frame->format = state->codec_ctx->pix_fmt;
frame->width = state->codec_ctx->width;
frame->height = state->codec_ctx->height;
if(keyframe_requested) {
frame->pict_type = AV_PICTURE_TYPE_I;
}
av_image_fill_arrays(frame->data, frame->linesize, payload->data,
frame->format, frame->width, frame->height, 1);

Expand Down
2 changes: 1 addition & 1 deletion c_src/membrane_h264_ffmpeg_plugin/encoder.spec.exs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ spec create(

spec get_frame_size(state) :: {:ok :: label, frame_size :: int} | {:error :: label}

spec encode(payload, pts :: int64, use_shm :: bool, state) ::
spec encode(payload, pts :: int64, use_shm :: bool, keyframe_requested :: bool, state) ::
{:ok :: label, dts_list :: [int64], pts_list :: [int64], [payload]}
| {:error :: label, reason :: atom}

Expand Down
19 changes: 18 additions & 1 deletion lib/membrane_h264_ffmpeg/encoder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ defmodule Membrane.H264.FFmpeg.Encoder do
state =
opts
|> Map.put(:encoder_ref, nil)
|> Map.put(:keyframe_requested?, false)

{[], state}
end
Expand All @@ -141,12 +142,13 @@ defmodule Membrane.H264.FFmpeg.Encoder do
buffer.payload,
pts,
use_shm?,
state.keyframe_requested?,
encoder_ref
) do
{:ok, dts_list, pts_list, frames} ->
bufs = wrap_frames(dts_list, pts_list, frames)

{bufs, state}
{bufs, %{state | keyframe_requested?: false}}

{:error, reason} ->
raise "Native encoder failed to encode the payload: #{inspect(reason)}"
Expand Down Expand Up @@ -194,6 +196,21 @@ defmodule Membrane.H264.FFmpeg.Encoder do
{actions, 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
{[], %{state | keyframe_requested?: true}}
end

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

defp flush_encoder_if_exists(%{encoder_ref: nil}), do: []

defp flush_encoder_if_exists(%{encoder_ref: encoder_ref, use_shm?: use_shm?}) do
Expand Down
3 changes: 2 additions & 1 deletion test/encoder/encoder_native_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ defmodule Encoder.NativeTest do
Enc.encode(
frame,
Common.to_h264_time_base_truncated(seconds(timestamp)),
false,
_use_shm? = false,
_keyframe_requested? = false,
ref
)
end
Expand Down