static GstFlowReturn gst_video_filter_transform (GstBaseTransform * trans, GstBuffer * inbuf, GstBuffer * outbuf) { GstFlowReturn res; GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans); GstVideoFilterClass *fclass; if (G_UNLIKELY (!filter->negotiated)) goto unknown_format; fclass = GST_VIDEO_FILTER_GET_CLASS (filter); if (fclass->transform_frame) { GstVideoFrame in_frame, out_frame; if (!gst_video_frame_map (&in_frame, &filter->in_info, inbuf, GST_MAP_READ)) goto invalid_buffer; if (!gst_video_frame_map (&out_frame, &filter->out_info, outbuf, GST_MAP_WRITE)) goto invalid_buffer; /* GstVideoFrame has another reference, so the buffer looks unwriteable, * meaning that we can't attach any metas or anything to it. Other * map() functions like gst_buffer_map() don't get another reference * of the buffer and expect the buffer reference to be kept until * the buffer is unmapped again. */ gst_buffer_unref (inbuf); gst_buffer_unref (outbuf); res = fclass->transform_frame (filter, &in_frame, &out_frame); gst_buffer_ref (inbuf); gst_buffer_ref (outbuf); gst_video_frame_unmap (&out_frame); gst_video_frame_unmap (&in_frame); } else { GST_DEBUG_OBJECT (trans, "no transform_frame vmethod"); res = GST_FLOW_OK; } return res; /* ERRORS */ unknown_format: { GST_ELEMENT_ERROR (filter, CORE, NOT_IMPLEMENTED, (NULL), ("unknown format")); return GST_FLOW_NOT_NEGOTIATED; } invalid_buffer: { GST_ELEMENT_WARNING (filter, CORE, NOT_IMPLEMENTED, (NULL), ("invalid video buffer received")); return GST_FLOW_OK; } }
static GstFlowReturn gst_video_filter_transform_ip (GstBaseTransform * trans, GstBuffer * buf) { GstFlowReturn res; GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans); GstVideoFilterClass *fclass; if (G_UNLIKELY (!filter->negotiated)) goto unknown_format; fclass = GST_VIDEO_FILTER_GET_CLASS (filter); if (fclass->transform_frame_ip) { GstVideoFrame frame; GstMapFlags flags; flags = GST_MAP_READ; if (!gst_base_transform_is_passthrough (trans)) flags |= GST_MAP_WRITE; if (!gst_video_frame_map (&frame, &filter->in_info, buf, flags)) goto invalid_buffer; res = fclass->transform_frame_ip (filter, &frame); gst_video_frame_unmap (&frame); } else { GST_DEBUG_OBJECT (trans, "no transform_frame_ip vmethod"); res = GST_FLOW_OK; } return res; /* ERRORS */ unknown_format: { GST_ELEMENT_ERROR (filter, CORE, NOT_IMPLEMENTED, (NULL), ("unknown format")); return GST_FLOW_NOT_NEGOTIATED; } invalid_buffer: { GST_ELEMENT_WARNING (filter, CORE, NOT_IMPLEMENTED, (NULL), ("invalid video buffer received")); return GST_FLOW_OK; } }
static GstFlowReturn gst_video_filter_transform (GstBaseTransform * trans, GstBuffer * inbuf, GstBuffer * outbuf) { GstFlowReturn res; GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans); GstVideoFilterClass *fclass; if (G_UNLIKELY (!filter->negotiated)) goto unknown_format; fclass = GST_VIDEO_FILTER_GET_CLASS (filter); if (fclass->transform_frame) { GstVideoFrame in_frame, out_frame; if (!gst_video_frame_map (&in_frame, &filter->in_info, inbuf, GST_MAP_READ)) goto invalid_buffer; if (!gst_video_frame_map (&out_frame, &filter->out_info, outbuf, GST_MAP_WRITE)) goto invalid_buffer; res = fclass->transform_frame (filter, &in_frame, &out_frame); gst_video_frame_unmap (&out_frame); gst_video_frame_unmap (&in_frame); } else { GST_DEBUG_OBJECT (trans, "no transform_frame vmethod"); res = GST_FLOW_OK; } return res; /* ERRORS */ unknown_format: { GST_ELEMENT_ERROR (filter, CORE, NOT_IMPLEMENTED, (NULL), ("unknown format")); return GST_FLOW_NOT_NEGOTIATED; } invalid_buffer: { GST_ELEMENT_WARNING (filter, CORE, NOT_IMPLEMENTED, (NULL), ("invalid video buffer received")); return GST_FLOW_OK; } }
static gboolean gst_video_filter_set_caps (GstBaseTransform * trans, GstCaps * incaps, GstCaps * outcaps) { GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans); GstVideoFilterClass *fclass; GstVideoInfo in_info, out_info; gboolean res; /* input caps */ if (!gst_video_info_from_caps (&in_info, incaps)) goto invalid_caps; /* output caps */ if (!gst_video_info_from_caps (&out_info, outcaps)) goto invalid_caps; fclass = GST_VIDEO_FILTER_GET_CLASS (filter); if (fclass->set_info) res = fclass->set_info (filter, incaps, &in_info, outcaps, &out_info); else res = TRUE; if (res) { filter->in_info = in_info; filter->out_info = out_info; if (fclass->transform_frame == NULL) gst_base_transform_set_in_place (trans, TRUE); if (fclass->transform_frame_ip == NULL) GST_BASE_TRANSFORM_CLASS (fclass)->transform_ip_on_passthrough = FALSE; } filter->negotiated = res; return res; /* ERRORS */ invalid_caps: { GST_ERROR_OBJECT (filter, "invalid caps"); filter->negotiated = FALSE; return FALSE; } }
static gboolean gst_video_scale_src_event (GstBaseTransform * trans, GstEvent * event) { GstVideoScale *videoscale = GST_VIDEO_SCALE_CAST (trans); GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans); gboolean ret; gdouble a; GstStructure *structure; GST_DEBUG_OBJECT (videoscale, "handling %s event", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NAVIGATION: if (filter->in_info.width != filter->out_info.width || filter->in_info.height != filter->out_info.height) { event = GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event))); structure = (GstStructure *) gst_event_get_structure (event); if (gst_structure_get_double (structure, "pointer_x", &a)) { gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, a * filter->in_info.width / filter->out_info.width, NULL); } if (gst_structure_get_double (structure, "pointer_y", &a)) { gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, a * filter->in_info.height / filter->out_info.height, NULL); } } break; default: break; } ret = GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event); return ret; }
/* Answer the allocation query downstream. */ static gboolean gst_video_filter_propose_allocation (GstBaseTransform * trans, GstQuery * decide_query, GstQuery * query) { GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans); GstVideoInfo info; GstBufferPool *pool; GstCaps *caps; guint size; if (!GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans, decide_query, query)) return FALSE; /* passthrough, we're done */ if (decide_query == NULL) return TRUE; gst_query_parse_allocation (query, &caps, NULL); if (caps == NULL) return FALSE; if (!gst_video_info_from_caps (&info, caps)) return FALSE; size = GST_VIDEO_INFO_SIZE (&info); if (gst_query_get_n_allocation_pools (query) == 0) { GstStructure *structure; GstAllocator *allocator = NULL; GstAllocationParams params = { 0, 15, 0, 0, }; if (gst_query_get_n_allocation_params (query) > 0) gst_query_parse_nth_allocation_param (query, 0, &allocator, ¶ms); else gst_query_add_allocation_param (query, allocator, ¶ms); pool = gst_video_buffer_pool_new (); structure = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (structure, caps, size, 0, 0); gst_buffer_pool_config_set_allocator (structure, allocator, ¶ms); if (allocator) gst_object_unref (allocator); if (!gst_buffer_pool_set_config (pool, structure)) goto config_failed; gst_query_add_allocation_pool (query, pool, size, 0, 0); gst_object_unref (pool); gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); } return TRUE; /* ERRORS */ config_failed: { GST_ERROR_OBJECT (filter, "failed to set config"); gst_object_unref (pool); return FALSE; } }