From cc7676b968ab911473d3bf7e3f94df63a7aabb25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kita?= Date: Wed, 26 Feb 2025 15:31:43 +0100 Subject: [PATCH] Add cpu_used and g_threads options --- c_src/membrane_vpx_plugin/vpx_encoder.c | 9 ++++++++ .../membrane_vpx_plugin/vpx_encoder.spec.exs | 4 +++- lib/membrane_vpx/encoder/vp8_encoder.ex | 18 ++++++++++++++++ lib/membrane_vpx/encoder/vp9_encoder.ex | 18 ++++++++++++++++ lib/membrane_vpx/encoder/vpx_encoder.ex | 21 ++++++++++++------- .../encoder/vpx_encoder_native.ex | 21 +++++++++++++++++-- 6 files changed, 81 insertions(+), 10 deletions(-) diff --git a/c_src/membrane_vpx_plugin/vpx_encoder.c b/c_src/membrane_vpx_plugin/vpx_encoder.c index a06c48b..11b46ab 100644 --- a/c_src/membrane_vpx_plugin/vpx_encoder.c +++ b/c_src/membrane_vpx_plugin/vpx_encoder.c @@ -31,6 +31,7 @@ vpx_img_fmt_t translate_pixel_format(PixelFormat pixel_format) { void apply_user_encoder_config(vpx_codec_enc_cfg_t *config, user_encoder_config *user_config) { config->g_lag_in_frames = user_config->g_lag_in_frames; config->rc_target_bitrate = user_config->rc_target_bitrate; + config->g_threads = user_config->g_threads; } UNIFEX_TERM create( @@ -40,6 +41,7 @@ UNIFEX_TERM create( unsigned int height, PixelFormat pixel_format, unsigned int encoding_deadline, + unsigned int cpu_used, user_encoder_config user_config ) { UNIFEX_TERM result; @@ -72,6 +74,13 @@ UNIFEX_TERM create( if (vpx_codec_enc_init(&state->codec_context, state->codec_interface, &config, 0)) { return result_error(env, "Failed to initialize encoder", create_result_error, NULL, state); } + + vpx_codec_err_t res = vpx_codec_control(&state->codec_context, VP8E_SET_CPUUSED, cpu_used); // VP8E_SET_CPUUSED + // is valid for both VP8 and VP9 codecs ¯\_(ツ)_/¯ + if(res != VPX_CODEC_OK){ + return result_error(env, "Failed to set codec control cpu-used parameter", create_result_error, NULL, state); + } + if (!vpx_img_alloc(&state->img, translate_pixel_format(pixel_format), width, height, 1)) { return result_error( env, "Failed to allocate image", create_result_error, &state->codec_context, state diff --git a/c_src/membrane_vpx_plugin/vpx_encoder.spec.exs b/c_src/membrane_vpx_plugin/vpx_encoder.spec.exs index fa76553..2664794 100644 --- a/c_src/membrane_vpx_plugin/vpx_encoder.spec.exs +++ b/c_src/membrane_vpx_plugin/vpx_encoder.spec.exs @@ -14,7 +14,8 @@ type encoded_frame :: %EncodedFrame{ type user_encoder_config :: %UserEncoderConfig{ g_lag_in_frames: unsigned, - rc_target_bitrate: unsigned + rc_target_bitrate: unsigned, + g_threads: unsigned } spec create( @@ -23,6 +24,7 @@ spec create( height :: unsigned, pixel_format, encoding_deadline :: unsigned, + cpu_used :: unsigned, user_encoder_config ) :: {:ok :: label, state} | {:error :: label, reason :: atom} diff --git a/lib/membrane_vpx/encoder/vp8_encoder.ex b/lib/membrane_vpx/encoder/vp8_encoder.ex index 9cb369d..3225981 100644 --- a/lib/membrane_vpx/encoder/vp8_encoder.ex +++ b/lib/membrane_vpx/encoder/vp8_encoder.ex @@ -50,6 +50,24 @@ defmodule Membrane.VP8.Encoder do Note that this is a maximum value -- the encoder may produce frames sooner than the given limit. If set to 0 this feature will be disabled. """ + ], + cpu_used: [ + spec: non_neg_integer(), + default: 0, + description: """ + A parameter used to balance between compression and performance. + + Setting a lower value increases the encoding time but improves the quality and compression efficiency of the + output video. Setting a higher value speeds up the encoding at the cost of lower quality and large file sizes. + The parameter needs to be in range 0-15. + """ + ], + g_threads: [ + spec: pos_integer(), + default: 1, + description: """ + Specifies how many OS threads can be used by the encoder. + """ ] def_input_pad :input, diff --git a/lib/membrane_vpx/encoder/vp9_encoder.ex b/lib/membrane_vpx/encoder/vp9_encoder.ex index 07c2eab..3788652 100644 --- a/lib/membrane_vpx/encoder/vp9_encoder.ex +++ b/lib/membrane_vpx/encoder/vp9_encoder.ex @@ -50,6 +50,24 @@ defmodule Membrane.VP9.Encoder do Note that this is a maximum value -- the encoder may produce frames sooner than the given limit. If set to 0 this feature will be disabled. """ + ], + cpu_used: [ + spec: non_neg_integer(), + default: 0, + description: """ + A parameter used to balance between compression and performance. + + Setting a lower value increases the encoding time but improves the quality and compression efficiency of the + output video. Setting a higher value speeds up the encoding at the cost of lower quality and large file sizes. + The parameter needs to be in range 0-15. + """ + ], + g_threads: [ + spec: pos_integer(), + default: 1, + description: """ + Specifies how many OS threads can be used by the encoder. + """ ] def_input_pad :input, diff --git a/lib/membrane_vpx/encoder/vpx_encoder.ex b/lib/membrane_vpx/encoder/vpx_encoder.ex index 58bafe3..bd45b2f 100644 --- a/lib/membrane_vpx/encoder/vpx_encoder.ex +++ b/lib/membrane_vpx/encoder/vpx_encoder.ex @@ -10,11 +10,13 @@ defmodule Membrane.VPx.Encoder do @type unprocessed_user_encoder_config :: %{ g_lag_in_frames: non_neg_integer(), - rc_target_bitrate: pos_integer() | :auto + rc_target_bitrate: pos_integer() | :auto, + g_threads: pos_integer() } @type user_encoder_config :: %{ g_lag_in_frames: non_neg_integer(), - rc_target_bitrate: pos_integer() + rc_target_bitrate: pos_integer(), + g_threads: pos_integer() } @type encoded_frame :: %{payload: binary(), pts: non_neg_integer(), is_keyframe: boolean()} @@ -28,10 +30,11 @@ defmodule Membrane.VPx.Encoder do encoding_deadline: non_neg_integer() | :auto, user_encoder_config: Membrane.VPx.Encoder.unprocessed_user_encoder_config(), encoder_ref: reference() | nil, - force_next_keyframe: boolean() + force_next_keyframe: boolean(), + cpu_used: non_neg_integer() } - @enforce_keys [:codec, :codec_module, :encoding_deadline, :user_encoder_config] + @enforce_keys [:codec, :codec_module, :encoding_deadline, :user_encoder_config, :cpu_used] defstruct @enforce_keys ++ [ encoder_ref: nil, @@ -54,8 +57,10 @@ defmodule Membrane.VPx.Encoder do encoding_deadline: opts.encoding_deadline, user_encoder_config: %{ g_lag_in_frames: opts.g_lag_in_frames, - rc_target_bitrate: opts.rc_target_bitrate - } + rc_target_bitrate: opts.rc_target_bitrate, + g_threads: opts.g_threads + }, + cpu_used: opts.cpu_used } {[], state} @@ -141,6 +146,7 @@ defmodule Membrane.VPx.Encoder do height, pixel_format, encoding_deadline, + state.cpu_used, user_encoder_config ) @@ -165,7 +171,8 @@ defmodule Membrane.VPx.Encoder do %{ g_lag_in_frames: user_encoder_config.g_lag_in_frames, - rc_target_bitrate: rc_target_bitrate + rc_target_bitrate: rc_target_bitrate, + g_threads: user_encoder_config.g_threads } end diff --git a/lib/membrane_vpx/encoder/vpx_encoder_native.ex b/lib/membrane_vpx/encoder/vpx_encoder_native.ex index 5566bff..bc772d6 100644 --- a/lib/membrane_vpx/encoder/vpx_encoder_native.ex +++ b/lib/membrane_vpx/encoder/vpx_encoder_native.ex @@ -8,10 +8,27 @@ defmodule Membrane.VPx.Encoder.Native do pos_integer(), Membrane.RawVideo.pixel_format(), non_neg_integer(), + non_neg_integer(), Membrane.VPx.Encoder.user_encoder_config() ) :: reference() - def create!(codec, width, height, pixel_format, encoding_deadline, user_encoder_config) do - case create(codec, width, height, pixel_format, encoding_deadline, user_encoder_config) do + def create!( + codec, + width, + height, + pixel_format, + encoding_deadline, + cpu_used, + user_encoder_config + ) do + case create( + codec, + width, + height, + pixel_format, + encoding_deadline, + cpu_used, + user_encoder_config + ) do {:ok, decoder_ref} -> decoder_ref {:error, reason} -> raise "Failed to create native encoder: #{inspect(reason)}" end