diff options
author | Sebastian Dröge <sebastian.droege@collabora.co.uk> | 2012-09-17 09:16:39 +0200 |
---|---|---|
committer | Sebastian Dröge <sebastian.droege@collabora.co.uk> | 2012-09-17 09:29:26 +0200 |
commit | 481503670836d764a545cb5a32346e8bda5b5f3d (patch) | |
tree | f3cf3d3faa127402bb7b621bc4fcc9e64f2e6fe0 /ext | |
parent | 8ed85c7538593de6728223a187af0078db64f772 (diff) |
vp8enc: Store configuration in the vpx_codec_enc_cfg_t struct instead of duplicating all variables
Also protect encoder with a mutex.
Diffstat (limited to 'ext')
-rw-r--r-- | ext/vpx/gstvp8enc.c | 321 | ||||
-rw-r--r-- | ext/vpx/gstvp8enc.h | 54 |
2 files changed, 181 insertions, 194 deletions
diff --git a/ext/vpx/gstvp8enc.c b/ext/vpx/gstvp8enc.c index b828ae2c7..804617926 100644 --- a/ext/vpx/gstvp8enc.c +++ b/ext/vpx/gstvp8enc.c @@ -700,40 +700,53 @@ gst_vp8_enc_class_init (GstVP8EncClass * klass) static void gst_vp8_enc_init (GstVP8Enc * gst_vp8_enc) { + vpx_codec_err_t status; GST_DEBUG_OBJECT (gst_vp8_enc, "init"); - gst_vp8_enc->rc_end_usage = DEFAULT_RC_END_USAGE; - gst_vp8_enc->rc_target_bitrate = DEFAULT_RC_TARGET_BITRATE; + status = + vpx_codec_enc_config_default (&vpx_codec_vp8_cx_algo, &gst_vp8_enc->cfg, + 0); + if (status != VPX_CODEC_OK) { + GST_ERROR_OBJECT (gst_vp8_enc, + "Failed to get default encoder configuration: %s", + gst_vpx_error_name (status)); + gst_vp8_enc->have_default_config = FALSE; + } else { + gst_vp8_enc->have_default_config = TRUE; + } + + gst_vp8_enc->cfg.rc_end_usage = DEFAULT_RC_END_USAGE; + gst_vp8_enc->cfg.rc_target_bitrate = DEFAULT_RC_TARGET_BITRATE; gst_vp8_enc->rc_target_bitrate_set = FALSE; - gst_vp8_enc->rc_min_quantizer = DEFAULT_RC_MIN_QUANTIZER; - gst_vp8_enc->rc_max_quantizer = DEFAULT_RC_MAX_QUANTIZER; - gst_vp8_enc->rc_dropframe_thresh = DEFAULT_RC_DROPFRAME_THRESH; - gst_vp8_enc->rc_resize_allowed = DEFAULT_RC_RESIZE_ALLOWED; - gst_vp8_enc->rc_resize_up_thresh = DEFAULT_RC_RESIZE_UP_THRESH; - gst_vp8_enc->rc_resize_down_thresh = DEFAULT_RC_RESIZE_DOWN_THRESH; - gst_vp8_enc->rc_undershoot_pct = DEFAULT_RC_UNDERSHOOT_PCT; - gst_vp8_enc->rc_overshoot_pct = DEFAULT_RC_OVERSHOOT_PCT; - gst_vp8_enc->rc_buf_sz = DEFAULT_RC_BUF_SZ; - gst_vp8_enc->rc_buf_initial_sz = DEFAULT_RC_BUF_INITIAL_SZ; - gst_vp8_enc->rc_buf_optimal_sz = DEFAULT_RC_BUF_OPTIMAL_SZ; - gst_vp8_enc->rc_2pass_vbr_bias_pct = DEFAULT_RC_2PASS_VBR_BIAS_PCT; - gst_vp8_enc->rc_2pass_vbr_minsection_pct = + gst_vp8_enc->cfg.rc_min_quantizer = DEFAULT_RC_MIN_QUANTIZER; + gst_vp8_enc->cfg.rc_max_quantizer = DEFAULT_RC_MAX_QUANTIZER; + gst_vp8_enc->cfg.rc_dropframe_thresh = DEFAULT_RC_DROPFRAME_THRESH; + gst_vp8_enc->cfg.rc_resize_allowed = DEFAULT_RC_RESIZE_ALLOWED; + gst_vp8_enc->cfg.rc_resize_up_thresh = DEFAULT_RC_RESIZE_UP_THRESH; + gst_vp8_enc->cfg.rc_resize_down_thresh = DEFAULT_RC_RESIZE_DOWN_THRESH; + gst_vp8_enc->cfg.rc_undershoot_pct = DEFAULT_RC_UNDERSHOOT_PCT; + gst_vp8_enc->cfg.rc_overshoot_pct = DEFAULT_RC_OVERSHOOT_PCT; + gst_vp8_enc->cfg.rc_buf_sz = DEFAULT_RC_BUF_SZ; + gst_vp8_enc->cfg.rc_buf_initial_sz = DEFAULT_RC_BUF_INITIAL_SZ; + gst_vp8_enc->cfg.rc_buf_optimal_sz = DEFAULT_RC_BUF_OPTIMAL_SZ; + gst_vp8_enc->cfg.rc_2pass_vbr_bias_pct = DEFAULT_RC_2PASS_VBR_BIAS_PCT; + gst_vp8_enc->cfg.rc_2pass_vbr_minsection_pct = DEFAULT_RC_2PASS_VBR_MINSECTION_PCT; - gst_vp8_enc->rc_2pass_vbr_maxsection_pct = + gst_vp8_enc->cfg.rc_2pass_vbr_maxsection_pct = DEFAULT_RC_2PASS_VBR_MAXSECTION_PCT; - gst_vp8_enc->kf_mode = DEFAULT_KF_MODE; - gst_vp8_enc->kf_max_dist = DEFAULT_KF_MAX_DIST; - gst_vp8_enc->multipass_mode = DEFAULT_MULTIPASS_MODE; + gst_vp8_enc->cfg.kf_mode = DEFAULT_KF_MODE; + gst_vp8_enc->cfg.kf_max_dist = DEFAULT_KF_MAX_DIST; + gst_vp8_enc->cfg.g_pass = DEFAULT_MULTIPASS_MODE; gst_vp8_enc->multipass_cache_file = g_strdup (DEFAULT_MULTIPASS_CACHE_FILE); - gst_vp8_enc->ts_number_layers = DEFAULT_TS_NUMBER_LAYERS; + gst_vp8_enc->cfg.ts_number_layers = DEFAULT_TS_NUMBER_LAYERS; gst_vp8_enc->n_ts_target_bitrate = 0; gst_vp8_enc->n_ts_rate_decimator = 0; - gst_vp8_enc->ts_periodicity = DEFAULT_TS_PERIODICITY; + gst_vp8_enc->cfg.ts_periodicity = DEFAULT_TS_PERIODICITY; gst_vp8_enc->n_ts_layer_id = 0; - gst_vp8_enc->error_resilient = DEFAULT_ERROR_RESILIENT; - gst_vp8_enc->lag_in_frames = DEFAULT_LAG_IN_FRAMES; - gst_vp8_enc->threads = DEFAULT_THREADS; + gst_vp8_enc->cfg.g_error_resilient = DEFAULT_ERROR_RESILIENT; + gst_vp8_enc->cfg.g_lag_in_frames = DEFAULT_LAG_IN_FRAMES; + gst_vp8_enc->cfg.g_threads = DEFAULT_THREADS; gst_vp8_enc->deadline = DEFAULT_DEADLINE; gst_vp8_enc->h_scaling_mode = DEFAULT_H_SCALING_MODE; gst_vp8_enc->v_scaling_mode = DEFAULT_V_SCALING_MODE; @@ -750,7 +763,9 @@ gst_vp8_enc_init (GstVP8Enc * gst_vp8_enc) gst_vp8_enc->cq_level = DEFAULT_CQ_LEVEL; gst_vp8_enc->max_intra_bitrate_pct = DEFAULT_MAX_INTRA_BITRATE_PCT; - gst_vp8_enc->profile = DEFAULT_PROFILE; + gst_vp8_enc->cfg.g_profile = DEFAULT_PROFILE; + + g_mutex_init (&gst_vp8_enc->encoder_lock); } static void @@ -769,6 +784,8 @@ gst_vp8_enc_finalize (GObject * object) if (gst_vp8_enc->input_state) gst_video_codec_state_unref (gst_vp8_enc->input_state); + g_mutex_clear (&gst_vp8_enc->encoder_lock); + G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -783,64 +800,65 @@ gst_vp8_enc_set_property (GObject * object, guint prop_id, gst_vp8_enc = GST_VP8_ENC (object); GST_DEBUG_OBJECT (object, "gst_vp8_enc_set_property"); + g_mutex_lock (&gst_vp8_enc->encoder_lock); switch (prop_id) { case PROP_RC_END_USAGE: - gst_vp8_enc->rc_end_usage = g_value_get_enum (value); + gst_vp8_enc->cfg.rc_end_usage = g_value_get_enum (value); break; case PROP_RC_TARGET_BITRATE: - gst_vp8_enc->rc_target_bitrate = g_value_get_int (value); + gst_vp8_enc->cfg.rc_target_bitrate = g_value_get_int (value) / 1000; gst_vp8_enc->rc_target_bitrate_set = TRUE; break; case PROP_RC_MIN_QUANTIZER: - gst_vp8_enc->rc_min_quantizer = g_value_get_int (value); + gst_vp8_enc->cfg.rc_min_quantizer = g_value_get_int (value); break; case PROP_RC_MAX_QUANTIZER: - gst_vp8_enc->rc_max_quantizer = g_value_get_int (value); + gst_vp8_enc->cfg.rc_max_quantizer = g_value_get_int (value); break; case PROP_RC_DROPFRAME_THRESH: - gst_vp8_enc->rc_dropframe_thresh = g_value_get_int (value); + gst_vp8_enc->cfg.rc_dropframe_thresh = g_value_get_int (value); break; case PROP_RC_RESIZE_ALLOWED: - gst_vp8_enc->rc_resize_allowed = g_value_get_boolean (value); + gst_vp8_enc->cfg.rc_resize_allowed = g_value_get_boolean (value); break; case PROP_RC_RESIZE_UP_THRESH: - gst_vp8_enc->rc_resize_up_thresh = g_value_get_int (value); + gst_vp8_enc->cfg.rc_resize_up_thresh = g_value_get_int (value); break; case PROP_RC_RESIZE_DOWN_THRESH: - gst_vp8_enc->rc_resize_down_thresh = g_value_get_int (value); + gst_vp8_enc->cfg.rc_resize_down_thresh = g_value_get_int (value); break; case PROP_RC_UNDERSHOOT_PCT: - gst_vp8_enc->rc_undershoot_pct = g_value_get_int (value); + gst_vp8_enc->cfg.rc_undershoot_pct = g_value_get_int (value); break; case PROP_RC_OVERSHOOT_PCT: - gst_vp8_enc->rc_overshoot_pct = g_value_get_int (value); + gst_vp8_enc->cfg.rc_overshoot_pct = g_value_get_int (value); break; case PROP_RC_BUF_SZ: - gst_vp8_enc->rc_buf_sz = g_value_get_int (value); + gst_vp8_enc->cfg.rc_buf_sz = g_value_get_int (value); break; case PROP_RC_BUF_INITIAL_SZ: - gst_vp8_enc->rc_buf_initial_sz = g_value_get_int (value); + gst_vp8_enc->cfg.rc_buf_initial_sz = g_value_get_int (value); break; case PROP_RC_BUF_OPTIMAL_SZ: - gst_vp8_enc->rc_buf_optimal_sz = g_value_get_int (value); + gst_vp8_enc->cfg.rc_buf_optimal_sz = g_value_get_int (value); break; case PROP_RC_2PASS_VBR_BIAS_PCT: - gst_vp8_enc->rc_2pass_vbr_bias_pct = g_value_get_int (value); + gst_vp8_enc->cfg.rc_2pass_vbr_bias_pct = g_value_get_int (value); break; case PROP_RC_2PASS_VBR_MINSECTION_PCT: - gst_vp8_enc->rc_2pass_vbr_minsection_pct = g_value_get_int (value); + gst_vp8_enc->cfg.rc_2pass_vbr_minsection_pct = g_value_get_int (value); break; case PROP_RC_2PASS_VBR_MAXSECTION_PCT: - gst_vp8_enc->rc_2pass_vbr_maxsection_pct = g_value_get_int (value); + gst_vp8_enc->cfg.rc_2pass_vbr_maxsection_pct = g_value_get_int (value); break; case PROP_KF_MODE: - gst_vp8_enc->kf_mode = g_value_get_enum (value); + gst_vp8_enc->cfg.kf_mode = g_value_get_enum (value); break; case PROP_KF_MAX_DIST: - gst_vp8_enc->kf_max_dist = g_value_get_int (value); + gst_vp8_enc->cfg.kf_max_dist = g_value_get_int (value); break; case PROP_MULTIPASS_MODE: - gst_vp8_enc->multipass_mode = g_value_get_enum (value); + gst_vp8_enc->cfg.g_pass = g_value_get_enum (value); break; case PROP_MULTIPASS_CACHE_FILE: if (gst_vp8_enc->multipass_cache_file) @@ -848,11 +866,13 @@ gst_vp8_enc_set_property (GObject * object, guint prop_id, gst_vp8_enc->multipass_cache_file = g_value_dup_string (value); break; case PROP_TS_NUMBER_LAYERS: - gst_vp8_enc->ts_number_layers = g_value_get_int (value); + gst_vp8_enc->cfg.ts_number_layers = g_value_get_int (value); break; case PROP_TS_TARGET_BITRATE:{ GValueArray *va = g_value_get_boxed (value); + memset (&gst_vp8_enc->cfg.ts_target_bitrate, 0, + sizeof (gst_vp8_enc->cfg.ts_target_bitrate)); if (va->n_values > VPX_TS_MAX_LAYERS) { g_warning ("%s: Only %d layers allowed at maximum", GST_ELEMENT_NAME (gst_vp8_enc), VPX_TS_MAX_LAYERS); @@ -860,7 +880,7 @@ gst_vp8_enc_set_property (GObject * object, guint prop_id, gint i; for (i = 0; i < va->n_values; i++) - gst_vp8_enc->ts_target_bitrate[i] = + gst_vp8_enc->cfg.ts_target_bitrate[i] = g_value_get_int (g_value_array_get_nth (va, i)); gst_vp8_enc->n_ts_target_bitrate = va->n_values; } else { @@ -871,6 +891,8 @@ gst_vp8_enc_set_property (GObject * object, guint prop_id, case PROP_TS_RATE_DECIMATOR:{ GValueArray *va = g_value_get_boxed (value); + memset (&gst_vp8_enc->cfg.ts_rate_decimator, 0, + sizeof (gst_vp8_enc->cfg.ts_rate_decimator)); if (va->n_values > VPX_TS_MAX_LAYERS) { g_warning ("%s: Only %d layers allowed at maximum", GST_ELEMENT_NAME (gst_vp8_enc), VPX_TS_MAX_LAYERS); @@ -878,7 +900,7 @@ gst_vp8_enc_set_property (GObject * object, guint prop_id, gint i; for (i = 0; i < va->n_values; i++) - gst_vp8_enc->ts_rate_decimator[i] = + gst_vp8_enc->cfg.ts_rate_decimator[i] = g_value_get_int (g_value_array_get_nth (va, i)); gst_vp8_enc->n_ts_rate_decimator = va->n_values; } else { @@ -887,11 +909,13 @@ gst_vp8_enc_set_property (GObject * object, guint prop_id, break; } case PROP_TS_PERIODICITY: - gst_vp8_enc->ts_periodicity = g_value_get_int (value); + gst_vp8_enc->cfg.ts_periodicity = g_value_get_int (value); break; case PROP_TS_LAYER_ID:{ GValueArray *va = g_value_get_boxed (value); + memset (&gst_vp8_enc->cfg.ts_layer_id, 0, + sizeof (gst_vp8_enc->cfg.ts_layer_id)); if (va->n_values > VPX_TS_MAX_PERIODICITY) { g_warning ("%s: Only %d sized layer sequences allowed at maximum", GST_ELEMENT_NAME (gst_vp8_enc), VPX_TS_MAX_PERIODICITY); @@ -899,7 +923,7 @@ gst_vp8_enc_set_property (GObject * object, guint prop_id, gint i; for (i = 0; i < va->n_values; i++) - gst_vp8_enc->ts_layer_id[i] = + gst_vp8_enc->cfg.ts_layer_id[i] = g_value_get_int (g_value_array_get_nth (va, i)); gst_vp8_enc->n_ts_layer_id = va->n_values; } else { @@ -908,13 +932,13 @@ gst_vp8_enc_set_property (GObject * object, guint prop_id, break; } case PROP_ERROR_RESILIENT: - gst_vp8_enc->error_resilient = g_value_get_flags (value); + gst_vp8_enc->cfg.g_error_resilient = g_value_get_flags (value); break; case PROP_LAG_IN_FRAMES: - gst_vp8_enc->lag_in_frames = g_value_get_int (value); + gst_vp8_enc->cfg.g_lag_in_frames = g_value_get_int (value); break; case PROP_THREADS: - gst_vp8_enc->threads = g_value_get_int (value); + gst_vp8_enc->cfg.g_threads = g_value_get_int (value); break; case PROP_DEADLINE: gst_vp8_enc->deadline = g_value_get_int64 (value); @@ -964,6 +988,8 @@ gst_vp8_enc_set_property (GObject * object, guint prop_id, default: break; } + + g_mutex_unlock (&gst_vp8_enc->encoder_lock); } static void @@ -975,69 +1001,70 @@ gst_vp8_enc_get_property (GObject * object, guint prop_id, GValue * value, g_return_if_fail (GST_IS_VP8_ENC (object)); gst_vp8_enc = GST_VP8_ENC (object); + g_mutex_lock (&gst_vp8_enc->encoder_lock); switch (prop_id) { case PROP_RC_END_USAGE: - g_value_set_enum (value, gst_vp8_enc->rc_end_usage); + g_value_set_enum (value, gst_vp8_enc->cfg.rc_end_usage); break; case PROP_RC_TARGET_BITRATE: - g_value_set_int (value, gst_vp8_enc->rc_target_bitrate); + g_value_set_int (value, gst_vp8_enc->cfg.rc_target_bitrate * 1000); break; case PROP_RC_MIN_QUANTIZER: - g_value_set_int (value, gst_vp8_enc->rc_min_quantizer); + g_value_set_int (value, gst_vp8_enc->cfg.rc_min_quantizer); break; case PROP_RC_MAX_QUANTIZER: - g_value_set_int (value, gst_vp8_enc->rc_max_quantizer); + g_value_set_int (value, gst_vp8_enc->cfg.rc_max_quantizer); break; case PROP_RC_DROPFRAME_THRESH: - g_value_set_int (value, gst_vp8_enc->rc_dropframe_thresh); + g_value_set_int (value, gst_vp8_enc->cfg.rc_dropframe_thresh); break; case PROP_RC_RESIZE_ALLOWED: - g_value_set_boolean (value, gst_vp8_enc->rc_resize_allowed); + g_value_set_boolean (value, gst_vp8_enc->cfg.rc_resize_allowed); break; case PROP_RC_RESIZE_UP_THRESH: - g_value_set_int (value, gst_vp8_enc->rc_resize_up_thresh); + g_value_set_int (value, gst_vp8_enc->cfg.rc_resize_up_thresh); break; case PROP_RC_RESIZE_DOWN_THRESH: - g_value_set_int (value, gst_vp8_enc->rc_resize_down_thresh); + g_value_set_int (value, gst_vp8_enc->cfg.rc_resize_down_thresh); break; case PROP_RC_UNDERSHOOT_PCT: - g_value_set_int (value, gst_vp8_enc->rc_undershoot_pct); + g_value_set_int (value, gst_vp8_enc->cfg.rc_undershoot_pct); break; case PROP_RC_OVERSHOOT_PCT: - g_value_set_int (value, gst_vp8_enc->rc_overshoot_pct); + g_value_set_int (value, gst_vp8_enc->cfg.rc_overshoot_pct); break; case PROP_RC_BUF_SZ: - g_value_set_int (value, gst_vp8_enc->rc_buf_sz); + g_value_set_int (value, gst_vp8_enc->cfg.rc_buf_sz); break; case PROP_RC_BUF_INITIAL_SZ: - g_value_set_int (value, gst_vp8_enc->rc_buf_initial_sz); + g_value_set_int (value, gst_vp8_enc->cfg.rc_buf_initial_sz); break; case PROP_RC_BUF_OPTIMAL_SZ: - g_value_set_int (value, gst_vp8_enc->rc_buf_optimal_sz); + g_value_set_int (value, gst_vp8_enc->cfg.rc_buf_optimal_sz); break; case PROP_RC_2PASS_VBR_BIAS_PCT: - g_value_set_int (value, gst_vp8_enc->rc_2pass_vbr_bias_pct); + g_value_set_int (value, gst_vp8_enc->cfg.rc_2pass_vbr_bias_pct); break; case PROP_RC_2PASS_VBR_MINSECTION_PCT: - g_value_set_int (value, gst_vp8_enc->rc_2pass_vbr_minsection_pct); + g_value_set_int (value, gst_vp8_enc->cfg.rc_2pass_vbr_minsection_pct); break; case PROP_RC_2PASS_VBR_MAXSECTION_PCT: - g_value_set_int (value, gst_vp8_enc->rc_2pass_vbr_maxsection_pct); + g_value_set_int (value, gst_vp8_enc->cfg.rc_2pass_vbr_maxsection_pct); break; case PROP_KF_MODE: - g_value_set_enum (value, gst_vp8_enc->kf_mode); + g_value_set_enum (value, gst_vp8_enc->cfg.kf_mode); break; case PROP_KF_MAX_DIST: - g_value_set_int (value, gst_vp8_enc->kf_max_dist); + g_value_set_int (value, gst_vp8_enc->cfg.kf_max_dist); break; case PROP_MULTIPASS_MODE: - g_value_set_enum (value, gst_vp8_enc->multipass_mode); + g_value_set_enum (value, gst_vp8_enc->cfg.g_pass); break; case PROP_MULTIPASS_CACHE_FILE: g_value_set_string (value, gst_vp8_enc->multipass_cache_file); break; case PROP_TS_NUMBER_LAYERS: - g_value_set_int (value, gst_vp8_enc->ts_number_layers); + g_value_set_int (value, gst_vp8_enc->cfg.ts_number_layers); break; case PROP_TS_TARGET_BITRATE:{ GValueArray *va; @@ -1052,7 +1079,7 @@ gst_vp8_enc_get_property (GObject * object, guint prop_id, GValue * value, GValue v = { 0, }; g_value_init (&v, G_TYPE_INT); - g_value_set_int (&v, gst_vp8_enc->ts_target_bitrate[i]); + g_value_set_int (&v, gst_vp8_enc->cfg.ts_target_bitrate[i]); g_value_array_append (va, &v); g_value_unset (&v); } @@ -1074,7 +1101,7 @@ gst_vp8_enc_get_property (GObject * object, guint prop_id, GValue * value, GValue v = { 0, }; g_value_init (&v, G_TYPE_INT); - g_value_set_int (&v, gst_vp8_enc->ts_rate_decimator[i]); + g_value_set_int (&v, gst_vp8_enc->cfg.ts_rate_decimator[i]); g_value_array_append (va, &v); g_value_unset (&v); } @@ -1084,7 +1111,7 @@ gst_vp8_enc_get_property (GObject * object, guint prop_id, GValue * value, break; } case PROP_TS_PERIODICITY: - g_value_set_int (value, gst_vp8_enc->ts_periodicity); + g_value_set_int (value, gst_vp8_enc->cfg.ts_periodicity); break; case PROP_TS_LAYER_ID:{ GValueArray *va; @@ -1099,7 +1126,7 @@ gst_vp8_enc_get_property (GObject * object, guint prop_id, GValue * value, GValue v = { 0, }; g_value_init (&v, G_TYPE_INT); - g_value_set_int (&v, gst_vp8_enc->ts_layer_id[i]); + g_value_set_int (&v, gst_vp8_enc->cfg.ts_layer_id[i]); g_value_array_append (va, &v); g_value_unset (&v); } @@ -1109,13 +1136,13 @@ gst_vp8_enc_get_property (GObject * object, guint prop_id, GValue * value, break; } case PROP_ERROR_RESILIENT: - g_value_set_flags (value, gst_vp8_enc->error_resilient); + g_value_set_flags (value, gst_vp8_enc->cfg.g_error_resilient); break; case PROP_LAG_IN_FRAMES: - g_value_set_int (value, gst_vp8_enc->lag_in_frames); + g_value_set_int (value, gst_vp8_enc->cfg.g_lag_in_frames); break; case PROP_THREADS: - g_value_set_int (value, gst_vp8_enc->threads); + g_value_set_int (value, gst_vp8_enc->cfg.g_threads); break; case PROP_DEADLINE: g_value_set_int64 (value, gst_vp8_enc->deadline); @@ -1166,13 +1193,23 @@ gst_vp8_enc_get_property (GObject * object, guint prop_id, GValue * value, G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } + + g_mutex_unlock (&gst_vp8_enc->encoder_lock); } static gboolean gst_vp8_enc_start (GstVideoEncoder * video_encoder) { + GstVP8Enc *encoder = GST_VP8_ENC (video_encoder); + GST_DEBUG_OBJECT (video_encoder, "start"); + if (!encoder->have_default_config) { + GST_ELEMENT_ERROR (encoder, LIBRARY, INIT, + ("Failed to get default encoder configuration"), (NULL)); + return FALSE; + } + return TRUE; } @@ -1185,6 +1222,7 @@ gst_vp8_enc_stop (GstVideoEncoder * video_encoder) encoder = GST_VP8_ENC (video_encoder); + g_mutex_lock (&encoder->encoder_lock); if (encoder->inited) { vpx_codec_destroy (&encoder->encoder); encoder->inited = FALSE; @@ -1195,11 +1233,12 @@ gst_vp8_enc_stop (GstVideoEncoder * video_encoder) encoder->first_pass_cache_content = NULL; } - if (encoder->last_pass_cache_content.buf) { - g_free (encoder->last_pass_cache_content.buf); - encoder->last_pass_cache_content.buf = NULL; - encoder->last_pass_cache_content.sz = 0; + if (encoder->cfg.rc_twopass_stats_in.buf) { + g_free (encoder->cfg.rc_twopass_stats_in.buf); + encoder->cfg.rc_twopass_stats_in.buf = NULL; + encoder->cfg.rc_twopass_stats_in.sz = 0; } + g_mutex_unlock (&encoder->encoder_lock); gst_tag_setter_reset_tags (GST_TAG_SETTER (encoder)); @@ -1250,7 +1289,6 @@ gst_vp8_enc_set_format (GstVideoEncoder * video_encoder, GstVideoCodecState * state) { GstVP8Enc *encoder; - vpx_codec_enc_cfg_t cfg; vpx_codec_err_t status; vpx_image_t *image; guint8 *data = NULL; @@ -1268,85 +1306,50 @@ gst_vp8_enc_set_format (GstVideoEncoder * video_encoder, return FALSE; } - status = vpx_codec_enc_config_default (&vpx_codec_vp8_cx_algo, &cfg, 0); - if (status != VPX_CODEC_OK) { - GST_ELEMENT_ERROR (encoder, LIBRARY, INIT, - ("Failed to get default encoder configuration"), ("%s", - gst_vpx_error_name (status))); - return FALSE; - } - - encoder->profile = gst_vp8_enc_get_downstream_profile (encoder); + g_mutex_lock (&encoder->encoder_lock); + encoder->cfg.g_profile = gst_vp8_enc_get_downstream_profile (encoder); /* Scale default bitrate to our size */ - cfg.rc_target_bitrate = gst_util_uint64_scale (cfg.rc_target_bitrate, - GST_VIDEO_INFO_WIDTH (info) * GST_VIDEO_INFO_HEIGHT (info), - cfg.g_w * cfg.g_h); - - cfg.g_w = GST_VIDEO_INFO_WIDTH (info); - cfg.g_h = GST_VIDEO_INFO_HEIGHT (info); - cfg.g_timebase.num = GST_VIDEO_INFO_FPS_D (info); - cfg.g_timebase.den = GST_VIDEO_INFO_FPS_N (info); - - cfg.rc_end_usage = encoder->rc_end_usage; - if (encoder->rc_target_bitrate_set) - cfg.rc_target_bitrate = encoder->rc_target_bitrate / 1000; - cfg.rc_min_quantizer = encoder->rc_min_quantizer; - cfg.rc_max_quantizer = encoder->rc_max_quantizer; - cfg.rc_dropframe_thresh = encoder->rc_dropframe_thresh; - cfg.rc_resize_allowed = encoder->rc_resize_allowed; - cfg.rc_resize_up_thresh = encoder->rc_resize_up_thresh; - cfg.rc_resize_down_thresh = encoder->rc_resize_down_thresh; - cfg.rc_undershoot_pct = encoder->rc_undershoot_pct; - cfg.rc_overshoot_pct = encoder->rc_overshoot_pct; - cfg.rc_buf_sz = encoder->rc_buf_sz; - cfg.rc_buf_initial_sz = encoder->rc_buf_initial_sz; - cfg.rc_buf_optimal_sz = encoder->rc_buf_optimal_sz; - cfg.rc_2pass_vbr_bias_pct = encoder->rc_2pass_vbr_bias_pct; - cfg.rc_2pass_vbr_minsection_pct = encoder->rc_2pass_vbr_minsection_pct; - cfg.rc_2pass_vbr_maxsection_pct = encoder->rc_2pass_vbr_maxsection_pct; - cfg.kf_mode = encoder->kf_mode; - cfg.kf_max_dist = encoder->kf_max_dist; - cfg.ts_number_layers = encoder->ts_number_layers; - memcpy (cfg.ts_target_bitrate, encoder->ts_target_bitrate, - sizeof (encoder->ts_target_bitrate)); - memcpy (cfg.ts_rate_decimator, encoder->ts_rate_decimator, - sizeof (encoder->ts_rate_decimator)); - cfg.ts_periodicity = encoder->ts_periodicity; - memcpy (cfg.ts_layer_id, encoder->ts_layer_id, sizeof (encoder->ts_layer_id)); - cfg.g_error_resilient = encoder->error_resilient; - cfg.g_lag_in_frames = encoder->lag_in_frames; - cfg.g_threads = encoder->threads; - - cfg.g_pass = encoder->multipass_mode; - if (encoder->multipass_mode == VPX_RC_FIRST_PASS) { + if (!encoder->rc_target_bitrate_set) + encoder->cfg.rc_target_bitrate = + gst_util_uint64_scale (DEFAULT_RC_TARGET_BITRATE, + GST_VIDEO_INFO_WIDTH (info) * GST_VIDEO_INFO_HEIGHT (info), 320 * 240); + + encoder->cfg.g_w = GST_VIDEO_INFO_WIDTH (info); + encoder->cfg.g_h = GST_VIDEO_INFO_HEIGHT (info); + encoder->cfg.g_timebase.num = GST_VIDEO_INFO_FPS_D (info); + encoder->cfg.g_timebase.den = GST_VIDEO_INFO_FPS_N (info); + + if (encoder->cfg.g_pass == VPX_RC_FIRST_PASS) { encoder->first_pass_cache_content = g_byte_array_sized_new (4096); - } else if (encoder->multipass_mode == VPX_RC_LAST_PASS) { + } else if (encoder->cfg.g_pass == VPX_RC_LAST_PASS) { GError *err = NULL; if (!encoder->multipass_cache_file) { GST_ELEMENT_ERROR (encoder, RESOURCE, OPEN_READ, ("No multipass cache file provided"), (NULL)); + g_mutex_unlock (&encoder->encoder_lock); return FALSE; } if (!g_file_get_contents (encoder->multipass_cache_file, - (gchar **) & encoder->last_pass_cache_content.buf, - &encoder->last_pass_cache_content.sz, &err)) { + (gchar **) & encoder->cfg.rc_twopass_stats_in.buf, + &encoder->cfg.rc_twopass_stats_in.sz, &err)) { GST_ELEMENT_ERROR (encoder, RESOURCE, OPEN_READ, ("Failed to read multipass cache file provided"), ("%s", err->message)); g_error_free (err); + g_mutex_unlock (&encoder->encoder_lock); return FALSE; } - cfg.rc_twopass_stats_in = encoder->last_pass_cache_content; } status = vpx_codec_enc_init (&encoder->encoder, &vpx_codec_vp8_cx_algo, - &cfg, 0); + &encoder->cfg, 0); if (status != VPX_CODEC_OK) { GST_ELEMENT_ERROR (encoder, LIBRARY, INIT, ("Failed to initialize encoder"), ("%s", gst_vpx_error_name (status))); + g_mutex_unlock (&encoder->encoder_lock); return FALSE; } @@ -1447,7 +1450,7 @@ gst_vp8_enc_set_format (GstVideoEncoder * video_encoder, } gst_video_encoder_set_latency (video_encoder, 0, - gst_util_uint64_scale (encoder->lag_in_frames, + gst_util_uint64_scale (encoder->cfg.g_lag_in_frames, GST_VIDEO_INFO_FPS_D (info) * GST_SECOND, GST_VIDEO_INFO_FPS_N (info))); encoder->inited = TRUE; @@ -1471,7 +1474,7 @@ gst_vp8_enc_set_format (GstVideoEncoder * video_encoder, image->stride[VPX_PLANE_U] = GST_VIDEO_INFO_COMP_STRIDE (info, 1); image->stride[VPX_PLANE_V] = GST_VIDEO_INFO_COMP_STRIDE (info, 2); - profile_str = g_strdup_printf ("%d", encoder->profile); + profile_str = g_strdup_printf ("%d", encoder->cfg.g_profile); caps = gst_caps_new_simple ("video/x-vp8", "profile", G_TYPE_STRING, profile_str, NULL); g_free (profile_str); @@ -1534,6 +1537,8 @@ gst_vp8_enc_set_format (GstVideoEncoder * video_encoder, gst_structure_set_value (s, "streamheader", &array); g_value_unset (&array); } + g_mutex_unlock (&encoder->encoder_lock); + output_state = gst_video_encoder_set_output_state (video_encoder, caps, state); gst_video_codec_state_unref (output_state); @@ -1543,6 +1548,13 @@ gst_vp8_enc_set_format (GstVideoEncoder * video_encoder, return ret; } +static void +_gst_video_codec_frame_unref0 (GstVideoCodecFrame * frame) +{ + if (frame) + gst_video_codec_frame_unref (frame); +} + static GstFlowReturn gst_vp8_enc_process (GstVP8Enc * encoder) { @@ -1552,9 +1564,11 @@ gst_vp8_enc_process (GstVP8Enc * encoder) GstVP8EncUserData *user_data; GstVideoCodecFrame *frame; GstFlowReturn ret = GST_FLOW_OK; + GList *l, *frames = NULL; video_encoder = GST_VIDEO_ENCODER (encoder); + g_mutex_lock (&encoder->encoder_lock); pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter); while (pkt != NULL) { GstBuffer *buffer; @@ -1564,7 +1578,7 @@ gst_vp8_enc_process (GstVP8Enc * encoder) pkt->kind); if (pkt->kind == VPX_CODEC_STATS_PKT - && encoder->multipass_mode == VPX_RC_FIRST_PASS) { + && encoder->cfg.g_pass == VPX_RC_FIRST_PASS) { GST_LOG_OBJECT (encoder, "handling STATS packet"); g_byte_array_append (encoder->first_pass_cache_content, @@ -1575,7 +1589,7 @@ gst_vp8_enc_process (GstVP8Enc * encoder) buffer = gst_buffer_new (); GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_LIVE); frame->output_buffer = buffer; - gst_video_encoder_finish_frame (video_encoder, frame); + frames = g_list_prepend (frames, frame); } pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter); @@ -1609,11 +1623,23 @@ gst_vp8_enc_process (GstVP8Enc * encoder) user_data->invisible = g_list_append (user_data->invisible, buffer); } else { frame->output_buffer = buffer; - ret = gst_video_encoder_finish_frame (video_encoder, frame); + frames = g_list_prepend (frames, frame); } pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter); } + g_mutex_unlock (&encoder->encoder_lock); + + frames = g_list_reverse (frames); + for (l = frames; l; l = l->next) { + ret = gst_video_encoder_finish_frame (video_encoder, l->data); + l->data = NULL; + if (ret != GST_FLOW_OK) + break; + } + + g_list_foreach (frames, (GFunc) _gst_video_codec_frame_unref0, NULL); + g_list_free (frames); return ret; } @@ -1629,9 +1655,11 @@ gst_vp8_enc_finish (GstVideoEncoder * video_encoder) encoder = GST_VP8_ENC (video_encoder); + g_mutex_lock (&encoder->encoder_lock); status = vpx_codec_encode (&encoder->encoder, NULL, encoder->n_frames, 1, flags, encoder->deadline); + g_mutex_unlock (&encoder->encoder_lock); if (status != 0) { GST_ERROR_OBJECT (encoder, "encode returned %d %s", status, gst_vpx_error_name (status)); @@ -1641,8 +1669,7 @@ gst_vp8_enc_finish (GstVideoEncoder * video_encoder) /* dispatch remaining frames */ gst_vp8_enc_process (encoder); - if (encoder->multipass_mode == VPX_RC_FIRST_PASS - && encoder->multipass_cache_file) { + if (encoder->cfg.g_pass == VPX_RC_FIRST_PASS && encoder->multipass_cache_file) { GError *err = NULL; if (!g_file_set_contents (encoder->multipass_cache_file, @@ -1709,8 +1736,10 @@ gst_vp8_enc_handle_frame (GstVideoEncoder * video_encoder, flags |= VPX_EFLAG_FORCE_KF; } + g_mutex_lock (&encoder->encoder_lock); status = vpx_codec_encode (&encoder->encoder, image, encoder->n_frames, 1, flags, encoder->deadline); + g_mutex_unlock (&encoder->encoder_lock); gst_video_frame_unmap (&vframe); if (status != 0) { diff --git a/ext/vpx/gstvp8enc.h b/ext/vpx/gstvp8enc.h index 7338affeb..a8120677a 100644 --- a/ext/vpx/gstvp8enc.h +++ b/ext/vpx/gstvp8enc.h @@ -56,60 +56,18 @@ struct _GstVP8Enc /* < private > */ vpx_codec_ctx_t encoder; - - /* from downstream caps */ - int profile; + GMutex encoder_lock; /* properties */ - /* Rate control options */ - enum vpx_rc_mode rc_end_usage; - unsigned int rc_target_bitrate; + vpx_codec_enc_cfg_t cfg; + gboolean have_default_config; gboolean rc_target_bitrate_set; - unsigned int rc_min_quantizer, rc_max_quantizer; - - unsigned int rc_dropframe_thresh; - gboolean rc_resize_allowed; - unsigned int rc_resize_up_thresh; - unsigned int rc_resize_down_thresh; - unsigned int rc_undershoot_pct; - unsigned int rc_overshoot_pct; - unsigned int rc_buf_sz; - unsigned int rc_buf_initial_sz; - unsigned int rc_buf_optimal_sz; - - unsigned int rc_2pass_vbr_bias_pct; - unsigned int rc_2pass_vbr_minsection_pct; - unsigned int rc_2pass_vbr_maxsection_pct; - - /* Global keyframe options */ - enum vpx_kf_mode kf_mode; - unsigned int kf_max_dist; - + gint n_ts_target_bitrate; + gint n_ts_rate_decimator; + gint n_ts_layer_id; /* Global two-pass options */ - enum vpx_enc_pass multipass_mode; gchar *multipass_cache_file; GByteArray *first_pass_cache_content; - vpx_fixed_buf_t last_pass_cache_content; - - /* Global temporal scalability options */ - unsigned int ts_number_layers; - unsigned int ts_target_bitrate[VPX_TS_MAX_LAYERS]; - int n_ts_target_bitrate; - unsigned int ts_rate_decimator[VPX_TS_MAX_LAYERS]; - int n_ts_rate_decimator; - unsigned int ts_periodicity; - unsigned int ts_layer_id[VPX_TS_MAX_PERIODICITY]; - int n_ts_layer_id; - - /* Global, other options */ - vpx_codec_er_flags_t error_resilient; - unsigned int lag_in_frames; - - int threads; -#if 0 - /* Only usage 0 is defined right now */ - int usage; -#endif /* Encode parameter */ gint64 deadline; |