mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-11 19:06:33 +00:00
935c21a9a9
See https://gitlab.freedesktop.org/gstreamer/gst-libav/issues/41#note_142808 The switch to the new ffmpeg property system changed the type of the bitrate property from int to int64, which potentially breaks many existing applications at runtime as properties are usually set via g_object_set(). As such, override the type to int until GStreamer 2.0.
597 lines
18 KiB
C
597 lines
18 KiB
C
/* GStreamer
|
|
*
|
|
* FFMpeg Configuration
|
|
*
|
|
* Copyright (C) <2006> Mark Nauwelaerts <manauw@skynet.be>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "gstav.h"
|
|
#include "gstavvidenc.h"
|
|
#include "gstavcfg.h"
|
|
|
|
#include <string.h>
|
|
#include <libavutil/opt.h>
|
|
|
|
static GQuark avoption_quark;
|
|
static GHashTable *generic_overrides = NULL;
|
|
|
|
static void
|
|
make_generic_overrides (void)
|
|
{
|
|
g_assert (!generic_overrides);
|
|
generic_overrides = g_hash_table_new_full (g_str_hash, g_str_equal,
|
|
g_free, (GDestroyNotify) gst_structure_free);
|
|
|
|
g_hash_table_insert (generic_overrides, g_strdup ("b"),
|
|
gst_structure_new_empty ("bitrate"));
|
|
g_hash_table_insert (generic_overrides, g_strdup ("ab"),
|
|
gst_structure_new_empty ("bitrate"));
|
|
g_hash_table_insert (generic_overrides, g_strdup ("g"),
|
|
gst_structure_new_empty ("gop-size"));
|
|
g_hash_table_insert (generic_overrides, g_strdup ("bt"),
|
|
gst_structure_new_empty ("bitrate-tolerance"));
|
|
g_hash_table_insert (generic_overrides, g_strdup ("bf"),
|
|
gst_structure_new_empty ("max-bframes"));
|
|
|
|
/* Those are exposed through caps */
|
|
g_hash_table_insert (generic_overrides, g_strdup ("profile"),
|
|
gst_structure_new ("profile", "skip", G_TYPE_BOOLEAN, TRUE, NULL));
|
|
g_hash_table_insert (generic_overrides, g_strdup ("level"),
|
|
gst_structure_new ("level", "skip", G_TYPE_BOOLEAN, TRUE, NULL));
|
|
g_hash_table_insert (generic_overrides, g_strdup ("color_primaries"),
|
|
gst_structure_new ("color_primaries", "skip", G_TYPE_BOOLEAN, TRUE,
|
|
NULL));
|
|
g_hash_table_insert (generic_overrides, g_strdup ("color_trc"),
|
|
gst_structure_new ("color_trc", "skip", G_TYPE_BOOLEAN, TRUE, NULL));
|
|
g_hash_table_insert (generic_overrides, g_strdup ("colorspace"),
|
|
gst_structure_new ("colorspace", "skip", G_TYPE_BOOLEAN, TRUE, NULL));
|
|
g_hash_table_insert (generic_overrides, g_strdup ("color_range"),
|
|
gst_structure_new ("color_range", "skip", G_TYPE_BOOLEAN, TRUE, NULL));
|
|
}
|
|
|
|
void
|
|
gst_ffmpeg_cfg_init (void)
|
|
{
|
|
avoption_quark = g_quark_from_static_string ("ffmpeg-cfg-param-spec-data");
|
|
make_generic_overrides ();
|
|
}
|
|
|
|
static gint
|
|
cmp_enum_value (GEnumValue * val1, GEnumValue * val2)
|
|
{
|
|
return val1->value - val2->value;
|
|
}
|
|
|
|
static GType
|
|
register_enum (const AVClass ** obj, const AVOption * top_opt)
|
|
{
|
|
const AVOption *opt = NULL;
|
|
GType res = 0;
|
|
GArray *values = g_array_new (TRUE, TRUE, sizeof (GEnumValue));
|
|
gchar *lower_obj_name = g_ascii_strdown ((*obj)->class_name, -1);
|
|
gchar *enum_name = g_strdup_printf ("%s-%s", lower_obj_name, top_opt->unit);
|
|
gboolean none_default = TRUE;
|
|
|
|
g_strcanon (enum_name, G_CSET_a_2_z G_CSET_DIGITS, '-');
|
|
|
|
if ((res = g_type_from_name (enum_name)))
|
|
goto done;
|
|
|
|
while ((opt = av_opt_next (obj, opt))) {
|
|
if (opt->type == AV_OPT_TYPE_CONST && !g_strcmp0 (top_opt->unit, opt->unit)) {
|
|
GEnumValue val;
|
|
|
|
val.value = opt->default_val.i64;
|
|
val.value_name = g_strdup (opt->help ? opt->help : opt->name);
|
|
val.value_nick = g_strdup (opt->name);
|
|
|
|
if (opt->default_val.i64 == top_opt->default_val.i64)
|
|
none_default = FALSE;
|
|
|
|
g_array_append_val (values, val);
|
|
}
|
|
}
|
|
|
|
if (values->len) {
|
|
guint i = 0;
|
|
gint cur_val;
|
|
gboolean cur_val_set = FALSE;
|
|
|
|
/* Sometimes ffmpeg sets a default value but no named constants with
|
|
* this value, we assume this means "unspecified" and add our own
|
|
*/
|
|
if (none_default) {
|
|
GEnumValue val;
|
|
|
|
val.value = top_opt->default_val.i64;
|
|
val.value_name = g_strdup ("Unspecified");
|
|
val.value_nick = g_strdup ("unknown");
|
|
g_array_append_val (values, val);
|
|
}
|
|
|
|
g_array_sort (values, (GCompareFunc) cmp_enum_value);
|
|
|
|
/* Dedup, easy once sorted
|
|
* We do this because ffmpeg can expose multiple names for the
|
|
* same constant, the way we expose enums makes this too confusing.
|
|
*/
|
|
while (i < values->len) {
|
|
if (cur_val_set) {
|
|
if (g_array_index (values, GEnumValue, i).value == cur_val) {
|
|
g_array_remove_index (values, i);
|
|
} else {
|
|
cur_val = g_array_index (values, GEnumValue, i).value;
|
|
i++;
|
|
}
|
|
} else {
|
|
cur_val = g_array_index (values, GEnumValue, i).value;
|
|
cur_val_set = TRUE;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
res =
|
|
g_enum_register_static (enum_name, &g_array_index (values, GEnumValue,
|
|
0));
|
|
}
|
|
|
|
done:
|
|
g_free (lower_obj_name);
|
|
g_free (enum_name);
|
|
return res;
|
|
}
|
|
|
|
static gint
|
|
cmp_flags_value (GEnumValue * val1, GEnumValue * val2)
|
|
{
|
|
return val1->value - val2->value;
|
|
}
|
|
|
|
static GType
|
|
register_flags (const AVClass ** obj, const AVOption * top_opt)
|
|
{
|
|
const AVOption *opt = NULL;
|
|
GType res = 0;
|
|
GArray *values = g_array_new (TRUE, TRUE, sizeof (GEnumValue));
|
|
gchar *lower_obj_name = g_ascii_strdown ((*obj)->class_name, -1);
|
|
gchar *flags_name = g_strdup_printf ("%s-%s", lower_obj_name, top_opt->unit);
|
|
|
|
g_strcanon (flags_name, G_CSET_a_2_z G_CSET_DIGITS, '-');
|
|
|
|
if ((res = g_type_from_name (flags_name)))
|
|
goto done;
|
|
|
|
while ((opt = av_opt_next (obj, opt))) {
|
|
if (opt->type == AV_OPT_TYPE_CONST && !g_strcmp0 (top_opt->unit, opt->unit)) {
|
|
GFlagsValue val;
|
|
|
|
/* We expose pass manually, hardcoding this isn't very nice, but
|
|
* I don't expect we want to do that sort of things often enough
|
|
* to warrant a general mechanism
|
|
*/
|
|
if (!g_strcmp0 (top_opt->name, "flags")) {
|
|
if (opt->default_val.i64 == AV_CODEC_FLAG_QSCALE ||
|
|
opt->default_val.i64 == AV_CODEC_FLAG_PASS1 ||
|
|
opt->default_val.i64 == AV_CODEC_FLAG_PASS2) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
val.value = opt->default_val.i64;
|
|
val.value_name = g_strdup (opt->help ? opt->help : opt->name);
|
|
val.value_nick = g_strdup (opt->name);
|
|
|
|
g_array_append_val (values, val);
|
|
}
|
|
}
|
|
|
|
if (values->len) {
|
|
g_array_sort (values, (GCompareFunc) cmp_flags_value);
|
|
|
|
res =
|
|
g_flags_register_static (flags_name, &g_array_index (values,
|
|
GFlagsValue, 0));
|
|
}
|
|
|
|
done:
|
|
g_free (lower_obj_name);
|
|
g_free (flags_name);
|
|
return res;
|
|
}
|
|
|
|
static guint
|
|
install_opts (GObjectClass * gobject_class, const AVClass ** obj, guint prop_id,
|
|
gint flags, const gchar * extra_help, GHashTable * overrides)
|
|
{
|
|
const AVOption *opt = NULL;
|
|
|
|
while ((opt = av_opt_next (obj, opt))) {
|
|
GParamSpec *pspec = NULL;
|
|
AVOptionRanges *r;
|
|
gdouble min = G_MINDOUBLE;
|
|
gdouble max = G_MAXDOUBLE;
|
|
gchar *help;
|
|
const gchar *name;
|
|
|
|
if (overrides && g_hash_table_contains (overrides, opt->name)) {
|
|
gboolean skip;
|
|
const GstStructure *s =
|
|
(GstStructure *) g_hash_table_lookup (overrides, opt->name);
|
|
|
|
name = gst_structure_get_name (s);
|
|
if (gst_structure_get_boolean (s, "skip", &skip) && skip) {
|
|
continue;
|
|
}
|
|
} else {
|
|
name = opt->name;
|
|
}
|
|
|
|
if ((opt->flags & flags) != flags)
|
|
continue;
|
|
|
|
if (g_object_class_find_property (gobject_class, name))
|
|
continue;
|
|
|
|
if (av_opt_query_ranges (&r, obj, opt->name, AV_OPT_SEARCH_FAKE_OBJ) >= 0) {
|
|
if (r->nb_ranges == 1) {
|
|
min = r->range[0]->value_min;
|
|
max = r->range[0]->value_max;
|
|
}
|
|
av_opt_freep_ranges (&r);
|
|
}
|
|
|
|
help = g_strdup_printf ("%s%s", opt->help, extra_help);
|
|
|
|
switch (opt->type) {
|
|
case AV_OPT_TYPE_INT:
|
|
if (opt->unit) {
|
|
GType enum_gtype;
|
|
enum_gtype = register_enum (obj, opt);
|
|
|
|
if (enum_gtype) {
|
|
pspec = g_param_spec_enum (name, name, help,
|
|
enum_gtype, opt->default_val.i64, G_PARAM_READWRITE);
|
|
g_object_class_install_property (gobject_class, prop_id++, pspec);
|
|
} else { /* Some options have a unit but no named constants associated */
|
|
pspec = g_param_spec_int (name, name, help,
|
|
(gint) min, (gint) max, opt->default_val.i64,
|
|
G_PARAM_READWRITE);
|
|
g_object_class_install_property (gobject_class, prop_id++, pspec);
|
|
}
|
|
} else {
|
|
pspec = g_param_spec_int (name, name, help,
|
|
(gint) min, (gint) max, opt->default_val.i64, G_PARAM_READWRITE);
|
|
g_object_class_install_property (gobject_class, prop_id++, pspec);
|
|
}
|
|
break;
|
|
case AV_OPT_TYPE_FLAGS:
|
|
if (opt->unit) {
|
|
GType flags_gtype;
|
|
flags_gtype = register_flags (obj, opt);
|
|
|
|
if (flags_gtype) {
|
|
pspec = g_param_spec_flags (name, name, help,
|
|
flags_gtype, opt->default_val.i64, G_PARAM_READWRITE);
|
|
g_object_class_install_property (gobject_class, prop_id++, pspec);
|
|
}
|
|
}
|
|
break;
|
|
case AV_OPT_TYPE_DURATION: /* Fall through */
|
|
case AV_OPT_TYPE_INT64:
|
|
/* FIXME 2.0: Workaround for worst property related API change. We
|
|
* continue using a 32 bit integer for the bitrate property as
|
|
* otherwise too much existing code will fail at runtime.
|
|
*
|
|
* See https://gitlab.freedesktop.org/gstreamer/gst-libav/issues/41#note_142808 */
|
|
if (g_strcmp0 (name, "bitrate") == 0) {
|
|
pspec = g_param_spec_int (name, name, help,
|
|
(gint) MAX (min, G_MININT), (gint) MIN (max, G_MAXINT),
|
|
(gint) opt->default_val.i64, G_PARAM_READWRITE);
|
|
} else {
|
|
/* ffmpeg expresses all ranges with doubles, this is sad */
|
|
pspec = g_param_spec_int64 (name, name, help,
|
|
(min == (gdouble) INT64_MIN ? INT64_MIN : (gint64) min),
|
|
(max == (gdouble) INT64_MAX ? INT64_MAX : (gint64) max),
|
|
opt->default_val.i64, G_PARAM_READWRITE);
|
|
}
|
|
g_object_class_install_property (gobject_class, prop_id++, pspec);
|
|
break;
|
|
case AV_OPT_TYPE_DOUBLE:
|
|
pspec = g_param_spec_double (name, name, help,
|
|
min, max, opt->default_val.dbl, G_PARAM_READWRITE);
|
|
g_object_class_install_property (gobject_class, prop_id++, pspec);
|
|
break;
|
|
case AV_OPT_TYPE_FLOAT:
|
|
pspec = g_param_spec_float (name, name, help,
|
|
(gfloat) min, (gfloat) max, (gfloat) opt->default_val.dbl,
|
|
G_PARAM_READWRITE);
|
|
g_object_class_install_property (gobject_class, prop_id++, pspec);
|
|
break;
|
|
case AV_OPT_TYPE_STRING:
|
|
pspec = g_param_spec_string (name, name, help,
|
|
opt->default_val.str, G_PARAM_READWRITE);
|
|
g_object_class_install_property (gobject_class, prop_id++, pspec);
|
|
break;
|
|
case AV_OPT_TYPE_UINT64:
|
|
/* ffmpeg expresses all ranges with doubles, this is appalling */
|
|
pspec = g_param_spec_uint64 (name, name, help,
|
|
(gint64) (min == (gdouble) 0 ? 0 : min),
|
|
(gint64) (max == (gdouble) UINT64_MAX ? UINT64_MAX : min),
|
|
opt->default_val.i64, G_PARAM_READWRITE);
|
|
g_object_class_install_property (gobject_class, prop_id++, pspec);
|
|
break;
|
|
case AV_OPT_TYPE_BOOL:
|
|
pspec = g_param_spec_boolean (name, name, help,
|
|
opt->default_val.i64 ? TRUE : FALSE, G_PARAM_READWRITE);
|
|
g_object_class_install_property (gobject_class, prop_id++, pspec);
|
|
break;
|
|
/* TODO: didn't find options for the video encoders with
|
|
* the following type, add support if needed */
|
|
case AV_OPT_TYPE_CHANNEL_LAYOUT:
|
|
case AV_OPT_TYPE_COLOR:
|
|
case AV_OPT_TYPE_VIDEO_RATE:
|
|
case AV_OPT_TYPE_SAMPLE_FMT:
|
|
case AV_OPT_TYPE_PIXEL_FMT:
|
|
case AV_OPT_TYPE_IMAGE_SIZE:
|
|
case AV_OPT_TYPE_DICT:
|
|
case AV_OPT_TYPE_BINARY:
|
|
case AV_OPT_TYPE_RATIONAL:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
g_free (help);
|
|
|
|
if (pspec) {
|
|
g_param_spec_set_qdata (pspec, avoption_quark, (gpointer) opt);
|
|
}
|
|
}
|
|
|
|
return prop_id;
|
|
}
|
|
|
|
void
|
|
gst_ffmpeg_cfg_install_properties (GObjectClass * klass, AVCodec * in_plugin,
|
|
guint base, gint flags)
|
|
{
|
|
gint prop_id;
|
|
AVCodecContext *ctx;
|
|
|
|
prop_id = base;
|
|
g_return_if_fail (base > 0);
|
|
|
|
ctx = avcodec_alloc_context3 (in_plugin);
|
|
if (!ctx)
|
|
g_warning ("could not get context");
|
|
|
|
prop_id =
|
|
install_opts ((GObjectClass *) klass, &in_plugin->priv_class, prop_id, 0,
|
|
" (Private codec option)", NULL);
|
|
prop_id =
|
|
install_opts ((GObjectClass *) klass, &ctx->av_class, prop_id, flags,
|
|
" (Generic codec option, might have no effect)", generic_overrides);
|
|
|
|
if (ctx) {
|
|
gst_ffmpeg_avcodec_close (ctx);
|
|
av_free (ctx);
|
|
}
|
|
}
|
|
|
|
static gint
|
|
set_option_value (AVCodecContext * ctx, GParamSpec * pspec,
|
|
const GValue * value, const AVOption * opt)
|
|
{
|
|
int res = -1;
|
|
|
|
switch (G_PARAM_SPEC_VALUE_TYPE (pspec)) {
|
|
case G_TYPE_INT:
|
|
res = av_opt_set_int (ctx, opt->name,
|
|
g_value_get_int (value), AV_OPT_SEARCH_CHILDREN);
|
|
break;
|
|
case G_TYPE_INT64:
|
|
res = av_opt_set_int (ctx, opt->name,
|
|
g_value_get_int64 (value), AV_OPT_SEARCH_CHILDREN);
|
|
break;
|
|
case G_TYPE_UINT64:
|
|
res = av_opt_set_int (ctx, opt->name,
|
|
g_value_get_uint64 (value), AV_OPT_SEARCH_CHILDREN);
|
|
break;
|
|
case G_TYPE_DOUBLE:
|
|
res = av_opt_set_double (ctx, opt->name,
|
|
g_value_get_double (value), AV_OPT_SEARCH_CHILDREN);
|
|
break;
|
|
case G_TYPE_FLOAT:
|
|
res = av_opt_set_double (ctx, opt->name,
|
|
g_value_get_float (value), AV_OPT_SEARCH_CHILDREN);
|
|
break;
|
|
case G_TYPE_STRING:
|
|
res = av_opt_set (ctx, opt->name,
|
|
g_value_get_string (value), AV_OPT_SEARCH_CHILDREN);
|
|
/* Some code in FFmpeg returns ENOMEM if the string is NULL:
|
|
* *dst = av_strdup(val);
|
|
* return *dst ? 0 : AVERROR(ENOMEM);
|
|
* That makes little sense, let's ignore that
|
|
*/
|
|
if (!g_value_get_string (value))
|
|
res = 0;
|
|
break;
|
|
case G_TYPE_BOOLEAN:
|
|
res = av_opt_set_int (ctx, opt->name,
|
|
g_value_get_boolean (value), AV_OPT_SEARCH_CHILDREN);
|
|
break;
|
|
default:
|
|
if (G_IS_PARAM_SPEC_ENUM (pspec)) {
|
|
res = av_opt_set_int (ctx, opt->name,
|
|
g_value_get_enum (value), AV_OPT_SEARCH_CHILDREN);
|
|
} else if (G_IS_PARAM_SPEC_FLAGS (pspec)) {
|
|
res = av_opt_set_int (ctx, opt->name,
|
|
g_value_get_flags (value), AV_OPT_SEARCH_CHILDREN);
|
|
} else { /* oops, bit lazy we don't cover this case yet */
|
|
g_critical ("%s does not yet support type %s", GST_FUNCTION,
|
|
g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
gboolean
|
|
gst_ffmpeg_cfg_set_property (AVCodecContext * refcontext, const GValue * value,
|
|
GParamSpec * pspec)
|
|
{
|
|
const AVOption *opt;
|
|
|
|
opt = g_param_spec_get_qdata (pspec, avoption_quark);
|
|
|
|
if (!opt)
|
|
return FALSE;
|
|
|
|
return set_option_value (refcontext, pspec, value, opt) >= 0;
|
|
}
|
|
|
|
gboolean
|
|
gst_ffmpeg_cfg_get_property (AVCodecContext * refcontext, GValue * value,
|
|
GParamSpec * pspec)
|
|
{
|
|
const AVOption *opt;
|
|
int res = -1;
|
|
|
|
opt = g_param_spec_get_qdata (pspec, avoption_quark);
|
|
|
|
if (!opt)
|
|
return FALSE;
|
|
|
|
switch (G_PARAM_SPEC_VALUE_TYPE (pspec)) {
|
|
case G_TYPE_INT:
|
|
{
|
|
int64_t val;
|
|
if ((res = av_opt_get_int (refcontext, opt->name,
|
|
AV_OPT_SEARCH_CHILDREN, &val) >= 0))
|
|
g_value_set_int (value, val);
|
|
break;
|
|
}
|
|
case G_TYPE_INT64:
|
|
{
|
|
int64_t val;
|
|
if ((res = av_opt_get_int (refcontext, opt->name,
|
|
AV_OPT_SEARCH_CHILDREN, &val) >= 0))
|
|
g_value_set_int64 (value, val);
|
|
break;
|
|
}
|
|
case G_TYPE_UINT64:
|
|
{
|
|
int64_t val;
|
|
if ((res = av_opt_get_int (refcontext, opt->name,
|
|
AV_OPT_SEARCH_CHILDREN, &val) >= 0))
|
|
g_value_set_uint64 (value, val);
|
|
break;
|
|
}
|
|
case G_TYPE_DOUBLE:
|
|
{
|
|
gdouble val;
|
|
if ((res = av_opt_get_double (refcontext, opt->name,
|
|
AV_OPT_SEARCH_CHILDREN, &val) >= 0))
|
|
g_value_set_double (value, val);
|
|
break;
|
|
}
|
|
case G_TYPE_FLOAT:
|
|
{
|
|
gdouble val;
|
|
if ((res = av_opt_get_double (refcontext, opt->name,
|
|
AV_OPT_SEARCH_CHILDREN, &val) >= 0))
|
|
g_value_set_float (value, (gfloat) val);
|
|
break;
|
|
}
|
|
case G_TYPE_STRING:
|
|
{
|
|
uint8_t *val;
|
|
if ((res = av_opt_get (refcontext, opt->name,
|
|
AV_OPT_SEARCH_CHILDREN | AV_OPT_ALLOW_NULL, &val) >= 0)) {
|
|
g_value_set_string (value, (gchar *) val);
|
|
}
|
|
break;
|
|
}
|
|
case G_TYPE_BOOLEAN:
|
|
{
|
|
int64_t val;
|
|
if ((res = av_opt_get_int (refcontext, opt->name,
|
|
AV_OPT_SEARCH_CHILDREN, &val) >= 0))
|
|
g_value_set_boolean (value, val ? TRUE : FALSE);
|
|
break;
|
|
}
|
|
default:
|
|
if (G_IS_PARAM_SPEC_ENUM (pspec)) {
|
|
int64_t val;
|
|
|
|
if ((res = av_opt_get_int (refcontext, opt->name,
|
|
AV_OPT_SEARCH_CHILDREN, &val) >= 0))
|
|
g_value_set_enum (value, val);
|
|
} else if (G_IS_PARAM_SPEC_FLAGS (pspec)) {
|
|
int64_t val;
|
|
|
|
if ((res = av_opt_get_int (refcontext, opt->name,
|
|
AV_OPT_SEARCH_CHILDREN, &val) >= 0))
|
|
g_value_set_flags (value, val);
|
|
} else { /* oops, bit lazy we don't cover this case yet */
|
|
g_critical ("%s does not yet support type %s", GST_FUNCTION,
|
|
g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
|
|
}
|
|
}
|
|
|
|
return res >= 0;
|
|
}
|
|
|
|
void
|
|
gst_ffmpeg_cfg_fill_context (GObject * object, AVCodecContext * context)
|
|
{
|
|
GParamSpec **pspecs;
|
|
guint num_props, i;
|
|
|
|
pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object),
|
|
&num_props);
|
|
|
|
for (i = 0; i < num_props; ++i) {
|
|
GParamSpec *pspec = pspecs[i];
|
|
const AVOption *opt;
|
|
GValue value = G_VALUE_INIT;
|
|
|
|
opt = g_param_spec_get_qdata (pspec, avoption_quark);
|
|
|
|
if (!opt)
|
|
continue;
|
|
|
|
g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
|
|
g_object_get_property (object, pspec->name, &value);
|
|
set_option_value (context, pspec, &value, opt);
|
|
g_value_unset (&value);
|
|
}
|
|
g_free (pspecs);
|
|
}
|
|
|
|
void
|
|
gst_ffmpeg_cfg_finalize (void)
|
|
{
|
|
GST_ERROR ("Finalizing");
|
|
g_assert (generic_overrides);
|
|
g_hash_table_unref (generic_overrides);
|
|
}
|