videoaggregator: Move aggregated_frame and the pad buffer into the private struct

The aggregated_frame is now called prepared_frame and passed to the
prepare_frame and cleanup_frame virtual methods directly. For the
currently queued buffer there is a method on the video aggregator pad
now.
This commit is contained in:
Sebastian Dröge 2018-05-05 15:49:17 +02:00
parent 7f7324b3e6
commit 83192bce84
7 changed files with 209 additions and 143 deletions

View file

@ -39,9 +39,10 @@ static void gst_gl_mixer_pad_get_property (GObject * object, guint prop_id,
static void gst_gl_mixer_pad_set_property (GObject * object, guint prop_id, static void gst_gl_mixer_pad_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec); const GValue * value, GParamSpec * pspec);
static gboolean gst_gl_mixer_pad_prepare_frame (GstVideoAggregatorPad * vpad, static gboolean gst_gl_mixer_pad_prepare_frame (GstVideoAggregatorPad * vpad,
GstVideoAggregator * vagg); GstVideoAggregator * vagg, GstBuffer * buffer,
GstVideoFrame * prepared_frame);
static void gst_gl_mixer_pad_clean_frame (GstVideoAggregatorPad * vpad, static void gst_gl_mixer_pad_clean_frame (GstVideoAggregatorPad * vpad,
GstVideoAggregator * vagg); GstVideoAggregator * vagg, GstVideoFrame * prepared_frame);
enum enum
{ {
@ -101,54 +102,45 @@ gst_gl_mixer_pad_set_property (GObject * object, guint prop_id,
static gboolean static gboolean
gst_gl_mixer_pad_prepare_frame (GstVideoAggregatorPad * vpad, gst_gl_mixer_pad_prepare_frame (GstVideoAggregatorPad * vpad,
GstVideoAggregator * vagg) GstVideoAggregator * vagg, GstBuffer * buffer,
GstVideoFrame * prepared_frame)
{ {
GstGLMixerPad *pad = GST_GL_MIXER_PAD (vpad); GstGLMixerPad *pad = GST_GL_MIXER_PAD (vpad);
GstGLMixer *mix = GST_GL_MIXER (vagg); GstGLMixer *mix = GST_GL_MIXER (vagg);
GstVideoInfo gl_info;
GstGLSyncMeta *sync_meta;
pad->current_texture = 0; pad->current_texture = 0;
vpad->aggregated_frame = NULL;
if (vpad->buffer != NULL) { gst_video_info_set_format (&gl_info,
GstVideoInfo gl_info; GST_VIDEO_FORMAT_RGBA,
GstVideoFrame aggregated_frame; GST_VIDEO_INFO_WIDTH (&vpad->info), GST_VIDEO_INFO_HEIGHT (&vpad->info));
GstGLSyncMeta *sync_meta;
gst_video_info_set_format (&gl_info, sync_meta = gst_buffer_get_gl_sync_meta (buffer);
GST_VIDEO_FORMAT_RGBA, if (sync_meta)
GST_VIDEO_INFO_WIDTH (&vpad->info), gst_gl_sync_meta_wait (sync_meta, GST_GL_BASE_MIXER (mix)->context);
GST_VIDEO_INFO_HEIGHT (&vpad->info));
sync_meta = gst_buffer_get_gl_sync_meta (vpad->buffer); if (!gst_video_frame_map (prepared_frame, &gl_info, buffer,
if (sync_meta) GST_MAP_READ | GST_MAP_GL)) {
gst_gl_sync_meta_wait (sync_meta, GST_GL_BASE_MIXER (mix)->context); GST_ERROR_OBJECT (pad, "Failed to map input frame");
return FALSE;
if (!gst_video_frame_map (&aggregated_frame, &gl_info, vpad->buffer,
GST_MAP_READ | GST_MAP_GL)) {
GST_ERROR_OBJECT (pad, "Failed to map input frame");
return FALSE;
}
pad->current_texture = *(guint *) aggregated_frame.data[0];
vpad->aggregated_frame = g_slice_new0 (GstVideoFrame);
*vpad->aggregated_frame = aggregated_frame;
} }
pad->current_texture = *(guint *) prepared_frame->data[0];
return TRUE; return TRUE;
} }
static void static void
gst_gl_mixer_pad_clean_frame (GstVideoAggregatorPad * vpad, gst_gl_mixer_pad_clean_frame (GstVideoAggregatorPad * vpad,
GstVideoAggregator * vagg) GstVideoAggregator * vagg, GstVideoFrame * prepared_frame)
{ {
GstGLMixerPad *pad = GST_GL_MIXER_PAD (vpad); GstGLMixerPad *pad = GST_GL_MIXER_PAD (vpad);
pad->current_texture = 0; pad->current_texture = 0;
if (vpad->aggregated_frame) { if (prepared_frame->buffer) {
gst_video_frame_unmap (vpad->aggregated_frame); gst_video_frame_unmap (prepared_frame);
g_slice_free (GstVideoFrame, vpad->aggregated_frame); memset (prepared_frame, 0, sizeof (GstVideoFrame));
vpad->aggregated_frame = NULL;
} }
} }

View file

@ -88,7 +88,7 @@ G_DEFINE_TYPE_WITH_CODE (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);
static gboolean _negotiated_caps (GstAggregator * aggregator, GstCaps * caps); static gboolean _negotiated_caps (GstAggregator * aggregator, GstCaps * caps);
gboolean gst_gl_stereo_mix_make_output (GstGLStereoMix * mix); static gboolean gst_gl_stereo_mix_make_output (GstGLStereoMix * mix);
static gboolean gst_gl_stereo_mix_process_frames (GstGLStereoMix * mixer); static gboolean gst_gl_stereo_mix_process_frames (GstGLStereoMix * mixer);
#define DEFAULT_DOWNMIX GST_GL_STEREO_DOWNMIX_ANAGLYPH_GREEN_MAGENTA_DUBOIS #define DEFAULT_DOWNMIX GST_GL_STEREO_DOWNMIX_ANAGLYPH_GREEN_MAGENTA_DUBOIS
@ -301,7 +301,7 @@ gst_gl_stereo_mix_get_output_buffer (GstVideoAggregator * videoaggregator,
return ret; return ret;
} }
gboolean static gboolean
gst_gl_stereo_mix_make_output (GstGLStereoMix * mix) gst_gl_stereo_mix_make_output (GstGLStereoMix * mix)
{ {
GList *walk; GList *walk;
@ -316,11 +316,12 @@ gst_gl_stereo_mix_make_output (GstGLStereoMix * mix)
while (walk) { while (walk) {
GstVideoAggregatorPad *vaggpad = walk->data; GstVideoAggregatorPad *vaggpad = walk->data;
GstGLStereoMixPad *pad = walk->data; GstGLStereoMixPad *pad = walk->data;
GstBuffer *buffer = gst_video_aggregator_pad_get_current_buffer (vaggpad);
GST_LOG_OBJECT (mix, "Checking pad %" GST_PTR_FORMAT, vaggpad); GST_LOG_OBJECT (mix, "Checking pad %" GST_PTR_FORMAT, vaggpad);
if (vaggpad->buffer != NULL) { if (buffer != NULL) {
pad->current_buffer = vaggpad->buffer; pad->current_buffer = buffer;
GST_DEBUG_OBJECT (pad, "Got buffer %" GST_PTR_FORMAT, GST_DEBUG_OBJECT (pad, "Got buffer %" GST_PTR_FORMAT,
pad->current_buffer); pad->current_buffer);

View file

@ -1583,9 +1583,10 @@ gst_gl_video_mixer_callback (gpointer stuff)
{ {
GstVideoAffineTransformationMeta *af_meta; GstVideoAffineTransformationMeta *af_meta;
gfloat matrix[16]; gfloat matrix[16];
GstBuffer *buffer =
gst_video_aggregator_pad_get_current_buffer (vagg_pad);
af_meta = af_meta = gst_buffer_get_video_affine_transformation_meta (buffer);
gst_buffer_get_video_affine_transformation_meta (vagg_pad->buffer);
gst_gl_get_affine_transformation_meta_as_ndc_ext (af_meta, matrix); gst_gl_get_affine_transformation_meta_as_ndc_ext (af_meta, matrix);
gst_gl_shader_set_uniform_matrix_4fv (video_mixer->shader, gst_gl_shader_set_uniform_matrix_4fv (video_mixer->shader,
"u_transformation", 1, FALSE, matrix); "u_transformation", 1, FALSE, matrix);

View file

@ -264,14 +264,16 @@ gst_iqa_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf)
GST_OBJECT_LOCK (vagg); GST_OBJECT_LOCK (vagg);
for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) { for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
GstVideoAggregatorPad *pad = l->data; GstVideoAggregatorPad *pad = l->data;
GstVideoFrame *prepared_frame =
gst_video_aggregator_pad_get_prepared_frame (pad);
if (pad->aggregated_frame != NULL) { if (prepared_frame != NULL) {
if (!ref_frame) { if (!ref_frame) {
ref_frame = pad->aggregated_frame; ref_frame = prepared_frame;
} else { } else {
gboolean res; gboolean res;
gchar *padname = gst_pad_get_name (pad); gchar *padname = gst_pad_get_name (pad);
GstVideoFrame *cmp_frame = pad->aggregated_frame; GstVideoFrame *cmp_frame = prepared_frame;
res = compare_frames (self, ref_frame, cmp_frame, outbuf, msg_structure, res = compare_frames (self, ref_frame, cmp_frame, outbuf, msg_structure,
padname); padname);

View file

@ -65,6 +65,9 @@ enum
struct _GstVideoAggregatorPadPrivate struct _GstVideoAggregatorPadPrivate
{ {
GstBuffer *buffer;
GstVideoFrame prepared_frame;
/* properties */ /* properties */
guint zorder; guint zorder;
gboolean repeat_after_eos; gboolean repeat_after_eos;
@ -146,7 +149,7 @@ _flush_pad (GstAggregatorPad * aggpad, GstAggregator * aggregator)
GstVideoAggregatorPad *pad = GST_VIDEO_AGGREGATOR_PAD (aggpad); GstVideoAggregatorPad *pad = GST_VIDEO_AGGREGATOR_PAD (aggpad);
gst_video_aggregator_reset_qos (vagg); gst_video_aggregator_reset_qos (vagg);
gst_buffer_replace (&pad->buffer, NULL); gst_buffer_replace (&pad->priv->buffer, NULL);
pad->priv->start_time = -1; pad->priv->start_time = -1;
pad->priv->end_time = -1; pad->priv->end_time = -1;
@ -259,28 +262,26 @@ gst_video_aggregator_pad_finalize (GObject * o)
static gboolean static gboolean
gst_video_aggregator_pad_prepare_frame (GstVideoAggregatorPad * pad, gst_video_aggregator_pad_prepare_frame (GstVideoAggregatorPad * pad,
GstVideoAggregator * vagg) GstVideoAggregator * vagg, GstBuffer * buffer,
GstVideoFrame * prepared_frame)
{ {
guint outsize; GstVideoFrame frame;
GstVideoFrame *converted_frame;
GstBuffer *converted_buf = NULL;
GstVideoFrame *frame;
static GstAllocationParams params = { 0, 15, 0, 0, };
if (!pad->buffer) if (!pad->priv->buffer)
return TRUE; return TRUE;
frame = g_slice_new0 (GstVideoFrame); if (!gst_video_frame_map (&frame, &pad->info, pad->priv->buffer,
GST_MAP_READ)) {
if (!gst_video_frame_map (frame, &pad->info, pad->buffer, GST_MAP_READ)) {
GST_WARNING_OBJECT (vagg, "Could not map input buffer"); GST_WARNING_OBJECT (vagg, "Could not map input buffer");
return FALSE; return FALSE;
} }
if (pad->priv->convert) { if (pad->priv->convert) {
GstVideoFrame converted_frame;
GstBuffer *converted_buf = NULL;
static GstAllocationParams params = { 0, 15, 0, 0, };
gint converted_size; gint converted_size;
guint outsize;
converted_frame = g_slice_new0 (GstVideoFrame);
/* We wait until here to set the conversion infos, in case vagg->info changed */ /* We wait until here to set the conversion infos, in case vagg->info changed */
converted_size = pad->priv->conversion_info.size; converted_size = pad->priv->conversion_info.size;
@ -288,37 +289,32 @@ gst_video_aggregator_pad_prepare_frame (GstVideoAggregatorPad * pad,
converted_size = converted_size > outsize ? converted_size : outsize; converted_size = converted_size > outsize ? converted_size : outsize;
converted_buf = gst_buffer_new_allocate (NULL, converted_size, &params); converted_buf = gst_buffer_new_allocate (NULL, converted_size, &params);
if (!gst_video_frame_map (converted_frame, &(pad->priv->conversion_info), if (!gst_video_frame_map (&converted_frame, &(pad->priv->conversion_info),
converted_buf, GST_MAP_READWRITE)) { converted_buf, GST_MAP_READWRITE)) {
GST_WARNING_OBJECT (vagg, "Could not map converted frame"); GST_WARNING_OBJECT (vagg, "Could not map converted frame");
g_slice_free (GstVideoFrame, converted_frame); gst_video_frame_unmap (&frame);
gst_video_frame_unmap (frame);
g_slice_free (GstVideoFrame, frame);
return FALSE; return FALSE;
} }
gst_video_converter_frame (pad->priv->convert, frame, converted_frame); gst_video_converter_frame (pad->priv->convert, &frame, &converted_frame);
pad->priv->converted_buffer = converted_buf; pad->priv->converted_buffer = converted_buf;
gst_video_frame_unmap (frame); gst_video_frame_unmap (&frame);
g_slice_free (GstVideoFrame, frame); *prepared_frame = converted_frame;
} else { } else {
converted_frame = frame; *prepared_frame = frame;
} }
pad->aggregated_frame = converted_frame;
return TRUE; return TRUE;
} }
static void static void
gst_video_aggregator_pad_clean_frame (GstVideoAggregatorPad * pad, gst_video_aggregator_pad_clean_frame (GstVideoAggregatorPad * pad,
GstVideoAggregator * vagg) GstVideoAggregator * vagg, GstVideoFrame * prepared_frame)
{ {
if (pad->aggregated_frame) { if (prepared_frame->buffer) {
gst_video_frame_unmap (pad->aggregated_frame); gst_video_frame_unmap (prepared_frame);
g_slice_free (GstVideoFrame, pad->aggregated_frame); memset (prepared_frame, 0, sizeof (GstVideoFrame));
pad->aggregated_frame = NULL;
} }
if (pad->priv->converted_buffer) { if (pad->priv->converted_buffer) {
@ -368,11 +364,77 @@ gst_video_aggregator_pad_init (GstVideoAggregatorPad * vaggpad)
vaggpad->priv->zorder = DEFAULT_PAD_ZORDER; vaggpad->priv->zorder = DEFAULT_PAD_ZORDER;
vaggpad->priv->repeat_after_eos = DEFAULT_PAD_REPEAT_AFTER_EOS; vaggpad->priv->repeat_after_eos = DEFAULT_PAD_REPEAT_AFTER_EOS;
vaggpad->priv->converted_buffer = NULL; vaggpad->priv->converted_buffer = NULL;
vaggpad->aggregated_frame = NULL; memset (&vaggpad->priv->prepared_frame, 0, sizeof (GstVideoFrame));
vaggpad->priv->convert = NULL; vaggpad->priv->convert = NULL;
} }
/**
* gst_video_aggregator_pad_has_current_buffer:
* @pad: a #GstVideoAggregatorPad
*
* Checks if the pad currently has a buffer queued that is going to be used
* for the current output frame.
*
* This must only be called from the aggregate_frames() virtual method,
* or from the prepare_frame() virtual method of the aggregator pads.
*
* Returns: %TRUE if the pad has currently a buffer queued
*/
gboolean
gst_video_aggregator_pad_has_current_buffer (GstVideoAggregatorPad * pad)
{
g_return_val_if_fail (GST_IS_VIDEO_AGGREGATOR_PAD (pad), FALSE);
return pad->priv->buffer != NULL;
}
/**
* gst_video_aggregator_pad_has_current_buffer:
* @pad: a #GstVideoAggregatorPad
*
* Returns the currently queued buffer that is going to be used
* for the current output frame.
*
* This must only be called from the aggregate_frames() virtual method,
* or from the prepare_frame() virtual method of the aggregator pads.
*
* The return value is only valid until aggregate_frames() or prepare_frames()
* returns.
*
* Returns: (transfer none): The currently queued buffer
*/
GstBuffer *
gst_video_aggregator_pad_get_current_buffer (GstVideoAggregatorPad * pad)
{
g_return_val_if_fail (GST_IS_VIDEO_AGGREGATOR_PAD (pad), NULL);
return pad->priv->buffer;
}
/**
* gst_video_aggregator_pad_get_prepared_frame:
* @pad: a #GstVideoAggregatorPad
*
* Returns the currently prepared video frame that has to be aggregated into
* the current output frame.
*
* This must only be called from the aggregate_frames() virtual method,
* or from the prepare_frame() virtual method of the aggregator pads.
*
* The return value is only valid until aggregate_frames() or prepare_frames()
* returns.
*
* Returns: (transfer none): The currently prepared video frame
*/
GstVideoFrame *
gst_video_aggregator_pad_get_prepared_frame (GstVideoAggregatorPad * pad)
{
g_return_val_if_fail (GST_IS_VIDEO_AGGREGATOR_PAD (pad), NULL);
return pad->priv->prepared_frame.buffer ? &pad->priv->prepared_frame : NULL;
}
/************************************** /**************************************
* GstVideoAggregator implementation * * GstVideoAggregator implementation *
**************************************/ **************************************/
@ -1017,7 +1079,7 @@ gst_video_aggregator_reset (GstVideoAggregator * vagg)
for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) { for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
GstVideoAggregatorPad *p = l->data; GstVideoAggregatorPad *p = l->data;
gst_buffer_replace (&p->buffer, NULL); gst_buffer_replace (&p->priv->buffer, NULL);
p->priv->start_time = -1; p->priv->start_time = -1;
p->priv->end_time = -1; p->priv->end_time = -1;
@ -1038,7 +1100,7 @@ gst_video_aggregator_fill_queues (GstVideoAggregator * vagg,
gboolean need_reconfigure = FALSE; gboolean need_reconfigure = FALSE;
GstSegment *agg_segment = &GST_AGGREGATOR_PAD (agg->srcpad)->segment; GstSegment *agg_segment = &GST_AGGREGATOR_PAD (agg->srcpad)->segment;
/* get a set of buffers into pad->buffer that are within output_start_running_time /* get a set of buffers into pad->priv->buffer that are within output_start_running_time
* and output_end_running_time taking into account finished and unresponsive pads */ * and output_end_running_time taking into account finished and unresponsive pads */
GST_OBJECT_LOCK (vagg); GST_OBJECT_LOCK (vagg);
@ -1078,7 +1140,7 @@ gst_video_aggregator_fill_queues (GstVideoAggregator * vagg,
gst_segment_to_running_time (&segment, GST_FORMAT_TIME, start_time); gst_segment_to_running_time (&segment, GST_FORMAT_TIME, start_time);
if (start_time >= output_end_running_time) { if (start_time >= output_end_running_time) {
if (pad->buffer) { if (pad->priv->buffer) {
GST_DEBUG_OBJECT (pad, "buffer duration is -1, start_time >= " GST_DEBUG_OBJECT (pad, "buffer duration is -1, start_time >= "
"output_end_running_time. Keeping previous buffer"); "output_end_running_time. Keeping previous buffer");
} else { } else {
@ -1090,7 +1152,7 @@ gst_video_aggregator_fill_queues (GstVideoAggregator * vagg,
} else if (start_time < output_start_running_time) { } else if (start_time < output_start_running_time) {
GST_DEBUG_OBJECT (pad, "buffer duration is -1, start_time < " GST_DEBUG_OBJECT (pad, "buffer duration is -1, start_time < "
"output_start_running_time. Discarding old buffer"); "output_start_running_time. Discarding old buffer");
gst_buffer_replace (&pad->buffer, buf); gst_buffer_replace (&pad->priv->buffer, buf);
if (pad->priv->pending_vinfo.finfo) { if (pad->priv->pending_vinfo.finfo) {
pad->info = pad->priv->pending_vinfo; pad->info = pad->priv->pending_vinfo;
need_reconfigure = TRUE; need_reconfigure = TRUE;
@ -1103,7 +1165,7 @@ gst_video_aggregator_fill_queues (GstVideoAggregator * vagg,
} }
gst_buffer_unref (buf); gst_buffer_unref (buf);
buf = gst_aggregator_pad_pop_buffer (bpad); buf = gst_aggregator_pad_pop_buffer (bpad);
gst_buffer_replace (&pad->buffer, buf); gst_buffer_replace (&pad->priv->buffer, buf);
if (pad->priv->pending_vinfo.finfo) { if (pad->priv->pending_vinfo.finfo) {
pad->info = pad->priv->pending_vinfo; pad->info = pad->priv->pending_vinfo;
need_reconfigure = TRUE; need_reconfigure = TRUE;
@ -1168,7 +1230,7 @@ gst_video_aggregator_fill_queues (GstVideoAggregator * vagg,
GST_DEBUG_OBJECT (pad, GST_DEBUG_OBJECT (pad,
"Taking new buffer with start time %" GST_TIME_FORMAT, "Taking new buffer with start time %" GST_TIME_FORMAT,
GST_TIME_ARGS (start_time)); GST_TIME_ARGS (start_time));
gst_buffer_replace (&pad->buffer, buf); gst_buffer_replace (&pad->priv->buffer, buf);
if (pad->priv->pending_vinfo.finfo) { if (pad->priv->pending_vinfo.finfo) {
pad->info = pad->priv->pending_vinfo; pad->info = pad->priv->pending_vinfo;
need_reconfigure = TRUE; need_reconfigure = TRUE;
@ -1186,7 +1248,7 @@ gst_video_aggregator_fill_queues (GstVideoAggregator * vagg,
gst_buffer_unref (buf); gst_buffer_unref (buf);
eos = FALSE; eos = FALSE;
} else { } else {
gst_buffer_replace (&pad->buffer, buf); gst_buffer_replace (&pad->priv->buffer, buf);
if (pad->priv->pending_vinfo.finfo) { if (pad->priv->pending_vinfo.finfo) {
pad->info = pad->priv->pending_vinfo; pad->info = pad->priv->pending_vinfo;
need_reconfigure = TRUE; need_reconfigure = TRUE;
@ -1218,13 +1280,13 @@ gst_video_aggregator_fill_queues (GstVideoAggregator * vagg,
GST_DEBUG ("I just need more data"); GST_DEBUG ("I just need more data");
need_more_data = TRUE; need_more_data = TRUE;
} else { } else {
gst_buffer_replace (&pad->buffer, NULL); gst_buffer_replace (&pad->priv->buffer, NULL);
} }
} else if (is_eos) { } else if (is_eos) {
eos = FALSE; eos = FALSE;
} }
} else if (is_eos) { } else if (is_eos) {
gst_buffer_replace (&pad->buffer, NULL); gst_buffer_replace (&pad->priv->buffer, NULL);
} }
} }
} }
@ -1249,10 +1311,10 @@ sync_pad_values (GstElement * vagg, GstPad * pad, gpointer user_data)
GstClockTime timestamp; GstClockTime timestamp;
gint64 stream_time; gint64 stream_time;
if (vpad->buffer == NULL) if (vpad->priv->buffer == NULL)
return TRUE; return TRUE;
timestamp = GST_BUFFER_TIMESTAMP (vpad->buffer); timestamp = GST_BUFFER_TIMESTAMP (vpad->priv->buffer);
GST_OBJECT_LOCK (bpad); GST_OBJECT_LOCK (bpad);
stream_time = gst_segment_to_stream_time (&bpad->segment, GST_FORMAT_TIME, stream_time = gst_segment_to_stream_time (&bpad->segment, GST_FORMAT_TIME,
timestamp); timestamp);
@ -1272,10 +1334,13 @@ prepare_frames (GstElement * agg, GstPad * pad, gpointer user_data)
GstVideoAggregatorPadClass *vaggpad_class = GstVideoAggregatorPadClass *vaggpad_class =
GST_VIDEO_AGGREGATOR_PAD_GET_CLASS (pad); GST_VIDEO_AGGREGATOR_PAD_GET_CLASS (pad);
if (vpad->buffer == NULL || !vaggpad_class->prepare_frame) memset (&vpad->priv->prepared_frame, 0, sizeof (GstVideoFrame));
if (vpad->priv->buffer == NULL || !vaggpad_class->prepare_frame)
return TRUE; return TRUE;
return vaggpad_class->prepare_frame (vpad, GST_VIDEO_AGGREGATOR_CAST (agg)); return vaggpad_class->prepare_frame (vpad, GST_VIDEO_AGGREGATOR_CAST (agg),
vpad->priv->buffer, &vpad->priv->prepared_frame);
} }
static gboolean static gboolean
@ -1287,7 +1352,9 @@ clean_pad (GstElement * agg, GstPad * pad, gpointer user_data)
GST_VIDEO_AGGREGATOR_PAD_GET_CLASS (pad); GST_VIDEO_AGGREGATOR_PAD_GET_CLASS (pad);
if (vaggpad_class->clean_frame) if (vaggpad_class->clean_frame)
vaggpad_class->clean_frame (vpad, vagg); vaggpad_class->clean_frame (vpad, vagg, &vpad->priv->prepared_frame);
memset (&vpad->priv->prepared_frame, 0, sizeof (GstVideoFrame));
return TRUE; return TRUE;
} }
@ -1749,11 +1816,11 @@ gst_video_aggregator_flush (GstAggregator * agg)
/* Convert to the output segment rate */ /* Convert to the output segment rate */
if (ABS (agg_segment->rate) != abs_rate) { if (ABS (agg_segment->rate) != abs_rate) {
if (ABS (agg_segment->rate) != 1.0 && p->buffer) { if (ABS (agg_segment->rate) != 1.0 && p->priv->buffer) {
p->priv->start_time /= ABS (agg_segment->rate); p->priv->start_time /= ABS (agg_segment->rate);
p->priv->end_time /= ABS (agg_segment->rate); p->priv->end_time /= ABS (agg_segment->rate);
} }
if (abs_rate != 1.0 && p->buffer) { if (abs_rate != 1.0 && p->priv->buffer) {
p->priv->start_time *= abs_rate; p->priv->start_time *= abs_rate;
p->priv->end_time *= abs_rate; p->priv->end_time *= abs_rate;
} }
@ -1879,7 +1946,7 @@ gst_video_aggregator_release_pad (GstElement * element, GstPad * pad)
if (last_pad) if (last_pad)
gst_video_aggregator_reset (vagg); gst_video_aggregator_reset (vagg);
gst_buffer_replace (&vaggpad->buffer, NULL); gst_buffer_replace (&vaggpad->priv->buffer, NULL);
GST_ELEMENT_CLASS (gst_video_aggregator_parent_class)->release_pad GST_ELEMENT_CLASS (gst_video_aggregator_parent_class)->release_pad
(GST_ELEMENT (vagg), pad); (GST_ELEMENT (vagg), pad);

View file

@ -71,9 +71,6 @@ struct _GstVideoAggregatorPad
/* read-only, with OBJECT_LOCK */ /* read-only, with OBJECT_LOCK */
GstVideoInfo info; GstVideoInfo info;
GstBuffer *buffer;
GstVideoFrame *aggregated_frame;
/* Subclasses can force an alpha channel in the (input thus output) /* Subclasses can force an alpha channel in the (input thus output)
* colorspace format */ * colorspace format */
gboolean needs_alpha; gboolean needs_alpha;
@ -102,10 +99,13 @@ struct _GstVideoAggregatorPadClass
GstVideoInfo * wanted_info); GstVideoInfo * wanted_info);
gboolean (*prepare_frame) (GstVideoAggregatorPad * pad, gboolean (*prepare_frame) (GstVideoAggregatorPad * pad,
GstVideoAggregator * videoaggregator); GstVideoAggregator * videoaggregator,
GstBuffer * buffer,
GstVideoFrame * prepared_frame);
void (*clean_frame) (GstVideoAggregatorPad * pad, void (*clean_frame) (GstVideoAggregatorPad * pad,
GstVideoAggregator * videoaggregator); GstVideoAggregator * videoaggregator,
GstVideoFrame * prepared_frame);
gpointer _gst_reserved[GST_PADDING_LARGE]; gpointer _gst_reserved[GST_PADDING_LARGE];
}; };
@ -113,6 +113,15 @@ struct _GstVideoAggregatorPadClass
GST_VIDEO_BAD_API GST_VIDEO_BAD_API
GType gst_video_aggregator_pad_get_type (void); GType gst_video_aggregator_pad_get_type (void);
GST_VIDEO_BAD_API
gboolean gst_video_aggregator_pad_has_current_buffer (GstVideoAggregatorPad *pad);
GST_VIDEO_BAD_API
GstBuffer * gst_video_aggregator_pad_get_current_buffer (GstVideoAggregatorPad *pad);
GST_VIDEO_BAD_API
GstVideoFrame * gst_video_aggregator_pad_get_prepared_frame (GstVideoAggregatorPad *pad);
#define GST_TYPE_VIDEO_AGGREGATOR (gst_video_aggregator_get_type()) #define GST_TYPE_VIDEO_AGGREGATOR (gst_video_aggregator_get_type())
#define GST_VIDEO_AGGREGATOR(obj) \ #define GST_VIDEO_AGGREGATOR(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_AGGREGATOR, GstVideoAggregator)) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_AGGREGATOR, GstVideoAggregator))

View file

@ -376,14 +376,13 @@ clamp_rectangle (gint x, gint y, gint w, gint h, gint outer_width,
static gboolean static gboolean
gst_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad, gst_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
GstVideoAggregator * vagg) GstVideoAggregator * vagg, GstBuffer * buffer,
GstVideoFrame * prepared_frame)
{ {
GstCompositor *comp = GST_COMPOSITOR (vagg); GstCompositor *comp = GST_COMPOSITOR (vagg);
GstCompositorPad *cpad = GST_COMPOSITOR_PAD (pad); GstCompositorPad *cpad = GST_COMPOSITOR_PAD (pad);
guint outsize; guint outsize;
GstVideoFrame *converted_frame; GstVideoFrame frame;
GstBuffer *converted_buf = NULL;
GstVideoFrame *frame;
static GstAllocationParams params = { 0, 15, 0, 0, }; static GstAllocationParams params = { 0, 15, 0, 0, };
gint width, height; gint width, height;
gboolean frame_obscured = FALSE; gboolean frame_obscured = FALSE;
@ -392,9 +391,6 @@ gst_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
* Due to the clamping, this is different from the frame width/height above. */ * Due to the clamping, this is different from the frame width/height above. */
GstVideoRectangle frame_rect; GstVideoRectangle frame_rect;
if (!pad->buffer)
return TRUE;
/* There's three types of width/height here: /* There's three types of width/height here:
* 1. GST_VIDEO_FRAME_WIDTH/HEIGHT: * 1. GST_VIDEO_FRAME_WIDTH/HEIGHT:
* The frame width/height (same as pad->info.height/width; * The frame width/height (same as pad->info.height/width;
@ -476,7 +472,6 @@ gst_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
if (cpad->alpha == 0.0) { if (cpad->alpha == 0.0) {
GST_DEBUG_OBJECT (vagg, "Pad has alpha 0.0, not converting frame"); GST_DEBUG_OBJECT (vagg, "Pad has alpha 0.0, not converting frame");
converted_frame = NULL;
goto done; goto done;
} }
@ -486,7 +481,6 @@ gst_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
if (frame_rect.w == 0 || frame_rect.h == 0) { if (frame_rect.w == 0 || frame_rect.h == 0) {
GST_DEBUG_OBJECT (vagg, "Resulting frame is zero-width or zero-height " GST_DEBUG_OBJECT (vagg, "Resulting frame is zero-width or zero-height "
"(w: %i, h: %i), skipping", frame_rect.w, frame_rect.h); "(w: %i, h: %i), skipping", frame_rect.w, frame_rect.h);
converted_frame = NULL;
goto done; goto done;
} }
@ -523,9 +517,9 @@ gst_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
/* Check if there's a buffer to be aggregated, ensure it can't have an alpha /* Check if there's a buffer to be aggregated, ensure it can't have an alpha
* channel, then check opacity and frame boundaries */ * channel, then check opacity and frame boundaries */
if (pad2->buffer && cpad2->alpha == 1.0 && if (gst_video_aggregator_pad_has_current_buffer (pad2)
!GST_VIDEO_INFO_HAS_ALPHA (&pad2->info) && && cpad2->alpha == 1.0 && !GST_VIDEO_INFO_HAS_ALPHA (&pad2->info)
is_rectangle_contained (frame_rect, frame2_rect)) { && is_rectangle_contained (frame_rect, frame2_rect)) {
frame_obscured = TRUE; frame_obscured = TRUE;
GST_DEBUG_OBJECT (pad, "%ix%i@(%i,%i) obscured by %s %ix%i@(%i,%i) " GST_DEBUG_OBJECT (pad, "%ix%i@(%i,%i) obscured by %s %ix%i@(%i,%i) "
"in output of size %ix%i; skipping frame", frame_rect.w, frame_rect.h, "in output of size %ix%i; skipping frame", frame_rect.w, frame_rect.h,
@ -538,22 +532,18 @@ gst_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
} }
GST_OBJECT_UNLOCK (vagg); GST_OBJECT_UNLOCK (vagg);
if (frame_obscured) { if (frame_obscured)
converted_frame = NULL;
goto done; goto done;
}
frame = g_slice_new0 (GstVideoFrame); if (!gst_video_frame_map (&frame, &pad->info, buffer, GST_MAP_READ)) {
if (!gst_video_frame_map (frame, &pad->info, pad->buffer, GST_MAP_READ)) {
GST_WARNING_OBJECT (vagg, "Could not map input buffer"); GST_WARNING_OBJECT (vagg, "Could not map input buffer");
return FALSE; return FALSE;
} }
if (cpad->convert) { if (cpad->convert) {
gint converted_size; gint converted_size;
GstVideoFrame converted_frame;
converted_frame = g_slice_new0 (GstVideoFrame); GstBuffer *converted_buf = NULL;
/* We wait until here to set the conversion infos, in case vagg->info changed */ /* We wait until here to set the conversion infos, in case vagg->info changed */
converted_size = GST_VIDEO_INFO_SIZE (&cpad->conversion_info); converted_size = GST_VIDEO_INFO_SIZE (&cpad->conversion_info);
@ -561,40 +551,36 @@ gst_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
converted_size = converted_size > outsize ? converted_size : outsize; converted_size = converted_size > outsize ? converted_size : outsize;
converted_buf = gst_buffer_new_allocate (NULL, converted_size, &params); converted_buf = gst_buffer_new_allocate (NULL, converted_size, &params);
if (!gst_video_frame_map (converted_frame, &(cpad->conversion_info), if (!gst_video_frame_map (&converted_frame, &(cpad->conversion_info),
converted_buf, GST_MAP_READWRITE)) { converted_buf, GST_MAP_READWRITE)) {
GST_WARNING_OBJECT (vagg, "Could not map converted frame"); GST_WARNING_OBJECT (vagg, "Could not map converted frame");
g_slice_free (GstVideoFrame, converted_frame); gst_video_frame_unmap (&frame);
gst_video_frame_unmap (frame);
g_slice_free (GstVideoFrame, frame);
return FALSE; return FALSE;
} }
gst_video_converter_frame (cpad->convert, frame, converted_frame); gst_video_converter_frame (cpad->convert, &frame, &converted_frame);
cpad->converted_buffer = converted_buf; cpad->converted_buffer = converted_buf;
gst_video_frame_unmap (frame); gst_video_frame_unmap (&frame);
g_slice_free (GstVideoFrame, frame); *prepared_frame = converted_frame;
} else { } else {
converted_frame = frame; *prepared_frame = frame;
} }
done: done:
pad->aggregated_frame = converted_frame;
return TRUE; return TRUE;
} }
static void static void
gst_compositor_pad_clean_frame (GstVideoAggregatorPad * pad, gst_compositor_pad_clean_frame (GstVideoAggregatorPad * pad,
GstVideoAggregator * vagg) GstVideoAggregator * vagg, GstVideoFrame * prepared_frame)
{ {
GstCompositorPad *cpad = GST_COMPOSITOR_PAD (pad); GstCompositorPad *cpad = GST_COMPOSITOR_PAD (pad);
if (pad->aggregated_frame) { if (prepared_frame->buffer) {
gst_video_frame_unmap (pad->aggregated_frame); gst_video_frame_unmap (prepared_frame);
g_slice_free (GstVideoFrame, pad->aggregated_frame); memset (prepared_frame, 0, sizeof (GstVideoFrame));
pad->aggregated_frame = NULL;
} }
if (cpad->converted_buffer) { if (cpad->converted_buffer) {
@ -1065,44 +1051,50 @@ gst_compositor_crossfade_frames (GstCompositor * self, GstVideoFrame * outframe)
for (l = GST_ELEMENT (self)->sinkpads; l; l = l->next) { for (l = GST_ELEMENT (self)->sinkpads; l; l = l->next) {
GstVideoAggregatorPad *pad = l->data; GstVideoAggregatorPad *pad = l->data;
GstCompositorPad *compo_pad = GST_COMPOSITOR_PAD (pad); GstCompositorPad *compo_pad = GST_COMPOSITOR_PAD (pad);
GstVideoFrame *prepared_frame =
gst_video_aggregator_pad_get_prepared_frame (pad);
if (compo_pad->crossfade >= 0.0f && pad->aggregated_frame) { if (compo_pad->crossfade >= 0.0f && prepared_frame) {
gfloat alpha = compo_pad->crossfade * compo_pad->alpha; gfloat alpha = compo_pad->crossfade * compo_pad->alpha;
GstVideoAggregatorPad *npad = l->next ? l->next->data : NULL; GstVideoAggregatorPad *npad = l->next ? l->next->data : NULL;
GstVideoFrame *nframe; GstVideoFrame *next_prepared_frame;
GstVideoFrame nframe;
next_prepared_frame =
npad ? gst_video_aggregator_pad_get_prepared_frame (npad) : NULL;
if (!all_crossfading) { if (!all_crossfading) {
nframe = g_slice_new0 (GstVideoFrame); gst_compositor_fill_transparent (self, outframe, &nframe);
gst_compositor_fill_transparent (self, outframe, nframe);
} else { } else {
nframe = outframe; nframe = *outframe;
} }
self->overlay (pad->aggregated_frame, self->overlay (prepared_frame,
compo_pad->crossfaded ? 0 : compo_pad->xpos, compo_pad->crossfaded ? 0 : compo_pad->xpos,
compo_pad->crossfaded ? 0 : compo_pad->ypos, compo_pad->crossfaded ? 0 : compo_pad->ypos,
alpha, nframe, COMPOSITOR_BLEND_MODE_ADDITIVE); alpha, &nframe, COMPOSITOR_BLEND_MODE_ADDITIVE);
if (npad && npad->aggregated_frame) { if (npad && next_prepared_frame) {
GstCompositorPad *next_compo_pad = GST_COMPOSITOR_PAD (npad); GstCompositorPad *next_compo_pad = GST_COMPOSITOR_PAD (npad);
alpha = (1.0 - compo_pad->crossfade) * next_compo_pad->alpha; alpha = (1.0 - compo_pad->crossfade) * next_compo_pad->alpha;
self->overlay (npad->aggregated_frame, next_compo_pad->xpos, self->overlay (next_prepared_frame, next_compo_pad->xpos,
next_compo_pad->ypos, alpha, nframe, next_compo_pad->ypos, alpha, &nframe,
COMPOSITOR_BLEND_MODE_ADDITIVE); COMPOSITOR_BLEND_MODE_ADDITIVE);
/* Replace frame with current frame */ /* Replace frame with current frame */
gst_compositor_pad_clean_frame (npad, vagg); gst_compositor_pad_clean_frame (npad, vagg, next_prepared_frame);
npad->aggregated_frame = !all_crossfading ? nframe : NULL; if (!all_crossfading)
*next_prepared_frame = nframe;
next_compo_pad->crossfaded = TRUE; next_compo_pad->crossfaded = TRUE;
/* Frame is now consumed, clean it up */ /* Frame is now consumed, clean it up */
gst_compositor_pad_clean_frame (pad, vagg); gst_compositor_pad_clean_frame (pad, vagg, prepared_frame);
pad->aggregated_frame = NULL;
} else { } else {
GST_LOG_OBJECT (self, "Simply fading out as no following pad found"); GST_LOG_OBJECT (self, "Simply fading out as no following pad found");
gst_compositor_pad_clean_frame (pad, vagg); gst_compositor_pad_clean_frame (pad, vagg, prepared_frame);
pad->aggregated_frame = !all_crossfading ? nframe : NULL; if (!all_crossfading)
*prepared_frame = nframe;
compo_pad->crossfaded = TRUE; compo_pad->crossfaded = TRUE;
} }
} }
@ -1156,9 +1148,11 @@ gst_compositor_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf)
for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) { for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
GstVideoAggregatorPad *pad = l->data; GstVideoAggregatorPad *pad = l->data;
GstCompositorPad *compo_pad = GST_COMPOSITOR_PAD (pad); GstCompositorPad *compo_pad = GST_COMPOSITOR_PAD (pad);
GstVideoFrame *prepared_frame =
gst_video_aggregator_pad_get_prepared_frame (pad);
if (pad->aggregated_frame != NULL) { if (prepared_frame != NULL) {
composite (pad->aggregated_frame, composite (prepared_frame,
compo_pad->crossfaded ? 0 : compo_pad->xpos, compo_pad->crossfaded ? 0 : compo_pad->xpos,
compo_pad->crossfaded ? 0 : compo_pad->ypos, compo_pad->alpha, compo_pad->crossfaded ? 0 : compo_pad->ypos, compo_pad->alpha,
outframe, COMPOSITOR_BLEND_MODE_NORMAL); outframe, COMPOSITOR_BLEND_MODE_NORMAL);