mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
videoaggregator: don't do caps processing that is not overridable
Allows the subclass to completely override the chosen src caps. This is needed as videoaggregator generally has no idea exactly what operation is being performed. - Adds a fixate_caps vfunc for fixation - Merges gst_video_aggregator_update_converters() into gst_videoaggregator_update_src_caps() as we need some of its info for proper caps handling. - Pass the downstream caps to the update_caps vfunc https://bugzilla.gnome.org/show_bug.cgi?id=756207
This commit is contained in:
parent
adec074d7e
commit
f1323fb6df
6 changed files with 295 additions and 235 deletions
|
@ -221,9 +221,17 @@ gst_gl_mixer_pad_sink_acceptcaps (GstPad * pad, GstGLMixer * mix,
|
|||
|
||||
/* copies the given caps */
|
||||
static GstCaps *
|
||||
_update_caps (GstVideoAggregator * vagg, GstCaps * caps)
|
||||
_update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter)
|
||||
{
|
||||
return gst_gl_caps_replace_all_caps_features (caps,
|
||||
GstCaps *tmp;
|
||||
|
||||
if (filter) {
|
||||
tmp = gst_caps_intersect (caps, filter);
|
||||
} else {
|
||||
tmp = caps;
|
||||
}
|
||||
|
||||
return gst_gl_caps_replace_all_caps_features (tmp,
|
||||
GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,8 @@ GST_DEBUG_CATEGORY (gst_gl_stereo_mix_debug);
|
|||
#define gst_gl_stereo_mix_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstGLStereoMix, gst_gl_stereo_mix, GST_TYPE_GL_MIXER);
|
||||
|
||||
static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps);
|
||||
static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps,
|
||||
GstCaps * filter);
|
||||
static gboolean _negotiated_caps (GstVideoAggregator * videoaggregator,
|
||||
GstCaps * caps);
|
||||
gboolean gst_gl_stereo_mix_make_output (GstGLStereoMix * mix);
|
||||
|
@ -153,7 +154,6 @@ gst_gl_stereo_mix_class_init (GstGLStereoMixClass * klass)
|
|||
videoaggregator_class->get_output_buffer =
|
||||
gst_gl_stereo_mix_get_output_buffer;
|
||||
videoaggregator_class->find_best_format = gst_gl_stereo_mix_find_best_format;
|
||||
videoaggregator_class->preserve_update_caps_result = TRUE;
|
||||
|
||||
base_mix_class->supported_gl_api = GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
|
||||
}
|
||||
|
@ -471,7 +471,7 @@ get_converted_caps (GstGLStereoMix * mix, GstCaps * caps)
|
|||
|
||||
/* Return the possible output caps we decided in find_best_format() */
|
||||
static GstCaps *
|
||||
_update_caps (GstVideoAggregator * vagg, GstCaps * caps)
|
||||
_update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter)
|
||||
{
|
||||
GstGLStereoMix *mix = GST_GL_STEREO_MIX (vagg);
|
||||
|
||||
|
|
|
@ -460,7 +460,9 @@ static void gst_gl_video_mixer_set_property (GObject * object, guint prop_id,
|
|||
static void gst_gl_video_mixer_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps);
|
||||
static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps,
|
||||
GstCaps * filter);
|
||||
static GstCaps *_fixate_caps (GstVideoAggregator * vagg, GstCaps * caps);
|
||||
static void gst_gl_video_mixer_reset (GstGLMixer * mixer);
|
||||
static gboolean gst_gl_video_mixer_init_shader (GstGLMixer * mixer,
|
||||
GstCaps * outcaps);
|
||||
|
@ -863,6 +865,7 @@ gst_gl_video_mixer_class_init (GstGLVideoMixerClass * klass)
|
|||
gst_gl_video_mixer_process_textures;
|
||||
|
||||
vagg_class->update_caps = _update_caps;
|
||||
vagg_class->fixate_caps = _fixate_caps;
|
||||
|
||||
agg_class->sinkpads_type = GST_TYPE_GL_VIDEO_MIXER_PAD;
|
||||
|
||||
|
@ -912,9 +915,9 @@ gst_gl_video_mixer_get_property (GObject * object, guint prop_id,
|
|||
|
||||
static void
|
||||
_mixer_pad_get_output_size (GstGLVideoMixer * mix,
|
||||
GstGLVideoMixerPad * mix_pad, gint * width, gint * height)
|
||||
GstGLVideoMixerPad * mix_pad, gint out_par_n, gint out_par_d, gint * width,
|
||||
gint * height)
|
||||
{
|
||||
GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix);
|
||||
GstVideoAggregatorPad *vagg_pad = GST_VIDEO_AGGREGATOR_PAD (mix_pad);
|
||||
gint pad_width, pad_height;
|
||||
guint dar_n, dar_d;
|
||||
|
@ -937,13 +940,10 @@ _mixer_pad_get_output_size (GstGLVideoMixer * mix,
|
|||
|
||||
gst_video_calculate_display_ratio (&dar_n, &dar_d, pad_width, pad_height,
|
||||
GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
|
||||
GST_VIDEO_INFO_PAR_D (&vagg_pad->info),
|
||||
GST_VIDEO_INFO_PAR_N (&vagg->info), GST_VIDEO_INFO_PAR_D (&vagg->info)
|
||||
);
|
||||
GST_VIDEO_INFO_PAR_D (&vagg_pad->info), out_par_n, out_par_d);
|
||||
GST_LOG_OBJECT (mix_pad, "scaling %ux%u by %u/%u (%u/%u / %u/%u)", pad_width,
|
||||
pad_height, dar_n, dar_d, GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
|
||||
GST_VIDEO_INFO_PAR_D (&vagg_pad->info),
|
||||
GST_VIDEO_INFO_PAR_N (&vagg->info), GST_VIDEO_INFO_PAR_D (&vagg->info));
|
||||
GST_VIDEO_INFO_PAR_D (&vagg_pad->info), out_par_n, out_par_d);
|
||||
|
||||
if (pad_height % dar_n == 0) {
|
||||
pad_width = gst_util_uint64_scale_int (pad_height, dar_n, dar_d);
|
||||
|
@ -960,17 +960,45 @@ _mixer_pad_get_output_size (GstGLVideoMixer * mix,
|
|||
}
|
||||
|
||||
static GstCaps *
|
||||
_update_caps (GstVideoAggregator * vagg, GstCaps * caps)
|
||||
_update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter)
|
||||
{
|
||||
GstCaps *ret;
|
||||
|
||||
ret =
|
||||
GST_VIDEO_AGGREGATOR_CLASS (gst_gl_video_mixer_parent_class)->update_caps
|
||||
(vagg, caps, NULL);
|
||||
|
||||
if (filter) {
|
||||
GstCaps *tmp = gst_caps_intersect (ret, filter);
|
||||
gst_caps_unref (ret);
|
||||
ret = tmp;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
_fixate_caps (GstVideoAggregator * vagg, GstCaps * caps)
|
||||
{
|
||||
GstGLVideoMixer *mix = GST_GL_VIDEO_MIXER (vagg);
|
||||
GList *l;
|
||||
gint best_width = -1, best_height = -1;
|
||||
GstVideoInfo info;
|
||||
gint best_width = 0, best_height = 0;
|
||||
gint best_fps_n = 0, best_fps_d = 0;
|
||||
gint par_n, par_d;
|
||||
gdouble best_fps = 0.;
|
||||
GstCaps *ret = NULL;
|
||||
int i;
|
||||
GstStructure *s;
|
||||
GList *l;
|
||||
|
||||
caps = gst_caps_make_writable (caps);
|
||||
gst_video_info_from_caps (&info, caps);
|
||||
ret = gst_caps_make_writable (caps);
|
||||
|
||||
/* we need this to calculate how large to make the output frame */
|
||||
s = gst_caps_get_structure (ret, 0);
|
||||
if (gst_structure_has_field (s, "pixel-aspect-ratio")) {
|
||||
gst_structure_fixate_field_nearest_fraction (s, "pixel-aspect-ratio", 1, 1);
|
||||
gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
|
||||
} else {
|
||||
par_n = par_d = 1;
|
||||
}
|
||||
|
||||
GST_OBJECT_LOCK (vagg);
|
||||
for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
|
||||
|
@ -978,8 +1006,12 @@ _update_caps (GstVideoAggregator * vagg, GstCaps * caps)
|
|||
GstGLVideoMixerPad *mixer_pad = GST_GL_VIDEO_MIXER_PAD (vaggpad);
|
||||
gint this_width, this_height;
|
||||
gint width, height;
|
||||
gint fps_n, fps_d;
|
||||
gdouble cur_fps;
|
||||
|
||||
_mixer_pad_get_output_size (mix, mixer_pad, &width, &height);
|
||||
fps_n = GST_VIDEO_INFO_FPS_N (&vaggpad->info);
|
||||
fps_d = GST_VIDEO_INFO_FPS_D (&vaggpad->info);
|
||||
_mixer_pad_get_output_size (mix, mixer_pad, par_n, par_d, &width, &height);
|
||||
|
||||
if (width == 0 || height == 0)
|
||||
continue;
|
||||
|
@ -991,20 +1023,34 @@ _update_caps (GstVideoAggregator * vagg, GstCaps * caps)
|
|||
best_width = this_width;
|
||||
if (best_height < this_height)
|
||||
best_height = this_height;
|
||||
|
||||
if (fps_d == 0)
|
||||
cur_fps = 0.0;
|
||||
else
|
||||
gst_util_fraction_to_double (fps_n, fps_d, &cur_fps);
|
||||
|
||||
if (best_fps < cur_fps) {
|
||||
best_fps = cur_fps;
|
||||
best_fps_n = fps_n;
|
||||
best_fps_d = fps_d;
|
||||
}
|
||||
}
|
||||
GST_OBJECT_UNLOCK (vagg);
|
||||
|
||||
ret =
|
||||
GST_VIDEO_AGGREGATOR_CLASS (gst_gl_video_mixer_parent_class)->update_caps
|
||||
(vagg, caps);
|
||||
|
||||
for (i = 0; i < gst_caps_get_size (ret); i++) {
|
||||
GstStructure *s = gst_caps_get_structure (ret, i);
|
||||
|
||||
gst_structure_set (s, "width", G_TYPE_INT, best_width, "height", G_TYPE_INT,
|
||||
best_height, NULL);
|
||||
if (best_fps_n <= 0 || best_fps_d <= 0 || best_fps == 0.0) {
|
||||
best_fps_n = 25;
|
||||
best_fps_d = 1;
|
||||
best_fps = 25.0;
|
||||
}
|
||||
|
||||
s = gst_caps_get_structure (ret, 0);
|
||||
gst_structure_fixate_field_nearest_int (s, "width", best_width);
|
||||
gst_structure_fixate_field_nearest_int (s, "height", best_height);
|
||||
gst_structure_fixate_field_nearest_fraction (s, "framerate", best_fps_n,
|
||||
best_fps_d);
|
||||
gst_structure_fixate_field_nearest_fraction (s, "pixel-aspect-ratio", 1, 1);
|
||||
ret = gst_caps_fixate (ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1397,7 +1443,9 @@ gst_gl_video_mixer_callback (gpointer stuff)
|
|||
gint pad_width, pad_height;
|
||||
gfloat w, h;
|
||||
|
||||
_mixer_pad_get_output_size (video_mixer, pad, &pad_width, &pad_height);
|
||||
_mixer_pad_get_output_size (video_mixer, pad,
|
||||
GST_VIDEO_INFO_PAR_N (&vagg->info),
|
||||
GST_VIDEO_INFO_PAR_D (&vagg->info), &pad_width, &pad_height);
|
||||
|
||||
w = ((gfloat) pad_width / (gfloat) out_width);
|
||||
h = ((gfloat) pad_height / (gfloat) out_height);
|
||||
|
|
|
@ -532,86 +532,6 @@ gst_videoaggreagator_find_best_format (GstVideoAggregator * vagg,
|
|||
g_hash_table_unref (formats_table);
|
||||
}
|
||||
|
||||
/* WITH GST_VIDEO_AGGREGATOR_LOCK TAKEN
|
||||
* NOTE: After calling that method you **have to** call
|
||||
* gst_videoaggregator_update_src_caps (without releasing
|
||||
* the GST_VIDEO_AGGREGATOR_LOCK in between)
|
||||
*/
|
||||
static gboolean
|
||||
gst_videoaggregator_update_converters (GstVideoAggregator * vagg)
|
||||
{
|
||||
GList *tmp;
|
||||
GstVideoFormat best_format;
|
||||
GstVideoInfo best_info;
|
||||
gboolean at_least_one_alpha = FALSE;
|
||||
GstCaps *downstream_caps;
|
||||
GstAggregator *agg = GST_AGGREGATOR (vagg);
|
||||
|
||||
GstVideoAggregatorClass *vagg_class = GST_VIDEO_AGGREGATOR_GET_CLASS (vagg);
|
||||
GstVideoAggregatorPadClass *vaggpad_class = g_type_class_peek
|
||||
(GST_AGGREGATOR_GET_CLASS (vagg)->sinkpads_type);
|
||||
|
||||
best_format = GST_VIDEO_FORMAT_UNKNOWN;
|
||||
gst_video_info_init (&best_info);
|
||||
|
||||
downstream_caps = gst_pad_get_allowed_caps (agg->srcpad);
|
||||
|
||||
if (!downstream_caps || gst_caps_is_empty (downstream_caps)) {
|
||||
GST_INFO_OBJECT (vagg, "No downstream caps found %"
|
||||
GST_PTR_FORMAT, downstream_caps);
|
||||
if (downstream_caps)
|
||||
gst_caps_unref (downstream_caps);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
if (vagg_class->find_best_format) {
|
||||
vagg_class->find_best_format (vagg, downstream_caps, &best_info,
|
||||
&at_least_one_alpha);
|
||||
|
||||
best_format = GST_VIDEO_INFO_FORMAT (&best_info);
|
||||
}
|
||||
|
||||
if (best_format == GST_VIDEO_FORMAT_UNKNOWN) {
|
||||
downstream_caps = gst_caps_fixate (downstream_caps);
|
||||
gst_video_info_from_caps (&best_info, downstream_caps);
|
||||
best_format = GST_VIDEO_INFO_FORMAT (&best_info);
|
||||
}
|
||||
|
||||
gst_caps_unref (downstream_caps);
|
||||
|
||||
if (at_least_one_alpha
|
||||
&& !(best_info.finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA)) {
|
||||
GST_ELEMENT_ERROR (vagg, CORE, NEGOTIATION,
|
||||
("At least one of the input pads contains alpha, but downstream can't support alpha."),
|
||||
("Either convert your inputs to not contain alpha or add a videoconvert after the aggregator"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
vagg->info = best_info;
|
||||
|
||||
GST_DEBUG_OBJECT (vagg,
|
||||
"The output format will now be : %d with chroma : %s",
|
||||
best_format, gst_video_chroma_to_string (best_info.chroma_site));
|
||||
|
||||
if (vaggpad_class->set_info) {
|
||||
GST_OBJECT_LOCK (vagg);
|
||||
/* Then browse the sinks once more, setting or unsetting conversion if needed */
|
||||
for (tmp = GST_ELEMENT (vagg)->sinkpads; tmp; tmp = tmp->next) {
|
||||
GstVideoAggregatorPad *pad = GST_VIDEO_AGGREGATOR_PAD (tmp->data);
|
||||
|
||||
if (!vaggpad_class->set_info (pad, vagg, &pad->info, &best_info)) {
|
||||
GST_OBJECT_UNLOCK (vagg);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
GST_OBJECT_UNLOCK (vagg);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* WITH GST_VIDEO_AGGREGATOR_LOCK TAKEN */
|
||||
static gboolean
|
||||
gst_videoaggregator_src_setcaps (GstVideoAggregator * vagg, GstCaps * caps)
|
||||
|
@ -662,25 +582,22 @@ done:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* WITH GST_VIDEO_AGGREGATOR_LOCK TAKEN */
|
||||
static gboolean
|
||||
gst_videoaggregator_update_src_caps (GstVideoAggregator * vagg)
|
||||
static GstCaps *
|
||||
gst_videoaggregator_default_fixate_caps (GstVideoAggregator * vagg,
|
||||
GstCaps * caps)
|
||||
{
|
||||
GList *l;
|
||||
gint best_width = -1, best_height = -1;
|
||||
gdouble best_fps = -1, cur_fps;
|
||||
gint best_fps_n = -1, best_fps_d = -1;
|
||||
gboolean ret = TRUE;
|
||||
GstElementClass *klass = GST_ELEMENT_GET_CLASS (vagg);
|
||||
GstVideoAggregatorClass *vagg_klass = (GstVideoAggregatorClass *) klass;
|
||||
GstAggregator *agg = GST_AGGREGATOR (vagg);
|
||||
gdouble best_fps = -1.;
|
||||
GstStructure *s;
|
||||
GList *l;
|
||||
|
||||
GST_OBJECT_LOCK (vagg);
|
||||
for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
|
||||
GstVideoAggregatorPad *mpad = l->data;
|
||||
gint this_width, this_height;
|
||||
gint fps_n, fps_d;
|
||||
gint width, height;
|
||||
gdouble cur_fps;
|
||||
|
||||
fps_n = GST_VIDEO_INFO_FPS_N (&mpad->info);
|
||||
fps_d = GST_VIDEO_INFO_FPS_D (&mpad->info);
|
||||
|
@ -690,13 +607,10 @@ gst_videoaggregator_update_src_caps (GstVideoAggregator * vagg)
|
|||
if (width == 0 || height == 0)
|
||||
continue;
|
||||
|
||||
this_width = width;
|
||||
this_height = height;
|
||||
|
||||
if (best_width < this_width)
|
||||
best_width = this_width;
|
||||
if (best_height < this_height)
|
||||
best_height = this_height;
|
||||
if (best_width < width)
|
||||
best_width = width;
|
||||
if (best_height < height)
|
||||
best_height = height;
|
||||
|
||||
if (fps_d == 0)
|
||||
cur_fps = 0.0;
|
||||
|
@ -717,88 +631,142 @@ gst_videoaggregator_update_src_caps (GstVideoAggregator * vagg)
|
|||
best_fps = 25.0;
|
||||
}
|
||||
|
||||
if (best_width > 0 && best_height > 0 && best_fps > 0) {
|
||||
GstCaps *caps, *peercaps, *info_caps;
|
||||
GstStructure *s;
|
||||
GstVideoInfo info;
|
||||
int i;
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
gst_structure_fixate_field_nearest_int (s, "width", best_width);
|
||||
gst_structure_fixate_field_nearest_int (s, "height", best_height);
|
||||
gst_structure_fixate_field_nearest_fraction (s, "framerate", best_fps_n,
|
||||
best_fps_d);
|
||||
if (gst_structure_has_field (s, "pixel-aspect-ratio"))
|
||||
gst_structure_fixate_field_nearest_fraction (s, "pixel-aspect-ratio", 1, 1);
|
||||
caps = gst_caps_fixate (caps);
|
||||
|
||||
/* Initialize the video info with our target format and
|
||||
* the best width and height and framerate. Then copy over
|
||||
* all other fields as we negotiated them before
|
||||
*/
|
||||
gst_video_info_set_format (&info, GST_VIDEO_INFO_FORMAT (&vagg->info),
|
||||
best_width, best_height);
|
||||
info.fps_n = best_fps_n;
|
||||
info.fps_d = best_fps_d;
|
||||
info.chroma_site = vagg->info.chroma_site;
|
||||
info.par_n = vagg->info.par_n;
|
||||
info.par_d = vagg->info.par_d;
|
||||
info.colorimetry = vagg->info.colorimetry;
|
||||
info.flags = vagg->info.flags;
|
||||
info.interlace_mode = vagg->info.interlace_mode;
|
||||
return caps;
|
||||
}
|
||||
|
||||
info_caps = gst_video_info_to_caps (&info);
|
||||
static GstCaps *
|
||||
gst_videoaggregator_default_update_caps (GstVideoAggregator * vagg,
|
||||
GstCaps * caps, GstCaps * filter)
|
||||
{
|
||||
GstCaps *ret;
|
||||
|
||||
if (vagg_klass->update_caps) {
|
||||
if (!(caps = vagg_klass->update_caps (vagg, info_caps))) {
|
||||
gst_caps_unref (info_caps);
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
gst_caps_unref (info_caps);
|
||||
} else {
|
||||
caps = info_caps;
|
||||
if (filter) {
|
||||
ret = gst_caps_intersect (caps, filter);
|
||||
} else {
|
||||
ret = gst_caps_ref (caps);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* WITH GST_VIDEO_AGGREGATOR_LOCK TAKEN */
|
||||
static gboolean
|
||||
gst_videoaggregator_update_src_caps (GstVideoAggregator * vagg)
|
||||
{
|
||||
GstVideoAggregatorClass *vagg_klass = GST_VIDEO_AGGREGATOR_GET_CLASS (vagg);
|
||||
GstVideoAggregatorPadClass *vaggpad_klass = g_type_class_peek
|
||||
(GST_AGGREGATOR_GET_CLASS (vagg)->sinkpads_type);
|
||||
GstAggregator *agg = GST_AGGREGATOR (vagg);
|
||||
gboolean ret = TRUE, at_least_one_pad_configured = FALSE;
|
||||
GstVideoFormat best_format;
|
||||
GstVideoInfo best_info;
|
||||
gboolean at_least_one_alpha = FALSE;
|
||||
GstCaps *downstream_caps;
|
||||
GList *l;
|
||||
|
||||
best_format = GST_VIDEO_FORMAT_UNKNOWN;
|
||||
gst_video_info_init (&best_info);
|
||||
|
||||
downstream_caps = gst_pad_get_allowed_caps (agg->srcpad);
|
||||
|
||||
if (!downstream_caps || gst_caps_is_empty (downstream_caps)) {
|
||||
GST_INFO_OBJECT (vagg, "No downstream caps found %"
|
||||
GST_PTR_FORMAT, downstream_caps);
|
||||
if (downstream_caps)
|
||||
gst_caps_unref (downstream_caps);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (vagg_klass->find_best_format) {
|
||||
vagg_klass->find_best_format (vagg, downstream_caps, &best_info,
|
||||
&at_least_one_alpha);
|
||||
|
||||
best_format = GST_VIDEO_INFO_FORMAT (&best_info);
|
||||
}
|
||||
|
||||
if (best_format == GST_VIDEO_FORMAT_UNKNOWN) {
|
||||
GstCaps *tmp = gst_caps_fixate (gst_caps_ref (downstream_caps));
|
||||
gst_video_info_from_caps (&best_info, tmp);
|
||||
best_format = GST_VIDEO_INFO_FORMAT (&best_info);
|
||||
gst_caps_unref (tmp);
|
||||
}
|
||||
|
||||
if (at_least_one_alpha
|
||||
&& !(best_info.finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA)) {
|
||||
GST_ELEMENT_ERROR (vagg, CORE, NEGOTIATION,
|
||||
("At least one of the input pads contains alpha, but downstream can't support alpha."),
|
||||
("Either convert your inputs to not contain alpha or add a videoconvert after the aggregator"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (vagg,
|
||||
"The output format will now be : %d with chroma : %s",
|
||||
best_format, gst_video_chroma_to_string (best_info.chroma_site));
|
||||
|
||||
GST_OBJECT_LOCK (vagg);
|
||||
for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
|
||||
GstVideoAggregatorPad *mpad = l->data;
|
||||
|
||||
if (GST_VIDEO_INFO_WIDTH (&mpad->info) == 0
|
||||
|| GST_VIDEO_INFO_HEIGHT (&mpad->info) == 0)
|
||||
continue;
|
||||
|
||||
at_least_one_pad_configured = TRUE;
|
||||
break;
|
||||
}
|
||||
GST_OBJECT_UNLOCK (vagg);
|
||||
|
||||
if (at_least_one_pad_configured) {
|
||||
GstCaps *caps, *peercaps;
|
||||
|
||||
peercaps = gst_pad_peer_query_caps (agg->srcpad, NULL);
|
||||
|
||||
g_assert (vagg_klass->update_caps);
|
||||
if (!(caps = vagg_klass->update_caps (vagg, downstream_caps, peercaps))) {
|
||||
GST_WARNING_OBJECT (vagg, "Subclass failed to update provided caps");
|
||||
gst_caps_unref (downstream_caps);
|
||||
if (peercaps)
|
||||
gst_caps_unref (peercaps);
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* If the sub-class allows it, allow size/framerate changes */
|
||||
if (!vagg_klass->preserve_update_caps_result) {
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
gst_structure_get (s, "width", G_TYPE_INT, &best_width, "height",
|
||||
G_TYPE_INT, &best_height, NULL);
|
||||
|
||||
for (i = 0; i < gst_caps_get_size (caps); i++) {
|
||||
s = gst_caps_get_structure (caps, i);
|
||||
gst_structure_set (s, "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
|
||||
"height", GST_TYPE_INT_RANGE, 1, G_MAXINT, "framerate",
|
||||
GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
peercaps = gst_pad_peer_query_caps (agg->srcpad, caps);
|
||||
if (peercaps) {
|
||||
GstCaps *tmp;
|
||||
|
||||
tmp = gst_caps_intersect (caps, peercaps);
|
||||
GST_DEBUG_OBJECT (vagg, "intersecting %" GST_PTR_FORMAT
|
||||
" with peer caps %" GST_PTR_FORMAT " result %" GST_PTR_FORMAT, caps,
|
||||
peercaps, tmp);
|
||||
|
||||
gst_caps_unref (caps);
|
||||
gst_caps_unref (downstream_caps);
|
||||
if (peercaps)
|
||||
gst_caps_unref (peercaps);
|
||||
caps = tmp; /* pass ownership */
|
||||
if (gst_caps_is_empty (caps)) {
|
||||
GST_DEBUG_OBJECT (vagg, "empty caps");
|
||||
|
||||
if (!gst_caps_is_fixed (caps)) {
|
||||
g_assert (vagg_klass->fixate_caps);
|
||||
|
||||
caps = gst_caps_make_writable (caps);
|
||||
if (!(caps = vagg_klass->fixate_caps (vagg, caps))) {
|
||||
GST_WARNING_OBJECT (vagg, "Subclass failed to fixate provided caps");
|
||||
ret = FALSE;
|
||||
gst_caps_unref (caps);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
caps = gst_caps_truncate (caps);
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
gst_structure_fixate_field_nearest_int (s, "width", best_width);
|
||||
gst_structure_fixate_field_nearest_int (s, "height", best_height);
|
||||
gst_structure_fixate_field_nearest_fraction (s, "framerate", best_fps_n,
|
||||
best_fps_d);
|
||||
gst_structure_fixate_field_nearest_fraction (s, "pixel-aspect-ratio", 1,
|
||||
1);
|
||||
gst_video_info_from_caps (&vagg->info, caps);
|
||||
|
||||
/* fixate the the rest of the fields */
|
||||
caps = gst_caps_fixate (caps);
|
||||
if (vaggpad_klass->set_info) {
|
||||
/* Then browse the sinks once more, setting or unsetting conversion if needed */
|
||||
for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
|
||||
GstVideoAggregatorPad *pad = GST_VIDEO_AGGREGATOR_PAD (l->data);
|
||||
|
||||
gst_structure_get_int (s, "width", &info.width);
|
||||
gst_structure_get_int (s, "height", &info.height);
|
||||
gst_structure_get_fraction (s, "framerate", &info.fps_n, &info.fps_d);
|
||||
if (!vaggpad_klass->set_info (pad, vagg, &pad->info, &vagg->info)) {
|
||||
GST_OBJECT_UNLOCK (vagg);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gst_videoaggregator_src_setcaps (vagg, caps)) {
|
||||
|
@ -1414,10 +1382,7 @@ gst_videoaggregator_check_reconfigure (GstVideoAggregator * vagg,
|
|||
|| gst_pad_check_reconfigure (GST_AGGREGATOR_SRC_PAD (vagg))) {
|
||||
gboolean ret;
|
||||
|
||||
ret = gst_videoaggregator_update_converters (vagg);
|
||||
if (ret)
|
||||
ret = gst_videoaggregator_update_src_caps (vagg);
|
||||
|
||||
ret = gst_videoaggregator_update_src_caps (vagg);
|
||||
if (!ret) {
|
||||
if (timeout && gst_pad_needs_reconfigure (GST_AGGREGATOR_SRC_PAD (vagg))) {
|
||||
guint64 frame_duration;
|
||||
|
@ -2099,6 +2064,8 @@ gst_videoaggregator_class_init (GstVideoAggregatorClass * klass)
|
|||
|
||||
klass->find_best_format = gst_videoaggreagator_find_best_format;
|
||||
klass->get_output_buffer = gst_videoaggregator_get_output_buffer;
|
||||
klass->update_caps = gst_videoaggregator_default_update_caps;
|
||||
klass->fixate_caps = gst_videoaggregator_default_fixate_caps;
|
||||
|
||||
/* Register the pad class */
|
||||
g_type_class_ref (GST_TYPE_VIDEO_AGGREGATOR_PAD);
|
||||
|
|
|
@ -73,6 +73,9 @@ struct _GstVideoAggregator
|
|||
* @update_caps: Optional.
|
||||
* Lets subclasses update the #GstCaps representing
|
||||
* the src pad caps before usage. Return %NULL to indicate failure.
|
||||
* @fixate_caps: Fixate and return the src pad caps provided. The function takes
|
||||
* ownership of @caps and returns a fixated version of
|
||||
* @caps. @caps is not guaranteed to be writable.
|
||||
* @aggregate_frames: Lets subclasses aggregate frames that are ready. Subclasses
|
||||
* should iterate the GstElement.sinkpads and use the already
|
||||
* mapped #GstVideoFrame from GstVideoAggregatorPad.aggregated_frame
|
||||
|
@ -86,9 +89,6 @@ struct _GstVideoAggregator
|
|||
* Notifies subclasses what caps format has been negotiated
|
||||
* @find_best_format: Optional.
|
||||
* Lets subclasses decide of the best common format to use.
|
||||
* @preserve_update_caps_result: Sub-classes should set this to true if the return result
|
||||
* of the update_caps() method should not be further modified
|
||||
* by GstVideoAggregator by removing fields.
|
||||
**/
|
||||
struct _GstVideoAggregatorClass
|
||||
{
|
||||
|
@ -97,6 +97,9 @@ struct _GstVideoAggregatorClass
|
|||
|
||||
/*< public >*/
|
||||
GstCaps * (*update_caps) (GstVideoAggregator * videoaggregator,
|
||||
GstCaps * caps,
|
||||
GstCaps * filter_caps);
|
||||
GstCaps * (*fixate_caps) (GstVideoAggregator * videoaggregator,
|
||||
GstCaps * caps);
|
||||
GstFlowReturn (*aggregate_frames) (GstVideoAggregator * videoaggregator,
|
||||
GstBuffer * outbuffer);
|
||||
|
@ -109,8 +112,6 @@ struct _GstVideoAggregatorClass
|
|||
GstVideoInfo * best_info,
|
||||
gboolean * at_least_one_alpha);
|
||||
|
||||
gboolean preserve_update_caps_result;
|
||||
|
||||
GstCaps *sink_non_alpha_caps;
|
||||
|
||||
/* < private > */
|
||||
|
|
|
@ -216,9 +216,9 @@ gst_compositor_pad_set_property (GObject * object, guint prop_id,
|
|||
|
||||
static void
|
||||
_mixer_pad_get_output_size (GstCompositor * comp,
|
||||
GstCompositorPad * comp_pad, gint * width, gint * height)
|
||||
GstCompositorPad * comp_pad, gint out_par_n, gint out_par_d, gint * width,
|
||||
gint * height)
|
||||
{
|
||||
GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (comp);
|
||||
GstVideoAggregatorPad *vagg_pad = GST_VIDEO_AGGREGATOR_PAD (comp_pad);
|
||||
gint pad_width, pad_height;
|
||||
guint dar_n, dar_d;
|
||||
|
@ -241,13 +241,10 @@ _mixer_pad_get_output_size (GstCompositor * comp,
|
|||
|
||||
gst_video_calculate_display_ratio (&dar_n, &dar_d, pad_width, pad_height,
|
||||
GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
|
||||
GST_VIDEO_INFO_PAR_D (&vagg_pad->info),
|
||||
GST_VIDEO_INFO_PAR_N (&vagg->info), GST_VIDEO_INFO_PAR_D (&vagg->info)
|
||||
);
|
||||
GST_VIDEO_INFO_PAR_D (&vagg_pad->info), out_par_n, out_par_d);
|
||||
GST_LOG_OBJECT (comp_pad, "scaling %ux%u by %u/%u (%u/%u / %u/%u)", pad_width,
|
||||
pad_height, dar_n, dar_d, GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
|
||||
GST_VIDEO_INFO_PAR_D (&vagg_pad->info),
|
||||
GST_VIDEO_INFO_PAR_N (&vagg->info), GST_VIDEO_INFO_PAR_D (&vagg->info));
|
||||
GST_VIDEO_INFO_PAR_D (&vagg_pad->info), out_par_n, out_par_d);
|
||||
|
||||
if (pad_height % dar_n == 0) {
|
||||
pad_width = gst_util_uint64_scale_int (pad_height, dar_n, dar_d);
|
||||
|
@ -292,7 +289,8 @@ gst_compositor_pad_set_info (GstVideoAggregatorPad * pad,
|
|||
gst_video_colorimetry_to_string (&(wanted_info->colorimetry));
|
||||
best_chroma = gst_video_chroma_to_string (wanted_info->chroma_site);
|
||||
|
||||
_mixer_pad_get_output_size (comp, cpad, &width, &height);
|
||||
_mixer_pad_get_output_size (comp, cpad, GST_VIDEO_INFO_PAR_N (&vagg->info),
|
||||
GST_VIDEO_INFO_PAR_D (&vagg->info), &width, &height);
|
||||
|
||||
if (GST_VIDEO_INFO_FORMAT (wanted_info) !=
|
||||
GST_VIDEO_INFO_FORMAT (current_info)
|
||||
|
@ -310,8 +308,8 @@ gst_compositor_pad_set_info (GstVideoAggregatorPad * pad,
|
|||
width, height);
|
||||
tmp_info.chroma_site = wanted_info->chroma_site;
|
||||
tmp_info.colorimetry = wanted_info->colorimetry;
|
||||
tmp_info.par_n = vagg->info.par_n;
|
||||
tmp_info.par_d = vagg->info.par_d;
|
||||
tmp_info.par_n = wanted_info->par_n;
|
||||
tmp_info.par_d = wanted_info->par_d;
|
||||
tmp_info.fps_n = current_info->fps_n;
|
||||
tmp_info.fps_d = current_info->fps_d;
|
||||
tmp_info.flags = current_info->flags;
|
||||
|
@ -403,7 +401,8 @@ gst_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
|
|||
* width/height. See ->set_info()
|
||||
* */
|
||||
|
||||
_mixer_pad_get_output_size (comp, cpad, &width, &height);
|
||||
_mixer_pad_get_output_size (comp, cpad, GST_VIDEO_INFO_PAR_N (&vagg->info),
|
||||
GST_VIDEO_INFO_PAR_D (&vagg->info), &width, &height);
|
||||
|
||||
/* The only thing that can change here is the width
|
||||
* and height, otherwise set_info would've been called */
|
||||
|
@ -498,7 +497,8 @@ gst_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
|
|||
GstCompositorPad *cpad2 = GST_COMPOSITOR_PAD (pad2);
|
||||
gint pad2_width, pad2_height;
|
||||
|
||||
_mixer_pad_get_output_size (comp, cpad2, &pad2_width, &pad2_height);
|
||||
_mixer_pad_get_output_size (comp, cpad2, GST_VIDEO_INFO_PAR_N (&vagg->info),
|
||||
GST_VIDEO_INFO_PAR_D (&vagg->info), &pad2_width, &pad2_height);
|
||||
|
||||
/* We don't need to clamp the coords of the second rectangle */
|
||||
frame2_rect.x = cpad2->xpos;
|
||||
|
@ -883,17 +883,26 @@ set_functions (GstCompositor * self, GstVideoInfo * info)
|
|||
}
|
||||
|
||||
static GstCaps *
|
||||
_update_caps (GstVideoAggregator * vagg, GstCaps * caps)
|
||||
_fixate_caps (GstVideoAggregator * vagg, GstCaps * caps)
|
||||
{
|
||||
GList *l;
|
||||
gint best_width = -1, best_height = -1;
|
||||
GstVideoInfo info;
|
||||
gint best_fps_n = -1, best_fps_d = -1;
|
||||
gint par_n, par_d;
|
||||
gdouble best_fps = 0.;
|
||||
GstCaps *ret = NULL;
|
||||
GstStructure *s;
|
||||
|
||||
gst_video_info_from_caps (&info, caps);
|
||||
ret = gst_caps_make_writable (caps);
|
||||
|
||||
/* FIXME: this doesn't work for non 1/1 output par's as we don't have that
|
||||
* information available at this time */
|
||||
/* we need this to calculate how large to make the output frame */
|
||||
s = gst_caps_get_structure (ret, 0);
|
||||
if (gst_structure_has_field (s, "pixel-aspect-ratio")) {
|
||||
gst_structure_fixate_field_nearest_fraction (s, "pixel-aspect-ratio", 1, 1);
|
||||
gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
|
||||
} else {
|
||||
par_n = par_d = 1;
|
||||
}
|
||||
|
||||
GST_OBJECT_LOCK (vagg);
|
||||
for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
|
||||
|
@ -901,9 +910,13 @@ _update_caps (GstVideoAggregator * vagg, GstCaps * caps)
|
|||
GstCompositorPad *compositor_pad = GST_COMPOSITOR_PAD (vaggpad);
|
||||
gint this_width, this_height;
|
||||
gint width, height;
|
||||
gint fps_n, fps_d;
|
||||
gdouble cur_fps;
|
||||
|
||||
_mixer_pad_get_output_size (GST_COMPOSITOR (vagg), compositor_pad, &width,
|
||||
&height);
|
||||
fps_n = GST_VIDEO_INFO_FPS_N (&vaggpad->info);
|
||||
fps_d = GST_VIDEO_INFO_FPS_D (&vaggpad->info);
|
||||
_mixer_pad_get_output_size (GST_COMPOSITOR (vagg), compositor_pad, par_n,
|
||||
par_d, &width, &height);
|
||||
|
||||
if (width == 0 || height == 0)
|
||||
continue;
|
||||
|
@ -915,17 +928,40 @@ _update_caps (GstVideoAggregator * vagg, GstCaps * caps)
|
|||
best_width = this_width;
|
||||
if (best_height < this_height)
|
||||
best_height = this_height;
|
||||
|
||||
if (fps_d == 0)
|
||||
cur_fps = 0.0;
|
||||
else
|
||||
gst_util_fraction_to_double (fps_n, fps_d, &cur_fps);
|
||||
|
||||
if (best_fps < cur_fps) {
|
||||
best_fps = cur_fps;
|
||||
best_fps_n = fps_n;
|
||||
best_fps_d = fps_d;
|
||||
}
|
||||
}
|
||||
GST_OBJECT_UNLOCK (vagg);
|
||||
|
||||
if (best_width > 0 && best_height > 0) {
|
||||
info.width = best_width;
|
||||
info.height = best_height;
|
||||
if (set_functions (GST_COMPOSITOR (vagg), &info))
|
||||
ret = gst_video_info_to_caps (&info);
|
||||
if (best_fps_n <= 0 || best_fps_d <= 0 || best_fps == 0.0) {
|
||||
best_fps_n = 25;
|
||||
best_fps_d = 1;
|
||||
best_fps = 25.0;
|
||||
}
|
||||
|
||||
gst_caps_set_simple (ret, "pixel-aspect-ratio", GST_TYPE_FRACTION_RANGE,
|
||||
1, G_MAXINT, G_MAXINT, 1, NULL);
|
||||
gst_structure_fixate_field_nearest_int (s, "width", best_width);
|
||||
gst_structure_fixate_field_nearest_int (s, "height", best_height);
|
||||
gst_structure_fixate_field_nearest_fraction (s, "framerate", best_fps_n,
|
||||
best_fps_d);
|
||||
ret = gst_caps_fixate (ret);
|
||||
|
||||
if (best_width > 0 && best_height > 0) {
|
||||
GstVideoInfo v_info;
|
||||
|
||||
gst_video_info_from_caps (&v_info, ret);
|
||||
if (!set_functions (GST_COMPOSITOR (vagg), &v_info)) {
|
||||
GST_ERROR_OBJECT (vagg, "Failed to setup vfuncs");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1059,7 +1095,7 @@ gst_compositor_class_init (GstCompositorClass * klass)
|
|||
|
||||
agg_class->sinkpads_type = GST_TYPE_COMPOSITOR_PAD;
|
||||
agg_class->sink_query = _sink_query;
|
||||
videoaggregator_class->update_caps = _update_caps;
|
||||
videoaggregator_class->fixate_caps = _fixate_caps;
|
||||
videoaggregator_class->aggregate_frames = gst_compositor_aggregate_frames;
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_BACKGROUND,
|
||||
|
|
Loading…
Reference in a new issue