static GstFlowReturn gst_imx_blitter_video_transform_transform_frame(GstBaseTransform *transform, GstBuffer *in, GstBuffer *out) { gboolean ret = TRUE; GstImxBlitterVideoTransform *blitter_video_transform = GST_IMX_BLITTER_VIDEO_TRANSFORM(transform); g_assert(blitter_video_transform->blitter != NULL); if (!blitter_video_transform->inout_info_set) { GST_ELEMENT_ERROR(transform, CORE, NOT_IMPLEMENTED, (NULL), ("unknown format")); return GST_FLOW_NOT_NEGOTIATED; } if (in == out) { GST_LOG_OBJECT(transform, "passing buffer through"); return GST_FLOW_OK; } GST_IMX_BLITTER_VIDEO_TRANSFORM_LOCK(blitter_video_transform); ret = ret && gst_imx_blitter_set_input_frame(blitter_video_transform->blitter, in); ret = ret && gst_imx_blitter_set_output_frame(blitter_video_transform->blitter, out); ret = ret && gst_imx_blitter_blit(blitter_video_transform->blitter, 255); ret = ret && gst_imx_blitter_set_output_frame(blitter_video_transform->blitter, NULL); GST_IMX_BLITTER_VIDEO_TRANSFORM_UNLOCK(blitter_video_transform); return ret ? GST_FLOW_OK : GST_FLOW_ERROR; }
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; }
static GstFlowReturn gst_imx_blitter_video_sink_show_frame(GstVideoSink *video_sink, GstBuffer *buf) { GstImxBlitterVideoSink *blitter_video_sink = GST_IMX_BLITTER_VIDEO_SINK_CAST(video_sink); GstVideoCropMeta *video_crop_meta; GST_IMX_BLITTER_VIDEO_SINK_LOCK(blitter_video_sink); if (blitter_video_sink->input_crop && ((video_crop_meta = gst_buffer_get_video_crop_meta(buf)) != NULL)) { /* Crop metadata present. Reconfigure canvas. */ GstImxRegion source_region; 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; /* 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(GST_VIDEO_INFO_WIDTH(&(blitter_video_sink->input_video_info)), source_region.x2); source_region.y2 = MIN(GST_VIDEO_INFO_HEIGHT(&(blitter_video_sink->input_video_info)), source_region.y2); GST_LOG_OBJECT(blitter_video_sink, "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_sink->last_frame_with_cropdata) || !gst_imx_region_equal(&source_region, &(blitter_video_sink->last_source_region))) { GST_LOG_OBJECT(blitter_video_sink, "using new crop rectangle %" GST_IMX_REGION_FORMAT, GST_IMX_REGION_ARGS(&source_region)); blitter_video_sink->last_source_region = source_region; blitter_video_sink->canvas_needs_update = TRUE; } blitter_video_sink->last_frame_with_cropdata = TRUE; /* Update canvas and input region if necessary */ if (blitter_video_sink->canvas_needs_update) gst_imx_blitter_video_sink_update_canvas(blitter_video_sink, &(blitter_video_sink->last_source_region)); } else { /* Force an update if this frame has no crop metadata but the last one did */ if (blitter_video_sink->last_frame_with_cropdata) blitter_video_sink->canvas_needs_update = TRUE; blitter_video_sink->last_frame_with_cropdata = FALSE; /* Update canvas and input region if necessary */ if (blitter_video_sink->canvas_needs_update) gst_imx_blitter_video_sink_update_canvas(blitter_video_sink, NULL); } if (blitter_video_sink->canvas.visibility_mask == 0) { /* Visibility mask 0 -> nothing to blit */ GST_IMX_BLITTER_VIDEO_SINK_UNLOCK(blitter_video_sink); return GST_FLOW_OK; } gst_imx_blitter_set_input_frame(blitter_video_sink->blitter, buf); /* If using vsync, blit to the backbuffer, and flip * The flipping is done by scrolling in Y direction * by the same number of rows as there are on screen * The scrolling is implicitely vsync'ed */ if (blitter_video_sink->use_vsync) { /* Select which page to write/blit to */ ++blitter_video_sink->old_fb_page; blitter_video_sink->old_fb_page %= 3; gst_imx_blitter_video_sink_select_fb_page(blitter_video_sink, blitter_video_sink->old_fb_page); /* The actual blitting */ gst_imx_blitter_blit(blitter_video_sink->blitter, 255); /* Flush the blitter to make sure it does not use any cached output * information (for example, the physical address of the previously * selected fb page) */ gst_imx_blitter_flush(blitter_video_sink->blitter); /* Move the current_fb_page index to the next page. See the explanation * at the set_property PROP_USE_VSYNC block for the reason why three * pages are expected instead of 2. */ blitter_video_sink->current_fb_page++; blitter_video_sink->current_fb_page %= 3; /* Flip pages now */ gst_imx_blitter_video_sink_flip_to_selected_fb_page(blitter_video_sink); } else { gst_imx_blitter_blit(blitter_video_sink->blitter, 255); } GST_IMX_BLITTER_VIDEO_SINK_UNLOCK(blitter_video_sink); return GST_FLOW_OK; }