Set the theoraenc speed-level property from libtheora's defaults.

The speed-level property, which allows callers to trade of encoding
quality for speed in the libtheora api, has a version-dependent
maximum and default values. Instead of hardcoding the acceptable
range for the theoraenc element's presentation of this setting,
we query the library directly at class initialization time and
set the maximum and default values from that. If the query fails,
we fall back to the previous default setting.

To keep the values reported by gst-inspect (which I'm told use
the spec values from the class) with those available on an\
instantiated element, we remove to setting of enc->speed_level
from the initializer and instead pass G_PARAM_CONSTRUCT to
the property spec flags, asking g_object to set this property
when theoraenc objects are constructed.

NB in theory the maximum speed-level could depend on the actual
video caps. If later versions of libtheoraenc do this, a second
call will need to be made from theora_enc_reset to update the
property, since this function is mostly useful for realtime
adjustment of performance while the pipeline is running.
This commit is contained in:
Ralph Giles 2011-01-13 15:12:53 -08:00 committed by David Schleef
parent 7e06d35250
commit d467eb708a

View file

@ -175,6 +175,57 @@ granulepos_to_timestamp (GstTheoraEnc * theoraenc, ogg_int64_t granulepos)
theoraenc->info.fps_numerator); theoraenc->info.fps_numerator);
} }
/* Generate a dummy encoder context for use in th_encode_ctl queries
Release with th_encode_free()
This and the next routine from theora/examples/libtheora_info.c */
static th_enc_ctx *
dummy_encode_ctx (void)
{
th_enc_ctx *ctx;
th_info info;
/* set the minimal video parameters */
th_info_init (&info);
info.frame_width = 320;
info.frame_height = 240;
info.fps_numerator = 1;
info.fps_denominator = 1;
/* allocate and initialize a context object */
ctx = th_encode_alloc (&info);
if (!ctx)
GST_WARNING ("Failed to allocate dummy encoder context.");
/* clear the info struct */
th_info_clear (&info);
return ctx;
}
/* Query the current and maximum values for the 'speed level' setting.
This can be used to ask the encoder to trade off encoding quality
vs. performance cost, for example to adapt to realtime constraints. */
static int
check_speed_level (th_enc_ctx * ctx, int *current, int *max)
{
int ret;
/* query the current speed level */
ret = th_encode_ctl (ctx, TH_ENCCTL_GET_SPLEVEL, current, sizeof (int));
if (ret) {
GST_WARNING ("Error %d getting current speed level.", ret);
return ret;
}
/* query the maximum speed level, which varies by encoder version */
ret = th_encode_ctl (ctx, TH_ENCCTL_GET_SPLEVEL_MAX, max, sizeof (int));
if (ret) {
GST_WARNING ("Error %d getting maximum speed level.", ret);
return ret;
}
return 0;
}
static GstStaticPadTemplate theora_enc_sink_factory = static GstStaticPadTemplate theora_enc_sink_factory =
GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_SINK,
@ -242,6 +293,19 @@ gst_theora_enc_class_init (GstTheoraEncClass * klass)
GObjectClass *gobject_class = (GObjectClass *) klass; GObjectClass *gobject_class = (GObjectClass *) klass;
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
/* query runtime encoder properties */
th_enc_ctx *th_ctx;
int default_speed_level = THEORA_DEF_SPEEDLEVEL;
int max_speed_level = default_speed_level;
th_ctx = dummy_encode_ctx ();
if (th_ctx) {
if (!check_speed_level (th_ctx, &default_speed_level, &max_speed_level))
GST_WARNING
("Failed to determine settings for the speed-level property.");
th_encode_free (th_ctx);
}
gobject_class->set_property = theora_enc_set_property; gobject_class->set_property = theora_enc_set_property;
gobject_class->get_property = theora_enc_get_property; gobject_class->get_property = theora_enc_get_property;
gobject_class->finalize = theora_enc_finalize; gobject_class->finalize = theora_enc_finalize;
@ -301,9 +365,13 @@ gst_theora_enc_class_init (GstTheoraEncClass * klass)
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_SPEEDLEVEL, g_object_class_install_property (gobject_class, PROP_SPEEDLEVEL,
g_param_spec_int ("speed-level", "Speed level", g_param_spec_int ("speed-level", "Speed level",
"Controls the amount of motion vector searching done while " "Controls the amount of analysis performed when encoding."
"encoding", 0, 3, THEORA_DEF_SPEEDLEVEL, " Higher values trade compression quality for speed."
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); " This property requires libtheora version >= 1.0"
", and the maximum value may vary based on encoder version.",
0, max_speed_level, default_speed_level,
(GParamFlags) G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_VP3_COMPATIBLE, g_object_class_install_property (gobject_class, PROP_VP3_COMPATIBLE,
g_param_spec_boolean ("vp3-compatible", "VP3 Compatible", g_param_spec_boolean ("vp3-compatible", "VP3 Compatible",
"Disables non-VP3 compatible features", "Disables non-VP3 compatible features",
@ -371,7 +439,7 @@ gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class)
enc->expected_ts = GST_CLOCK_TIME_NONE; enc->expected_ts = GST_CLOCK_TIME_NONE;
enc->speed_level = THEORA_DEF_SPEEDLEVEL; /* enc->speed_level is set to the libtheora default by the constructor */
enc->vp3_compatible = THEORA_DEF_VP3_COMPATIBLE; enc->vp3_compatible = THEORA_DEF_VP3_COMPATIBLE;
enc->drop_frames = THEORA_DEF_DROP_FRAMES; enc->drop_frames = THEORA_DEF_DROP_FRAMES;
enc->cap_overflow = THEORA_DEF_CAP_OVERFLOW; enc->cap_overflow = THEORA_DEF_CAP_OVERFLOW;