Пример #1
0
static void gst_imx_compositor_update_overall_region(GstImxCompositor *compositor)
{
	GList *walk;
	gboolean first = TRUE;

	/* Catch redundant calls */
	if (compositor->overall_region_valid)
		return;

	if ((compositor->overall_width != 0) && (compositor->overall_height != 0))
	{
		/* If the width and height of the overall region are fixed to specific
		 * values by the caller, use these, and don't look at the canvases
		 * in the input pads. */

		compositor->overall_region.x2 = compositor->overall_width;
		compositor->overall_region.y2 = compositor->overall_height;
	}
	else
	{
		/* Overall width and/or height are set to 0. This means the caller wants
		 * the overall region to adapt to the sizes of the input canvases. The
		 * overall region must encompass and show all of them (exception:
		 * pads with negative xpos/ypos coordinates can have their canvas lie
		 * either partially or fully outside of the overall region).
		 * To compute this overall region, walk through all pads and merge their
		 * outer canvas regions together. */

		walk = GST_ELEMENT(compositor)->sinkpads;
		while (walk != NULL)
		{
			GstImxCompositorPad *compositor_pad = GST_IMX_COMPOSITOR_PAD_CAST(walk->data);
			GstImxRegion *outer_region = &(compositor_pad->canvas.outer_region);

			/* Update the outer region, since the xpos/ypos/width/height pad properties
			 * might have changed */
			gst_imx_compositor_pad_compute_outer_region(compositor_pad);

			/* The pad canvasses are *not* updated here. This is because in order for
			 * these updates to be done, a valid overall region needs to exist first.
			 * And the whole point of this loop is to compute said region.
			 * Furthermore, canvas updates anyway are unnecessary here. They'll be
			 * done later, during frame aggregation, when necessary. The only
			 * value that is needed here from the canvas is the outer region, and
			 * this one is already computed above. */

			if (first)
			{
				/* This is the first visited pad, so just copy its outer region */
				compositor->overall_region = *outer_region;
				first = FALSE;
			}
			else
				gst_imx_region_merge(&(compositor->overall_region), &(compositor->overall_region), outer_region);

			GST_DEBUG_OBJECT(compositor, "current outer region: %" GST_IMX_REGION_FORMAT "  merged overall region: %" GST_IMX_REGION_FORMAT, GST_IMX_REGION_ARGS(outer_region), GST_IMX_REGION_ARGS(&(compositor->overall_region)));

			/* Move to next pad */
			walk = g_list_next(walk);
		}
	}

	/* Make sure the overall region starts at (0,0), since any other topleft
	 * coordinates make little sense */
	compositor->overall_region.x1 = 0;
	compositor->overall_region.y1 = 0;

	/* Now that the overall region is computed, walk through the individual
	 * outer regions, and check if any of them completely cover the overall region
	 * If so, the compositor does not have to clear the frame first (= filling
	 * the overall region with fill_region), thus saving bandwidth */
	compositor->region_fill_necessary = TRUE;
	walk = GST_ELEMENT(compositor)->sinkpads;
	while (walk != NULL)
	{
		GstImxCompositorPad *compositor_pad = GST_IMX_COMPOSITOR_PAD_CAST(walk->data);
		GstImxRegion *outer_region = &(compositor_pad->canvas.outer_region);

		/* Check if the outer region completely contains the overall region */
		if (gst_imx_region_contains(&(compositor->overall_region), outer_region) == GST_IMX_REGION_CONTAINS_FULL)
		{
			/* disable filling if this outer region is opaque
			 * (because it will completely cover the overall region) */
			compositor->region_fill_necessary = (compositor_pad->alpha < 1.0);
			break;
		}

		walk = g_list_next(walk);
	}

	compositor->overall_region_valid = TRUE;
}
Пример #2
0
static void gst_imx_video_compositor_update_overall_region(GstImxVideoCompositor *compositor)
{
	GList *walk;
	gboolean first = TRUE;

	/* Catch redundant calls */
	if (compositor->overall_region_valid)
		return;

	if ((compositor->overall_width != 0) && (compositor->overall_height != 0))
	{
		/* If the width and height of the overall region are fixed to specific
		 * values by the caller, use these, and don't look at the canvases
		 * in the input pads. */

		compositor->overall_region.x2 = compositor->overall_width;
		compositor->overall_region.y2 = compositor->overall_height;
	}
	else
	{
		/* Overall width and/or height are set to 0. This means the caller wants
		 * the overall region to adapt to the sizes of the input canvases. The
		 * overall region must encompass and show all of them (exception:
		 * pads with negative xpos/ypos coordinates can have their canvas lie
		 * either partially or fully outside of the overall region).
		 * To compute this overall region, walk through all pads and merge their
		 * outer canvas regions together. */

		walk = GST_ELEMENT(compositor)->sinkpads;
		while (walk != NULL)
		{
			GstImxVideoCompositorPad *compositor_pad = GST_IMX_VIDEO_COMPOSITOR_PAD_CAST(walk->data);
			GstImxRegion *outer_region = &(compositor_pad->canvas.outer_region);

			/* Update the outer region, since the xpos/ypos/width/height pad properties
			 * might have changed */
			gst_imx_video_compositor_pad_compute_outer_region(compositor_pad);

			/* The pad canvasses are *not* updated here. This is because in order for
			 * these updates to be done, a valid overall region needs to exist first.
			 * And the whole point of this loop is to compute said region.
			 * Furthermore, canvas updates anyway are unnecessary here. They'll be
			 * done later, during frame aggregation, when necessary. The only
			 * value that is needed here from the canvas is the outer region, and
			 * this one is already computed above. */

			if (first)
			{
				/* This is the first visited pad, so just copy its outer region */
				compositor->overall_region = *outer_region;
				first = FALSE;
			}
			else
				gst_imx_region_merge(&(compositor->overall_region), &(compositor->overall_region), outer_region);

			GST_DEBUG_OBJECT(compositor, "current outer region: %" GST_IMX_REGION_FORMAT "  merged overall region: %" GST_IMX_REGION_FORMAT, GST_IMX_REGION_ARGS(outer_region), GST_IMX_REGION_ARGS(&(compositor->overall_region)));

			/* Move to next pad */
			walk = g_list_next(walk);
		}
	}

	/* Make sure the overall region starts at (0,0), since any other topleft
	 * coordinates make little sense */
	compositor->overall_region.x1 = 0;
	compositor->overall_region.y1 = 0;

	/* Now that the overall region is computed, walk through the individual
	 * outer regions, and check if any of them completely cover the overall region
	 * If so, the compositor does not have to clear the frame first (= filling
	 * the overall region with fill_region), thus saving bandwidth */
	compositor->region_fill_necessary = TRUE;
	walk = GST_ELEMENT(compositor)->sinkpads;
	while (walk != NULL)
	{
		GstImxVideoCompositorPad *compositor_pad = GST_IMX_VIDEO_COMPOSITOR_PAD_CAST(walk->data);
		GstImxRegion *outer_region = &(compositor_pad->canvas.outer_region);
		GstVideoInfo *info = &(GST_IMXBP_VIDEO_AGGREGATOR_PAD(compositor_pad)->info);

		/* Check if the outer region completely contains the overall region */
		if (gst_imx_region_contains(&(compositor->overall_region), outer_region) == GST_IMX_REGION_CONTAINS_FULL)
		{
			/* The outer region completely contains the inner region.
			 * If the video frames are opaque, then this means that
			 * their pixels will fully overwrite the entire overall
			 * region, so it does not have to be initially filled
			 * with the background color. This is used as a way for
			 * improving performance. Even if there are multiple
			 * input video streams which each have outer regions
			 * that fully contain the overall region, all it takes
			 * is for just one of these to be 100% opaque, and the
			 * region fill is not necessary. So, if such a fully
			 * opaque region that completely covers the overall
			 * region is found, exit the loop immediately, otherwise
			 * keep looking at the other pads.
			 *
			 * Also, blending may be necessary even if alpha is 1.0,
			 * since video frames might themselves have alpha values
			 * per-pixel (GST_VIDEO_INFO_HAS_ALPHA() returns TRUE in
			 * this case then). */
			compositor->region_fill_necessary = (compositor_pad->alpha < 1.0) || GST_VIDEO_INFO_HAS_ALPHA(info);
			if (!compositor->region_fill_necessary)
				break;
		}

		walk = g_list_next(walk);
	}

	compositor->overall_region_valid = TRUE;
}