Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/GStreamer/gst-plugins-good.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/vpx/gstvp9enc.c3
-rw-r--r--ext/vpx/gstvpxenc.c87
-rw-r--r--ext/vpx/gstvpxenc.h5
-rw-r--r--tests/check/elements/vp8enc.c106
-rw-r--r--tests/check/elements/vp9enc.c46
5 files changed, 231 insertions, 16 deletions
diff --git a/ext/vpx/gstvp9enc.c b/ext/vpx/gstvp9enc.c
index 362856476..f3058081e 100644
--- a/ext/vpx/gstvp9enc.c
+++ b/ext/vpx/gstvp9enc.c
@@ -101,6 +101,8 @@ static GstFlowReturn gst_vp9_enc_handle_invisible_frame_buffer (GstVPXEnc * enc,
static void gst_vp9_enc_set_frame_user_data (GstVPXEnc * enc,
GstVideoCodecFrame * frame, vpx_image_t * image);
+#define DEFAULT_BITS_PER_PIXEL 0.0289
+
static void
gst_vp9_enc_class_init (GstVP9EncClass * klass)
{
@@ -152,6 +154,7 @@ gst_vp9_enc_init (GstVP9Enc * gst_vp9_enc)
} else {
gst_vpx_enc->have_default_config = TRUE;
}
+ gst_vpx_enc->bits_per_pixel = DEFAULT_BITS_PER_PIXEL;
}
static vpx_codec_iface_t *
diff --git a/ext/vpx/gstvpxenc.c b/ext/vpx/gstvpxenc.c
index 12a781df2..cfb69c833 100644
--- a/ext/vpx/gstvpxenc.c
+++ b/ext/vpx/gstvpxenc.c
@@ -47,7 +47,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_vpxenc_debug);
#define DEFAULT_PROFILE 0
#define DEFAULT_RC_END_USAGE VPX_VBR
-#define DEFAULT_RC_TARGET_BITRATE 256000
+#define DEFAULT_RC_TARGET_BITRATE 0
#define DEFAULT_RC_MIN_QUANTIZER 4
#define DEFAULT_RC_MAX_QUANTIZER 63
@@ -102,6 +102,8 @@ GST_DEBUG_CATEGORY_STATIC (gst_vpxenc_debug);
#define DEFAULT_TIMEBASE_N 0
#define DEFAULT_TIMEBASE_D 1
+#define DEFAULT_BITS_PER_PIXEL 0.0434
+
enum
{
PROP_0,
@@ -148,7 +150,8 @@ enum
PROP_TUNING,
PROP_CQ_LEVEL,
PROP_MAX_INTRA_BITRATE_PCT,
- PROP_TIMEBASE
+ PROP_TIMEBASE,
+ PROP_BITS_PER_PIXEL
};
@@ -368,7 +371,8 @@ gst_vpx_enc_class_init (GstVPXEncClass * klass)
g_object_class_install_property (gobject_class, PROP_RC_TARGET_BITRATE,
g_param_spec_int ("target-bitrate", "Target bitrate",
- "Target bitrate (in bits/sec)",
+ "Target bitrate (in bits/sec) (0: auto - bitrate depends on "
+ "resolution, see \"bits-per-pixel\" property for more info)",
0, G_MAXINT, DEFAULT_RC_TARGET_BITRATE,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
@@ -638,6 +642,13 @@ gst_vpx_enc_class_init (GstVPXEncClass * klass)
0, 1, G_MAXINT, 1, DEFAULT_TIMEBASE_N, DEFAULT_TIMEBASE_D,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_BITS_PER_PIXEL,
+ g_param_spec_float ("bits-per-pixel", "Bits per pixel",
+ "Factor to convert number of pixels to bitrate value "
+ "(only has an effect if target-bitrate=0)",
+ 0.0, G_MAXFLOAT, DEFAULT_BITS_PER_PIXEL,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
GST_DEBUG_CATEGORY_INIT (gst_vpxenc_debug, "vpxenc", 0, "VPX Encoder");
gst_type_mark_as_plugin_api (GST_VPX_ENC_END_USAGE_TYPE);
@@ -657,7 +668,7 @@ gst_vpx_enc_init (GstVPXEnc * gst_vpx_enc)
gst_vpx_enc->cfg.rc_end_usage = DEFAULT_RC_END_USAGE;
gst_vpx_enc->cfg.rc_target_bitrate = DEFAULT_RC_TARGET_BITRATE / 1000;
- gst_vpx_enc->rc_target_bitrate_set = FALSE;
+ gst_vpx_enc->rc_target_bitrate_auto = DEFAULT_RC_TARGET_BITRATE == 0;
gst_vpx_enc->cfg.rc_min_quantizer = DEFAULT_RC_MIN_QUANTIZER;
gst_vpx_enc->cfg.rc_max_quantizer = DEFAULT_RC_MAX_QUANTIZER;
gst_vpx_enc->cfg.rc_dropframe_thresh = DEFAULT_RC_DROPFRAME_THRESH;
@@ -705,6 +716,7 @@ gst_vpx_enc_init (GstVPXEnc * gst_vpx_enc)
gst_vpx_enc->max_intra_bitrate_pct = DEFAULT_MAX_INTRA_BITRATE_PCT;
gst_vpx_enc->timebase_n = DEFAULT_TIMEBASE_N;
gst_vpx_enc->timebase_d = DEFAULT_TIMEBASE_D;
+ gst_vpx_enc->bits_per_pixel = DEFAULT_BITS_PER_PIXEL;
gst_vpx_enc->cfg.g_profile = DEFAULT_PROFILE;
@@ -735,6 +747,42 @@ gst_vpx_enc_finalize (GObject * object)
}
static void
+gst_vpx_enc_set_auto_bitrate (GstVPXEnc * encoder)
+{
+ if (encoder->input_state != NULL) {
+ guint size;
+ guint pixels_per_sec;
+ guint target_bitrate;
+ guint fps_n, fps_d;
+
+ if (GST_VIDEO_INFO_FPS_D (&encoder->input_state->info) != 0) {
+ fps_n = GST_VIDEO_INFO_FPS_N (&encoder->input_state->info);
+ fps_d = GST_VIDEO_INFO_FPS_D (&encoder->input_state->info);
+ } else {
+ /* otherwise assume 30 frames per second as a fallback */
+ fps_n = 30;
+ fps_d = 1;
+ }
+
+ size =
+ GST_VIDEO_INFO_WIDTH (&encoder->input_state->info) *
+ GST_VIDEO_INFO_HEIGHT (&encoder->input_state->info);
+ pixels_per_sec = size * fps_n / fps_d;
+ target_bitrate = pixels_per_sec * encoder->bits_per_pixel;
+
+ GST_DEBUG_OBJECT (encoder,
+ "Setting autobitrate for %ux%ux @ %u/%ufps %.4f = %ubps",
+ GST_VIDEO_INFO_WIDTH (&encoder->input_state->info),
+ GST_VIDEO_INFO_HEIGHT (&encoder->input_state->info),
+ GST_VIDEO_INFO_FPS_N (&encoder->input_state->info),
+ GST_VIDEO_INFO_FPS_D (&encoder->input_state->info),
+ encoder->bits_per_pixel, target_bitrate);
+
+ encoder->cfg.rc_target_bitrate = target_bitrate / 1000;
+ }
+}
+
+static void
gst_vpx_enc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
@@ -753,8 +801,13 @@ gst_vpx_enc_set_property (GObject * object, guint prop_id,
global = TRUE;
break;
case PROP_RC_TARGET_BITRATE:
- gst_vpx_enc->cfg.rc_target_bitrate = g_value_get_int (value) / 1000;
- gst_vpx_enc->rc_target_bitrate_set = TRUE;
+ if (g_value_get_int (value) == 0) {
+ gst_vpx_enc_set_auto_bitrate (gst_vpx_enc);
+ gst_vpx_enc->rc_target_bitrate_auto = TRUE;
+ } else {
+ gst_vpx_enc->cfg.rc_target_bitrate = g_value_get_int (value) / 1000;
+ gst_vpx_enc->rc_target_bitrate_auto = FALSE;
+ }
global = TRUE;
break;
case PROP_RC_MIN_QUANTIZER:
@@ -1097,6 +1150,13 @@ gst_vpx_enc_set_property (GObject * object, guint prop_id,
gst_vpx_enc->timebase_n = gst_value_get_fraction_numerator (value);
gst_vpx_enc->timebase_d = gst_value_get_fraction_denominator (value);
break;
+ case PROP_BITS_PER_PIXEL:
+ gst_vpx_enc->bits_per_pixel = g_value_get_float (value);
+ if (gst_vpx_enc->rc_target_bitrate_auto) {
+ gst_vpx_enc_set_auto_bitrate (gst_vpx_enc);
+ global = TRUE;
+ }
+ break;
default:
break;
}
@@ -1318,6 +1378,9 @@ gst_vpx_enc_get_property (GObject * object, guint prop_id, GValue * value,
gst_value_set_fraction (value, gst_vpx_enc->timebase_n,
gst_vpx_enc->timebase_d);
break;
+ case PROP_BITS_PER_PIXEL:
+ g_value_set_float (value, gst_vpx_enc->bits_per_pixel);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1452,14 +1515,6 @@ gst_vpx_enc_set_format (GstVideoEncoder * video_encoder,
}
encoder->cfg.g_profile = gst_vpx_enc_get_downstream_profile (encoder);
-
- /* Scale default bitrate to our size */
- 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 * 1000);
-
encoder->cfg.g_w = GST_VIDEO_INFO_WIDTH (info);
encoder->cfg.g_h = GST_VIDEO_INFO_HEIGHT (info);
@@ -1641,6 +1696,10 @@ gst_vpx_enc_set_format (GstVideoEncoder * video_encoder,
gst_video_codec_state_unref (encoder->input_state);
encoder->input_state = gst_video_codec_state_ref (state);
+ /* Scale default bitrate to our size */
+ if (encoder->rc_target_bitrate_auto)
+ gst_vpx_enc_set_auto_bitrate (encoder);
+
/* prepare cached image buffer setup */
image = &encoder->image;
memset (image, 0, sizeof (*image));
diff --git a/ext/vpx/gstvpxenc.h b/ext/vpx/gstvpxenc.h
index 5a0d5ba53..fbf5476ba 100644
--- a/ext/vpx/gstvpxenc.h
+++ b/ext/vpx/gstvpxenc.h
@@ -68,7 +68,7 @@ struct _GstVPXEnc
/* properties */
vpx_codec_enc_cfg_t cfg;
gboolean have_default_config;
- gboolean rc_target_bitrate_set;
+ gboolean rc_target_bitrate_auto;
gint n_ts_target_bitrate;
gint n_ts_rate_decimator;
gint n_ts_layer_id;
@@ -100,6 +100,9 @@ struct _GstVPXEnc
unsigned int timebase_n;
unsigned int timebase_d;
+ /* Bits per Pixel */
+ gfloat bits_per_pixel;
+
/* state */
gboolean inited;
diff --git a/tests/check/elements/vp8enc.c b/tests/check/elements/vp8enc.c
index 86b1d929d..e9d8c071f 100644
--- a/tests/check/elements/vp8enc.c
+++ b/tests/check/elements/vp8enc.c
@@ -17,8 +17,9 @@
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
-
+#include <gst/check/gstharness.h>
#include <gst/check/gstcheck.h>
+#include <gst/video/video.h>
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
@@ -90,6 +91,7 @@ cleanup_vp8enc (GstElement * vp8enc)
gst_check_teardown_element (vp8enc);
}
+
GST_START_TEST (test_encode_simple)
{
GstElement *vp8enc;
@@ -152,6 +154,106 @@ GST_START_TEST (test_encode_simple)
GST_END_TEST;
+#define gst_caps_new_i420(w, h) gst_caps_new_i420_full (w, h, 30, 1, 1, 1)
+static GstCaps *
+gst_caps_new_i420_full (gint width, gint height, gint fps_n, gint fps_d,
+ gint par_n, gint par_d)
+{
+ GstVideoInfo info;
+ gst_video_info_init (&info);
+ gst_video_info_set_format (&info, GST_VIDEO_FORMAT_I420, width, height);
+ GST_VIDEO_INFO_FPS_N (&info) = fps_n;
+ GST_VIDEO_INFO_FPS_D (&info) = fps_d;
+ GST_VIDEO_INFO_PAR_N (&info) = par_n;
+ GST_VIDEO_INFO_PAR_D (&info) = par_d;
+ return gst_video_info_to_caps (&info);
+}
+
+static GstBuffer *
+gst_harness_create_video_buffer_from_info (GstHarness * h, gint value,
+ GstVideoInfo * info, GstClockTime timestamp, GstClockTime duration)
+{
+ GstBuffer *buf;
+ gsize size;
+
+ size = GST_VIDEO_INFO_SIZE (info);
+
+ buf = gst_harness_create_buffer (h, size);
+ gst_buffer_memset (buf, 0, value, size);
+ g_assert (buf != NULL);
+
+ gst_buffer_add_video_meta_full (buf,
+ GST_VIDEO_FRAME_FLAG_NONE,
+ GST_VIDEO_INFO_FORMAT (info),
+ GST_VIDEO_INFO_WIDTH (info),
+ GST_VIDEO_INFO_HEIGHT (info),
+ GST_VIDEO_INFO_N_PLANES (info), info->offset, info->stride);
+
+ GST_BUFFER_PTS (buf) = timestamp;
+ GST_BUFFER_DURATION (buf) = duration;
+
+ return buf;
+}
+
+static GstBuffer *
+gst_harness_create_video_buffer_full (GstHarness * h, gint value,
+ guint width, guint height, GstClockTime timestamp, GstClockTime duration)
+{
+ GstVideoInfo info;
+
+ gst_video_info_init (&info);
+ gst_video_info_set_format (&info, GST_VIDEO_FORMAT_I420, width, height);
+
+ return gst_harness_create_video_buffer_from_info (h, value, &info,
+ timestamp, duration);
+}
+
+GST_START_TEST (test_encode_simple_when_bitrate_set_to_zero)
+{
+ GstHarness *h = gst_harness_new_parse ("vp8enc target-bitrate=0");
+ GstBuffer *buf;
+
+ gst_harness_set_src_caps (h, gst_caps_new_i420 (320, 240));
+
+ buf = gst_harness_create_video_buffer_full (h, 0x42,
+ 320, 240, 0, gst_util_uint64_scale (GST_SECOND, 1, 30));
+ gst_harness_push (h, buf);
+ gst_buffer_unref (gst_harness_pull (h));
+ gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_autobitrate_changes_with_caps)
+{
+ gint bitrate = 0;
+ GstHarness *h = gst_harness_new ("vp8enc");
+ gst_harness_set_src_caps (h, gst_caps_new_i420_full (1280, 720, 30, 1, 1, 1));
+
+ /* Default settings for 720p @ 30fps ~1.2Mbps */
+ g_object_get (h->element, "target-bitrate", &bitrate, NULL);
+ fail_unless_equals_int (bitrate, 1199000);
+
+ /* Change bits-per-pixel 0.036 to give us ~1Mbps */
+ g_object_set (h->element, "bits-per-pixel", 0.037, NULL);
+ g_object_get (h->element, "target-bitrate", &bitrate, NULL);
+ fail_unless_equals_int (bitrate, 1022000);
+
+ /* Halving the framerate should halve the auto bitrate */
+ gst_harness_set_src_caps (h, gst_caps_new_i420_full (1280, 720, 15, 1, 1, 1));
+ g_object_get (h->element, "target-bitrate", &bitrate, NULL);
+ fail_unless_equals_int (bitrate, 511000);
+
+ /* Halving the resolution should quarter the auto bitrate */
+ gst_harness_set_src_caps (h, gst_caps_new_i420_full (640, 360, 15, 1, 1, 1));
+ g_object_get (h->element, "target-bitrate", &bitrate, NULL);
+ fail_unless_equals_int (bitrate, 127000);
+
+ gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
static Suite *
vp8enc_suite (void)
{
@@ -161,6 +263,8 @@ vp8enc_suite (void)
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_encode_simple);
+ tcase_add_test (tc_chain, test_encode_simple_when_bitrate_set_to_zero);
+ tcase_add_test (tc_chain, test_autobitrate_changes_with_caps);
return s;
}
diff --git a/tests/check/elements/vp9enc.c b/tests/check/elements/vp9enc.c
index f7be0e0fb..b7ae12fd9 100644
--- a/tests/check/elements/vp9enc.c
+++ b/tests/check/elements/vp9enc.c
@@ -21,6 +21,21 @@
#include <gst/check/gstcheck.h>
#include <gst/video/video.h>
+#define gst_caps_new_i420(w, h) gst_caps_new_i420_full (w, h, 30, 1, 1, 1)
+static GstCaps *
+gst_caps_new_i420_full (gint width, gint height, gint fps_n, gint fps_d,
+ gint par_n, gint par_d)
+{
+ GstVideoInfo info;
+ gst_video_info_init (&info);
+ gst_video_info_set_format (&info, GST_VIDEO_FORMAT_I420, width, height);
+ GST_VIDEO_INFO_FPS_N (&info) = fps_n;
+ GST_VIDEO_INFO_FPS_D (&info) = fps_d;
+ GST_VIDEO_INFO_PAR_N (&info) = par_n;
+ GST_VIDEO_INFO_PAR_D (&info) = par_d;
+ return gst_video_info_to_caps (&info);
+}
+
GST_START_TEST (test_encode_lag_in_frames)
{
GstHarness *h = gst_harness_new_parse ("vp9enc lag-in-frames=5 cpu-used=8 "
@@ -62,6 +77,36 @@ GST_START_TEST (test_encode_lag_in_frames)
GST_END_TEST;
+GST_START_TEST (test_autobitrate_changes_with_caps)
+{
+ gint bitrate = 0;
+ GstHarness *h = gst_harness_new ("vp9enc");
+ gst_harness_set_src_caps (h, gst_caps_new_i420_full (1280, 720, 30, 1, 1, 1));
+
+ /* Default settings for 720p @ 30fps ~0.8Mbps */
+ g_object_get (h->element, "target-bitrate", &bitrate, NULL);
+ fail_unless_equals_int (bitrate, 799000);
+
+ /* Change bits-per-pixel 0.036 to give us ~1Mbps */
+ g_object_set (h->element, "bits-per-pixel", 0.037, NULL);
+ g_object_get (h->element, "target-bitrate", &bitrate, NULL);
+ fail_unless_equals_int (bitrate, 1022000);
+
+ /* Halving the framerate should halve the auto bitrate */
+ gst_harness_set_src_caps (h, gst_caps_new_i420_full (1280, 720, 15, 1, 1, 1));
+ g_object_get (h->element, "target-bitrate", &bitrate, NULL);
+ fail_unless_equals_int (bitrate, 511000);
+
+ /* Halving the resolution should quarter the auto bitrate */
+ gst_harness_set_src_caps (h, gst_caps_new_i420_full (640, 360, 15, 1, 1, 1));
+ g_object_get (h->element, "target-bitrate", &bitrate, NULL);
+ fail_unless_equals_int (bitrate, 127000);
+
+ gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
static Suite *
vp9enc_suite (void)
{
@@ -71,6 +116,7 @@ vp9enc_suite (void)
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_encode_lag_in_frames);
+ tcase_add_test (tc_chain, test_autobitrate_changes_with_caps);
return s;
}