| /* GStreamer IMX video compositor plugin |
| * Copyright (c) 2015-2016, Freescale Semiconductor, Inc. All rights reserved. |
| * Copyright 2018 NXP |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| * Boston, MA 02111-1307, USA. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <string.h> |
| #include <gst/allocators/gstphymemmeta.h> |
| #include <gst/allocators/gstdmabuf.h> |
| #ifdef USE_ION |
| #include <gst/allocators/gstionmemory.h> |
| #endif |
| #include "gstimxcompositorpad.h" |
| #include "gstimxcompositor.h" |
| #include "imx_2d_device.h" |
| |
| #define ENABLE_OBSCURED_CHECKING |
| |
| #define DEFAULT_IMXCOMPOSITOR_PAD_XPOS 0 |
| #define DEFAULT_IMXCOMPOSITOR_PAD_YPOS 0 |
| #define DEFAULT_IMXCOMPOSITOR_PAD_WIDTH 0 |
| #define DEFAULT_IMXCOMPOSITOR_PAD_HEIGHT 0 |
| #define DEFAULT_IMXCOMPOSITOR_PAD_ROTATE IMX_2D_ROTATION_0 |
| #define DEFAULT_IMXCOMPOSITOR_PAD_ALPHA 1.0 |
| #define DEFAULT_IMXCOMPOSITOR_PAD_KEEP_RATIO FALSE |
| #define SINK_TEMP_BUFFER_INIT_SIZE (1920*1088*2) |
| |
| GST_DEBUG_CATEGORY_EXTERN (gst_imxcompositor_debug); |
| |
| GType gst_imx_compositor_rotation_get_type(void) { |
| static GType gst_imx_compositor_rotation_type = 0; |
| |
| if (!gst_imx_compositor_rotation_type) { |
| static GEnumValue rotation_values[] = { |
| {IMX_2D_ROTATION_0, "No rotation", "none"}, |
| {IMX_2D_ROTATION_90, "Rotate 90 degrees", "rotate-90"}, |
| {IMX_2D_ROTATION_180, "Rotate 180 degrees", "rotate-180"}, |
| {IMX_2D_ROTATION_270, "Rotate 270 degrees", "rotate-270"}, |
| {IMX_2D_ROTATION_HFLIP, "Flip horizontally", "horizontal-flip"}, |
| {IMX_2D_ROTATION_VFLIP, "Flip vertically", "vertical-flip"}, |
| {0, NULL, NULL }, |
| }; |
| |
| gst_imx_compositor_rotation_type = |
| g_enum_register_static("ImxCompositorRotationMode", rotation_values); |
| } |
| |
| return gst_imx_compositor_rotation_type; |
| } |
| |
| enum |
| { |
| PROP_IMXCOMPOSITOR_PAD_0, |
| PROP_IMXCOMPOSITOR_PAD_XPOS, |
| PROP_IMXCOMPOSITOR_PAD_YPOS, |
| PROP_IMXCOMPOSITOR_PAD_WIDTH, |
| PROP_IMXCOMPOSITOR_PAD_HEIGHT, |
| PROP_IMXCOMPOSITOR_PAD_ALPHA, |
| PROP_IMXCOMPOSITOR_PAD_ROTATE, |
| PROP_IMXCOMPOSITOR_PAD_DEINTERLACE, |
| PROP_IMXCOMPOSITOR_PAD_KEEP_RATIO |
| }; |
| |
| G_DEFINE_TYPE (GstImxCompositorPad, gst_imxcompositor_pad, \ |
| GST_TYPE_VIDEO_AGGREGATOR_PAD); |
| |
| static void |
| gst_imxcompositor_pad_get_property (GObject * object, guint prop_id, |
| GValue * value, GParamSpec * pspec) |
| { |
| GstImxCompositorPad *pad = GST_IMXCOMPOSITOR_PAD (object); |
| |
| switch (prop_id) { |
| case PROP_IMXCOMPOSITOR_PAD_XPOS: |
| g_value_set_int (value, pad->xpos); |
| break; |
| case PROP_IMXCOMPOSITOR_PAD_YPOS: |
| g_value_set_int (value, pad->ypos); |
| break; |
| case PROP_IMXCOMPOSITOR_PAD_WIDTH: |
| g_value_set_int (value, pad->width); |
| break; |
| case PROP_IMXCOMPOSITOR_PAD_HEIGHT: |
| g_value_set_int (value, pad->height); |
| break; |
| case PROP_IMXCOMPOSITOR_PAD_ROTATE: |
| g_value_set_enum (value, pad->rotate); |
| break; |
| case PROP_IMXCOMPOSITOR_PAD_ALPHA: |
| { |
| GstImxCompositor* comp = (GstImxCompositor*)gst_pad_get_parent(pad); |
| if (comp->capabilities & IMX_2D_DEVICE_CAP_ALPHA) { |
| g_value_set_double (value, pad->alpha); |
| } else { |
| g_value_set_double (value, 1.0); |
| g_print("!This device don't support alpha blending!\n"); |
| } |
| } |
| break; |
| case PROP_IMXCOMPOSITOR_PAD_KEEP_RATIO: |
| g_value_set_boolean(value, pad->keep_ratio); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| break; |
| } |
| } |
| |
| static void |
| gst_imxcompositor_pad_set_property (GObject * object, guint prop_id, |
| const GValue * value, GParamSpec * pspec) |
| { |
| GstImxCompositorPad *pad = GST_IMXCOMPOSITOR_PAD (object); |
| |
| switch (prop_id) { |
| case PROP_IMXCOMPOSITOR_PAD_XPOS: |
| pad->xpos = g_value_get_int (value); |
| break; |
| case PROP_IMXCOMPOSITOR_PAD_YPOS: |
| pad->ypos = g_value_get_int (value); |
| break; |
| case PROP_IMXCOMPOSITOR_PAD_ALPHA: |
| { |
| GstImxCompositor* comp = (GstImxCompositor*)gst_pad_get_parent(pad); |
| if (comp->capabilities & IMX_2D_DEVICE_CAP_ALPHA) { |
| pad->alpha = g_value_get_double (value); |
| } else { |
| pad->alpha = 1.0; |
| g_print("!This device don't support alpha blending, " |
| "pad alpha setting will be ignored!\n"); |
| } |
| gst_object_unref(comp); |
| } |
| break; |
| case PROP_IMXCOMPOSITOR_PAD_WIDTH: |
| pad->width = g_value_get_int (value); |
| break; |
| case PROP_IMXCOMPOSITOR_PAD_HEIGHT: |
| pad->height = g_value_get_int (value); |
| break; |
| case PROP_IMXCOMPOSITOR_PAD_ROTATE: |
| pad->rotate = g_value_get_enum (value); |
| break; |
| case PROP_IMXCOMPOSITOR_PAD_KEEP_RATIO: |
| pad->keep_ratio = g_value_get_boolean(value); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| break; |
| } |
| } |
| |
| static void |
| gst_imxcompositor_pad_finalize (GObject * object) |
| { |
| GstImxCompositorPad *pad = GST_IMXCOMPOSITOR_PAD (object); |
| |
| if (pad->sink_tmp_buf) { |
| gst_buffer_unref(pad->sink_tmp_buf); |
| pad->sink_tmp_buf = NULL; |
| } |
| |
| if (pad->sink_pool) { |
| gst_buffer_pool_set_active (pad->sink_pool, FALSE); |
| gst_object_unref (pad->sink_pool); |
| pad->sink_pool = NULL; |
| } |
| |
| G_OBJECT_CLASS (gst_imxcompositor_pad_parent_class)->finalize (object); |
| } |
| |
| void |
| gst_imxcompositor_pad_get_output_size (GstVideoAggregator * vagg, |
| GstImxCompositorPad * comp_pad, gint * width, gint * height) |
| { |
| GstVideoAggregatorPad *vagg_pad = GST_VIDEO_AGGREGATOR_PAD (comp_pad); |
| gint pad_width, pad_height; |
| guint dar_n, dar_d; |
| gint v_width, v_height; |
| GstVideoCropMeta *in_crop = NULL; |
| |
| if (!vagg || !comp_pad || !width || !height) |
| return; |
| |
| *width = comp_pad->width; |
| *height = comp_pad->height; |
| |
| if (!vagg_pad->info.finfo || !vagg->info.finfo) |
| return; |
| |
| v_width = GST_VIDEO_INFO_WIDTH (&vagg_pad->info); |
| v_height = GST_VIDEO_INFO_HEIGHT (&vagg_pad->info); |
| |
| if (vagg_pad->buffer) { |
| in_crop = gst_buffer_get_video_crop_meta(vagg_pad->buffer); |
| if (in_crop != NULL) { |
| GST_LOG_OBJECT (vagg_pad, "input crop meta: (%d, %d, %d, %d)", |
| in_crop->x, in_crop->y, in_crop->width, in_crop->height); |
| if ((in_crop->x >= v_width) || (in_crop->y >= v_height)) { |
| *width = *height = 0; |
| return; |
| } |
| |
| v_width = MIN(in_crop->width, (v_width - in_crop->x)); |
| v_height = MIN(in_crop->height, (v_height - in_crop->y)); |
| } |
| } |
| |
| pad_width = comp_pad->width <= 0 ? v_width : comp_pad->width; |
| pad_height = comp_pad->height <= 0 ? v_height : comp_pad->height; |
| |
| 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_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)); |
| |
| if (pad_height % dar_n == 0) { |
| pad_width = gst_util_uint64_scale_int (pad_height, dar_n, dar_d); |
| } else if (pad_width % dar_d == 0) { |
| pad_height = gst_util_uint64_scale_int (pad_width, dar_d, dar_n); |
| } else { |
| pad_width = gst_util_uint64_scale_int (pad_height, dar_n, dar_d); |
| } |
| |
| *width = pad_width; |
| *height = pad_height; |
| } |
| |
| static gboolean |
| gst_imxcompositor_pad_set_info (GstVideoAggregatorPad * pad, |
| GstVideoAggregator * vagg G_GNUC_UNUSED, |
| GstVideoInfo * current_info, GstVideoInfo * wanted_info) |
| { |
| GstImxCompositor *comp = (GstImxCompositor *)(vagg); |
| GstImxCompositorPad *cpad = (GstImxCompositorPad *)(pad); |
| gchar *colorimetry, *best_colorimetry; |
| const gchar *chroma, *best_chroma; |
| gint width, height; |
| |
| if (!current_info->finfo) |
| return TRUE; |
| |
| if (GST_VIDEO_INFO_FORMAT (current_info) == GST_VIDEO_FORMAT_UNKNOWN) |
| return TRUE; |
| |
| colorimetry = gst_video_colorimetry_to_string (&(current_info->colorimetry)); |
| chroma = gst_video_chroma_to_string (current_info->chroma_site); |
| |
| best_colorimetry = |
| gst_video_colorimetry_to_string (&(wanted_info->colorimetry)); |
| best_chroma = gst_video_chroma_to_string (wanted_info->chroma_site); |
| |
| gst_imxcompositor_pad_get_output_size (vagg, cpad, &width, &height); |
| |
| if (GST_VIDEO_INFO_FORMAT(wanted_info) != GST_VIDEO_INFO_FORMAT(current_info) |
| || g_strcmp0 (colorimetry, best_colorimetry) |
| || g_strcmp0 (chroma, best_chroma) |
| || width != current_info->width || height != current_info->height) { |
| GstVideoInfo tmp_info; |
| |
| gst_video_info_set_format (&tmp_info, GST_VIDEO_INFO_FORMAT (wanted_info), |
| 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.fps_n = current_info->fps_n; |
| tmp_info.fps_d = current_info->fps_d; |
| tmp_info.flags = current_info->flags; |
| tmp_info.interlace_mode = current_info->interlace_mode; |
| |
| GST_DEBUG_OBJECT (pad, "This pad will be converted from %d to %d", |
| GST_VIDEO_INFO_FORMAT (current_info), |
| GST_VIDEO_INFO_FORMAT (&tmp_info)); |
| |
| cpad->info = tmp_info; |
| } else { |
| cpad->info = *current_info; |
| GST_DEBUG_OBJECT (pad, "This pad will not need conversion"); |
| } |
| g_free (colorimetry); |
| g_free (best_colorimetry); |
| |
| return TRUE; |
| } |
| |
| static gboolean |
| is_rectangle_contained (GstVideoRectangle rect1, GstVideoRectangle rect2) |
| { |
| if ((rect2.x <= rect1.x) && (rect2.y <= rect1.y) && |
| ((rect2.x + rect2.w) >= (rect1.x + rect1.w)) && |
| ((rect2.y + rect2.h) >= (rect1.y + rect1.h))) |
| return TRUE; |
| return FALSE; |
| } |
| |
| static GstVideoRectangle |
| clamp_rectangle (GstVideoRectangle rect, gint outer_width, gint outer_height) |
| { |
| gint x2 = rect.x + rect.w; |
| gint y2 = rect.y + rect.h; |
| GstVideoRectangle clamped; |
| |
| clamped.x = CLAMP (rect.x, 0, outer_width); |
| clamped.y = CLAMP (rect.y, 0, outer_height); |
| clamped.w = CLAMP (x2, 0, outer_width) - clamped.x; |
| clamped.h = CLAMP (y2, 0, outer_height) - clamped.y; |
| |
| return clamped; |
| } |
| |
| static gboolean |
| gst_imxcompositor_pad_prepare_frame (GstVideoAggregatorPad * pad, |
| GstVideoAggregator * vagg) |
| { |
| GstImxCompositor *imxcomp = (GstImxCompositor *)(vagg); |
| GstImxCompositorPad *cpad = (GstImxCompositorPad *)(pad); |
| GstVideoFrame *frame; |
| gint width, height; |
| GstVideoRectangle video_area; |
| GstVideoRectangle clamp; |
| gint o_width, o_height; |
| GstVideoCropMeta *in_crop = NULL; |
| |
| if (!pad->buffer) |
| return TRUE; |
| |
| gst_imxcompositor_pad_get_output_size (vagg, cpad, &width, &height); |
| |
| if (cpad->alpha == 0.0) { |
| GST_DEBUG_OBJECT (vagg, "Pad has alpha 0.0, not converting frame"); |
| pad->aggregated_frame = NULL; |
| return TRUE; |
| } |
| |
| cpad->src_crop.x = 0; |
| cpad->src_crop.y = 0; |
| cpad->src_crop.w = GST_VIDEO_INFO_WIDTH (&pad->info); |
| cpad->src_crop.h = GST_VIDEO_INFO_HEIGHT (&pad->info); |
| |
| in_crop = gst_buffer_get_video_crop_meta(pad->buffer); |
| if (in_crop != NULL) { |
| GST_LOG_OBJECT (pad, "input crop meta: (%d, %d, %d, %d)", |
| in_crop->x, in_crop->y, in_crop->width, in_crop->height); |
| if ((in_crop->x >= cpad->src_crop.w) || (in_crop->y >= cpad->src_crop.h)) { |
| pad->aggregated_frame = NULL; |
| return TRUE; |
| } |
| |
| cpad->src_crop.x = in_crop->x; |
| cpad->src_crop.y = in_crop->y; |
| cpad->src_crop.w = MIN(in_crop->width, (cpad->src_crop.w - in_crop->x)); |
| cpad->src_crop.h = MIN(in_crop->height, (cpad->src_crop.h - in_crop->y)); |
| } |
| |
| video_area.x = cpad->xpos; |
| video_area.y = cpad->ypos; |
| video_area.w = width; |
| video_area.h = height; |
| |
| if (cpad->keep_ratio) { |
| GstVideoRectangle s_rect, d_rect, result; |
| s_rect.x = s_rect.y = 0; |
| s_rect.w = cpad->src_crop.w; |
| s_rect.h = cpad->src_crop.h; |
| d_rect.x = d_rect.y = 0; |
| d_rect.w = width; |
| d_rect.h = height; |
| if (cpad->rotate == IMX_2D_ROTATION_90 || |
| cpad->rotate == IMX_2D_ROTATION_270) { |
| gint tmp = d_rect.w; |
| d_rect.w = d_rect.h; |
| d_rect.h = tmp; |
| } |
| |
| gst_video_sink_center_rect (s_rect, d_rect, &result, TRUE); |
| |
| if (cpad->rotate == IMX_2D_ROTATION_90 || |
| cpad->rotate == IMX_2D_ROTATION_270) { |
| video_area.x += result.y; |
| video_area.y += result.x; |
| video_area.w = result.h; |
| video_area.h = result.w; |
| } else { |
| video_area.x += result.x; |
| video_area.y += result.y; |
| video_area.w = result.w; |
| video_area.h = result.h; |
| } |
| } |
| |
| o_width = GST_VIDEO_INFO_WIDTH (&vagg->info); |
| o_height = GST_VIDEO_INFO_HEIGHT (&vagg->info); |
| clamp = clamp_rectangle (video_area, o_width, o_height); |
| |
| if (clamp.w == 0 || clamp.h == 0) { |
| GST_DEBUG_OBJECT (vagg, "Resulting frame is zero-width or zero-height " |
| "(w: %i, h: %i), skipping", clamp.w, clamp.h); |
| pad->aggregated_frame = NULL; |
| return TRUE; |
| } |
| |
| cpad->dst_crop = clamp; |
| cpad->src_crop.x = cpad->src_crop.x + |
| (cpad->dst_crop.x - video_area.x) * cpad->src_crop.w / video_area.w; |
| cpad->src_crop.y = cpad->src_crop.y + |
| (cpad->dst_crop.y - video_area.y) * cpad->src_crop.h / video_area.h; |
| cpad->src_crop.w = cpad->dst_crop.w * cpad->src_crop.w / video_area.w; |
| cpad->src_crop.h = cpad->dst_crop.h * cpad->src_crop.h / video_area.h; |
| |
| #ifdef ENABLE_OBSCURED_CHECKING |
| gboolean frame_obscured = FALSE; |
| GList *l; |
| |
| GST_OBJECT_LOCK (vagg); |
| /* Check if this frame is obscured by a higher-zorder frame */ |
| for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) { |
| GstVideoRectangle frame2_rect; |
| GstVideoAggregatorPad *pad2 = l->data; |
| GstImxCompositorPad *cpad2 = (GstImxCompositorPad *)(pad2); |
| gint pad2_width, pad2_height; |
| |
| if (pad2->zorder > pad->zorder && pad2->buffer && cpad2->alpha == 1.0 && |
| !GST_VIDEO_INFO_HAS_ALPHA (&pad2->info)) { |
| gst_imxcompositor_pad_get_output_size (vagg, cpad2, |
| &pad2_width, &pad2_height); |
| |
| frame2_rect.x = cpad2->xpos; |
| frame2_rect.y = cpad2->ypos; |
| frame2_rect.w = pad2_width; |
| frame2_rect.h = pad2_height; |
| |
| if (is_rectangle_contained (clamp, frame2_rect)) { |
| frame_obscured = TRUE; |
| GST_DEBUG_OBJECT (pad, "%ix%i@(%i,%i) obscured by %s %ix%i@(%i,%i) " |
| "in output of size %ix%i; skipping frame", clamp.w, clamp.h, |
| clamp.x, clamp.y, GST_PAD_NAME (pad2), frame2_rect.w, |
| frame2_rect.h, frame2_rect.x, frame2_rect.y, o_width, o_height); |
| break; |
| } |
| } |
| } |
| GST_OBJECT_UNLOCK (vagg); |
| |
| if (frame_obscured) { |
| pad->aggregated_frame = NULL; |
| return TRUE; |
| } |
| #endif |
| |
| frame = g_slice_new0 (GstVideoFrame); |
| |
| #if GST_CHECK_VERSION(1, 14, 0) |
| if (!gst_video_frame_map (frame, &pad->info, pad->buffer, |
| #else |
| if (!gst_video_frame_map (frame, &pad->buffer_vinfo, pad->buffer, |
| #endif |
| GST_MAP_READ)) { |
| |
| GST_WARNING_OBJECT (vagg, "Could not map input buffer"); |
| g_slice_free (GstVideoFrame, frame); |
| return FALSE; |
| } |
| |
| /* Check if need copy input frame */ |
| if (!(gst_buffer_is_phymem(pad->buffer) |
| || gst_is_dmabuf_memory (gst_buffer_peek_memory (pad->buffer, 0)))) { |
| GST_DEBUG_OBJECT (pad, "copy input frame to physical continues memory"); |
| GstVideoInfo info; |
| GstCaps *caps = gst_video_info_to_caps(&frame->info); |
| gst_video_info_from_caps(&info, caps); //update the size info |
| gst_caps_unref(caps); |
| |
| if (!imxcomp->allocator) { |
| #ifdef USE_ION |
| imxcomp->allocator = gst_ion_allocator_obtain (); |
| #endif |
| } |
| |
| if (!imxcomp->allocator) |
| imxcomp->allocator = |
| gst_imx_2d_device_allocator_new((gpointer)(imxcomp->device)); |
| |
| if (!cpad->sink_tmp_buf) { |
| cpad->sink_tmp_buf = gst_buffer_new_allocate(imxcomp->allocator, |
| SINK_TEMP_BUFFER_INIT_SIZE, NULL); |
| cpad->sink_tmp_buf_size = SINK_TEMP_BUFFER_INIT_SIZE; |
| } |
| |
| if (cpad->sink_tmp_buf && info.size > SINK_TEMP_BUFFER_INIT_SIZE) { |
| if (cpad->sink_tmp_buf) |
| gst_buffer_unref(cpad->sink_tmp_buf); |
| cpad->sink_tmp_buf = gst_buffer_new_allocate(imxcomp->allocator, |
| info.size, NULL); |
| cpad->sink_tmp_buf_size = info.size; |
| } |
| |
| if (cpad->sink_tmp_buf) { |
| GstVideoFrame *copy_frame = g_slice_new0 (GstVideoFrame); |
| gst_video_frame_map(copy_frame, &info, cpad->sink_tmp_buf, GST_MAP_WRITE); |
| gst_video_frame_copy(copy_frame, frame); |
| gst_video_frame_unmap (frame); |
| g_slice_free (GstVideoFrame, frame); |
| frame = copy_frame; |
| |
| if (imxcomp->composition_meta_enable |
| && imx_video_overlay_composition_has_meta(pad->buffer)) { |
| imx_video_overlay_composition_remove_meta(cpad->sink_tmp_buf); |
| imx_video_overlay_composition_copy_meta(cpad->sink_tmp_buf, pad->buffer, |
| frame->info.width, frame->info.height, |
| frame->info.width, frame->info.height); |
| } |
| } else { |
| GST_ERROR_OBJECT (pad, |
| "Can't get input buffer,ignore this frame,continue next"); |
| gst_video_frame_unmap (frame); |
| g_slice_free (GstVideoFrame, frame); |
| pad->aggregated_frame = NULL; |
| return TRUE; |
| } |
| } |
| |
| if (cpad->sink_pool_update) { |
| memset (&cpad->align, 0, sizeof(GstVideoAlignment)); |
| if (cpad->sink_pool && gst_buffer_pool_is_active (cpad->sink_pool)) { |
| GstStructure *config = gst_buffer_pool_get_config (cpad->sink_pool); |
| |
| if (gst_buffer_pool_config_has_option (config, |
| GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) { |
| gst_buffer_pool_config_get_video_alignment (config, &cpad->align); |
| GST_DEBUG_OBJECT (pad, "input pool has alignment (%d, %d) , (%d, %d)", |
| cpad->align.padding_left, cpad->align.padding_top, |
| cpad->align.padding_right, cpad->align.padding_bottom); |
| } |
| gst_structure_free (config); |
| } else { |
| GstPhyMemMeta *phymemmeta = GST_PHY_MEM_META_GET (pad->buffer); |
| if (phymemmeta) { |
| cpad->align.padding_right = phymemmeta->x_padding; |
| cpad->align.padding_bottom = phymemmeta->y_padding; |
| GST_DEBUG_OBJECT (pad, "physical memory meta x_padding: %d " |
| "y_padding: %d",phymemmeta->x_padding, phymemmeta->y_padding); |
| } |
| } |
| cpad->sink_pool_update = FALSE; |
| } |
| |
| GstSegment *seg = &((GstAggregatorPad*)pad)->segment; |
| GstClockTime timestamp = GST_BUFFER_TIMESTAMP (pad->buffer); |
| gint64 stream_time = |
| gst_segment_to_stream_time (seg, GST_FORMAT_TIME, timestamp); |
| /* sync object properties on stream time */ |
| if (GST_CLOCK_TIME_IS_VALID (stream_time)) |
| gst_object_sync_values (GST_OBJECT (pad), stream_time); |
| |
| pad->aggregated_frame = frame; |
| |
| return TRUE; |
| } |
| |
| static void |
| gst_imxcompositor_pad_clean_frame (GstVideoAggregatorPad * pad, |
| GstVideoAggregator * vagg) |
| { |
| if (pad->aggregated_frame) { |
| gst_video_frame_unmap (pad->aggregated_frame); |
| g_slice_free (GstVideoFrame, pad->aggregated_frame); |
| pad->aggregated_frame = NULL; |
| } |
| } |
| |
| static void |
| gst_imxcompositor_pad_class_init (GstImxCompositorPadClass * klass) |
| { |
| GObjectClass *gobject_class = (GObjectClass *) klass; |
| GstVideoAggregatorPadClass *vaggpadclass = |
| (GstVideoAggregatorPadClass *) klass; |
| |
| gobject_class->set_property = gst_imxcompositor_pad_set_property; |
| gobject_class->get_property = gst_imxcompositor_pad_get_property; |
| gobject_class->finalize = gst_imxcompositor_pad_finalize; |
| |
| g_object_class_install_property (gobject_class, PROP_IMXCOMPOSITOR_PAD_XPOS, |
| g_param_spec_int ("xpos", "X Position", "X Position of the picture", |
| G_MININT32, G_MAXINT32, DEFAULT_IMXCOMPOSITOR_PAD_XPOS, |
| G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); |
| g_object_class_install_property (gobject_class, PROP_IMXCOMPOSITOR_PAD_YPOS, |
| g_param_spec_int ("ypos", "Y Position", "Y Position of the picture", |
| G_MININT32, G_MAXINT32, DEFAULT_IMXCOMPOSITOR_PAD_YPOS, |
| G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); |
| g_object_class_install_property (gobject_class, PROP_IMXCOMPOSITOR_PAD_WIDTH, |
| g_param_spec_int ("width", "Width", "Target width of the picture", |
| G_MININT32, G_MAXINT32, DEFAULT_IMXCOMPOSITOR_PAD_WIDTH, |
| G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); |
| g_object_class_install_property (gobject_class, PROP_IMXCOMPOSITOR_PAD_HEIGHT, |
| g_param_spec_int ("height", "Height", "Target height of the picture", |
| G_MININT32, G_MAXINT32, DEFAULT_IMXCOMPOSITOR_PAD_HEIGHT, |
| G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); |
| g_object_class_install_property (gobject_class, PROP_IMXCOMPOSITOR_PAD_ROTATE, |
| g_param_spec_enum("rotate", "input rotation", |
| "Rotation that shall be applied to input frames", |
| gst_imx_compositor_rotation_get_type(), |
| DEFAULT_IMXCOMPOSITOR_PAD_ROTATE, |
| G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); |
| g_object_class_install_property (gobject_class, PROP_IMXCOMPOSITOR_PAD_ALPHA, |
| g_param_spec_double ("alpha", "Alpha", "Alpha of the picture", 0.0, 1.0, |
| DEFAULT_IMXCOMPOSITOR_PAD_ALPHA, |
| G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); |
| g_object_class_install_property (gobject_class, |
| PROP_IMXCOMPOSITOR_PAD_KEEP_RATIO, |
| g_param_spec_boolean ("keep-ratio", "Keep Aspect Ratio", |
| "Keep the video aspect ratio after resize", |
| DEFAULT_IMXCOMPOSITOR_PAD_KEEP_RATIO, |
| G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); |
| |
| vaggpadclass->set_info = GST_DEBUG_FUNCPTR (gst_imxcompositor_pad_set_info); |
| vaggpadclass->prepare_frame = |
| GST_DEBUG_FUNCPTR (gst_imxcompositor_pad_prepare_frame); |
| vaggpadclass->clean_frame = |
| GST_DEBUG_FUNCPTR (gst_imxcompositor_pad_clean_frame); |
| } |
| |
| static void |
| gst_imxcompositor_pad_init (GstImxCompositorPad * compo_pad) |
| { |
| compo_pad->xpos = DEFAULT_IMXCOMPOSITOR_PAD_XPOS; |
| compo_pad->ypos = DEFAULT_IMXCOMPOSITOR_PAD_YPOS; |
| compo_pad->width = DEFAULT_IMXCOMPOSITOR_PAD_WIDTH; |
| compo_pad->height = DEFAULT_IMXCOMPOSITOR_PAD_HEIGHT; |
| compo_pad->rotate = DEFAULT_IMXCOMPOSITOR_PAD_ROTATE; |
| compo_pad->alpha = DEFAULT_IMXCOMPOSITOR_PAD_ALPHA; |
| compo_pad->keep_ratio = DEFAULT_IMXCOMPOSITOR_PAD_KEEP_RATIO; |
| compo_pad->sink_pool = NULL; |
| compo_pad->sink_tmp_buf = NULL; |
| compo_pad->sink_tmp_buf_size = 0; |
| memset(&compo_pad->align, 0, sizeof(GstVideoAlignment)); |
| } |