Ejemplo n.º 1
0
static gboolean gst_imx_blitter_video_transform_set_caps(GstBaseTransform *transform, GstCaps *in, GstCaps *out)
{
	gboolean inout_info_equal;
	GstVideoInfo in_info, out_info;
	GstImxBlitterVideoTransform *blitter_video_transform = GST_IMX_BLITTER_VIDEO_TRANSFORM(transform);
	GstImxBlitterVideoTransformClass *klass = GST_IMX_BLITTER_VIDEO_TRANSFORM_CLASS(G_OBJECT_GET_CLASS(transform));
	GstImxCanvas *canvas = &(blitter_video_transform->canvas);
	GstImxRegion source_subset;

	g_assert(klass->are_video_infos_equal != NULL);
	g_assert(blitter_video_transform->blitter != NULL);

	if (!gst_video_info_from_caps(&in_info, in) || !gst_video_info_from_caps(&out_info, out))
	{
		GST_ERROR_OBJECT(transform, "caps are invalid");
		blitter_video_transform->inout_info_set = FALSE;
		return FALSE;
	}

	inout_info_equal = klass->are_video_infos_equal(blitter_video_transform, &in_info, &out_info);

	if (inout_info_equal)
		GST_DEBUG_OBJECT(transform, "input and output caps are equal");
	else
		GST_DEBUG_OBJECT(transform, "input and output caps are not equal:  input: %" GST_PTR_FORMAT "  output: %" GST_PTR_FORMAT, (gpointer)in, (gpointer)out);

	gst_imx_blitter_set_input_video_info(blitter_video_transform->blitter, &in_info);
	gst_imx_blitter_set_output_video_info(blitter_video_transform->blitter, &out_info);

	/* setting new caps changes the canvas, so recalculate it
	 * the recalculation here is done without any input cropping, so set
	 * last_frame_with_cropdata to FALSE, in case subsequent frames do
	 * contain crop metadata */

	blitter_video_transform->last_frame_with_cropdata = FALSE;

	/* the canvas always encompasses the entire output frame */
	canvas->outer_region.x1 = 0;
	canvas->outer_region.y1 = 0;
	canvas->outer_region.x2 = GST_VIDEO_INFO_WIDTH(&out_info);
	canvas->outer_region.y2 = GST_VIDEO_INFO_HEIGHT(&out_info);

	gst_imx_canvas_calculate_inner_region(canvas, &in_info);
	gst_imx_canvas_clip(canvas, &(canvas->outer_region), &in_info, NULL, &source_subset);

	gst_imx_blitter_set_input_region(blitter_video_transform->blitter, &source_subset);
	gst_imx_blitter_set_output_canvas(blitter_video_transform->blitter, canvas);

	blitter_video_transform->input_video_info = in_info;
	blitter_video_transform->output_video_info = out_info;
	blitter_video_transform->inout_info_equal = inout_info_equal;
	blitter_video_transform->inout_info_set = TRUE;

	return TRUE;
}
Ejemplo n.º 2
0
gboolean gst_imx_blitter_compositor_draw_frame(GstImxCompositor *compositor, GstVideoInfo const *input_info, GstImxRegion const *input_region, GstImxCanvas const *output_canvas, GstBuffer *input_frame, guint8 alpha)
{
	gboolean ret = TRUE;
	GstImxBlitterCompositor *blitter_compositor = GST_IMX_BLITTER_COMPOSITOR(compositor);
	g_assert(blitter_compositor->blitter != NULL);

	ret = ret && gst_imx_blitter_set_input_video_info(blitter_compositor->blitter, input_info);
	ret = ret && gst_imx_blitter_set_input_region(blitter_compositor->blitter, input_region);
	ret = ret && gst_imx_blitter_set_input_frame(blitter_compositor->blitter, input_frame);
	ret = ret && gst_imx_blitter_set_output_canvas(blitter_compositor->blitter, output_canvas);

	ret = ret && gst_imx_blitter_blit(blitter_compositor->blitter, alpha);

	return ret;
}
Ejemplo n.º 3
0
static gboolean gst_imx_blitter_video_sink_acquire_blitter(GstImxBlitterVideoSink *blitter_video_sink)
{
	/* must be called with lock held */

	GstImxBlitterVideoSinkClass *klass = GST_IMX_BLITTER_VIDEO_SINK_CLASS(G_OBJECT_GET_CLASS(blitter_video_sink));

	g_assert(blitter_video_sink != NULL);
	g_assert(blitter_video_sink->framebuffer != NULL);
	g_assert(klass->create_blitter != NULL);

	/* Do nothing if the blitter is already acquired */
	if (blitter_video_sink->blitter != NULL)
		return TRUE;

	if ((blitter_video_sink->blitter = klass->create_blitter(blitter_video_sink)) == NULL)
	{
		GST_ERROR_OBJECT(blitter_video_sink, "could not acquire blitter");
		return FALSE;
	}

	if (!gst_imx_blitter_set_output_frame(blitter_video_sink->blitter, blitter_video_sink->framebuffer))
	{
		GST_ERROR_OBJECT(blitter_video_sink, "could not set the output frame");
		return FALSE;
	}

	if (!gst_imx_blitter_set_output_canvas(blitter_video_sink->blitter, &(blitter_video_sink->canvas)))
	{
		GST_ERROR_OBJECT(blitter_video_sink, "could not set the output canvas");
		return FALSE;
	}

	if (!gst_imx_blitter_set_output_video_info(blitter_video_sink->blitter, &(blitter_video_sink->output_video_info)))
	{
		GST_ERROR_OBJECT(blitter_video_sink, "could not set the output video info");
		return FALSE;
	}

	if (!gst_imx_blitter_set_num_output_pages(blitter_video_sink->blitter, blitter_video_sink->use_vsync ? 3 : 1))
	{
		GST_ERROR_OBJECT(blitter_video_sink, "could not set the number of output pages");
		return FALSE;
	}

	return TRUE;
}
Ejemplo n.º 4
0
static void gst_imx_blitter_video_sink_update_canvas(GstImxBlitterVideoSink *blitter_video_sink, GstImxRegion const *source_region)
{
	/* must be called with lock held */

	GstImxRegion *outer_region = &(blitter_video_sink->canvas.outer_region);
	GstImxRegion source_subset;

	/* Define the outer region */
	if ((blitter_video_sink->window_width == 0) || (blitter_video_sink->window_height == 0))
	{
		/* If either window_width or window_height is 0, then just use the
		 * entire framebuffer as the outer region */
		*outer_region = blitter_video_sink->framebuffer_region;
	}
	else
	{
		/* Use the defined window as the outer region */
		outer_region->x1 = blitter_video_sink->window_x_coord;
		outer_region->y1 = blitter_video_sink->window_y_coord;
		outer_region->x2 = blitter_video_sink->window_x_coord + blitter_video_sink->window_width;
		outer_region->y2 = blitter_video_sink->window_y_coord + blitter_video_sink->window_height;
	}

	gst_imx_canvas_calculate_inner_region(&(blitter_video_sink->canvas), &(blitter_video_sink->input_video_info));
	gst_imx_canvas_clip(
		&(blitter_video_sink->canvas),
		&(blitter_video_sink->framebuffer_region),
		&(blitter_video_sink->input_video_info),
		source_region,
		&source_subset
	);

	gst_imx_blitter_set_input_region(blitter_video_sink->blitter, &source_subset);
	gst_imx_blitter_set_output_canvas(blitter_video_sink->blitter, &(blitter_video_sink->canvas));

	blitter_video_sink->canvas_needs_update = FALSE;
}
Ejemplo n.º 5
0
static GstFlowReturn gst_imx_blitter_video_transform_prepare_output_buffer(GstBaseTransform *transform, GstBuffer *input, GstBuffer **outbuf)
{
	gboolean passthrough;
	GstImxBlitterVideoTransform *blitter_video_transform = GST_IMX_BLITTER_VIDEO_TRANSFORM(transform);
	GstImxBlitterVideoTransformClass *klass = GST_IMX_BLITTER_VIDEO_TRANSFORM_CLASS(G_OBJECT_GET_CLASS(transform));
	GstVideoCropMeta *video_crop_meta;
	gboolean update_canvas = FALSE;

	/* If either there is no input buffer or in- and output info are not equal,
	 * it is clear there can be no passthrough mode */
	passthrough = (input != NULL) && blitter_video_transform->inout_info_equal;

	GST_IMX_BLITTER_VIDEO_TRANSFORM_LOCK(blitter_video_transform);

	/* Check if cropping needs to be done */
	if ((input != NULL) && blitter_video_transform->input_crop && ((video_crop_meta = gst_buffer_get_video_crop_meta(input)) != NULL))
	{
		GstImxRegion source_region;
		gint in_width, in_height;

		source_region.x1 = video_crop_meta->x;
		source_region.y1 = video_crop_meta->y;
		source_region.x2 = video_crop_meta->x + video_crop_meta->width;
		source_region.y2 = video_crop_meta->y + video_crop_meta->height;

		in_width = GST_VIDEO_INFO_WIDTH(&(blitter_video_transform->input_video_info));
		in_height = GST_VIDEO_INFO_HEIGHT(&(blitter_video_transform->input_video_info));

		/* Make sure the source region does not exceed valid bounds */
		source_region.x1 = MAX(0, source_region.x1);
		source_region.y1 = MAX(0, source_region.y1);
		source_region.x2 = MIN(in_width, source_region.x2);
		source_region.y2 = MIN(in_height, source_region.y2);

		/* If the crop rectangle encompasses the entire frame, cropping is
		 * effectively a no-op, so make it passthrough in that case,
		 * unless passthrough is already FALSE */
		passthrough = passthrough && (source_region.x1 == 0) && (source_region.y1 == 0) && (source_region.x2 == in_width) && (source_region.y2 == in_height);

		GST_LOG_OBJECT(blitter_video_transform, "retrieved crop rectangle %" GST_IMX_REGION_FORMAT, GST_IMX_REGION_ARGS(&source_region));

		/* Canvas needs to be updated if either one of these applies:
		 * - the current frame has crop metadata, the last one didn't
		 * - the new crop rectangle and the last are different */
		if (!(blitter_video_transform->last_frame_with_cropdata) || !gst_imx_region_equal(&source_region, &(blitter_video_transform->last_source_region)))
		{
			GST_LOG_OBJECT(blitter_video_transform, "using new crop rectangle %" GST_IMX_REGION_FORMAT, GST_IMX_REGION_ARGS(&source_region));
			blitter_video_transform->last_source_region = source_region;
			update_canvas = TRUE;
		}

		blitter_video_transform->last_frame_with_cropdata = TRUE;
	}
	else
	{
		/* Force a canvas update if this frame has no crop metadata but the last one did */
		if (blitter_video_transform->last_frame_with_cropdata)
			update_canvas = TRUE;
		blitter_video_transform->last_frame_with_cropdata = FALSE;
	}

	if (update_canvas)
	{
		GstImxRegion source_subset;
		GstImxCanvas *canvas = &(blitter_video_transform->canvas);

		gst_imx_canvas_clip(
			canvas,
			&(canvas->outer_region),
			&(blitter_video_transform->input_video_info),
			blitter_video_transform->last_frame_with_cropdata ? &(blitter_video_transform->last_source_region) : NULL,
			&source_subset
		);

		gst_imx_blitter_set_input_region(blitter_video_transform->blitter, &source_subset);
		gst_imx_blitter_set_output_canvas(blitter_video_transform->blitter, canvas);
	}

	if ((input != NULL) && passthrough)
	{
		/* test for additional special cases for passthrough must not be enabled
		 * such case are transforms like rotation, deinterlacing ... */
		passthrough = passthrough && (blitter_video_transform->canvas.inner_rotation == GST_IMX_CANVAS_INNER_ROTATION_NONE) &&
		              (klass->are_transforms_necessary != NULL) &&
		              !(klass->are_transforms_necessary(blitter_video_transform, input));
	}
	else if (!blitter_video_transform->inout_info_equal)
		GST_LOG_OBJECT(transform, "input and output caps are not equal");
	else if (blitter_video_transform->last_frame_with_cropdata && !passthrough)
		GST_LOG_OBJECT(transform, "cropping is performed");
	else if (input == NULL)
		GST_LOG_OBJECT(transform, "input buffer is NULL");

	GST_IMX_BLITTER_VIDEO_TRANSFORM_UNLOCK(blitter_video_transform);

	GST_LOG_OBJECT(transform, "passthrough: %s", passthrough ? "yes" : "no");

	if (passthrough)
	{
		/* This instructs the base class to not allocate a new buffer for
		 * the output, and instead pass the input buffer as the output
		 * (this is used in the fransform_frame function below) */
		*outbuf = input;
		return GST_FLOW_OK;
	}
	else
		return GST_BASE_TRANSFORM_CLASS(gst_imx_blitter_video_transform_parent_class)->prepare_output_buffer(transform, input, outbuf);
}