2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David Schleef <ds@schleef.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
22 * SECTION:gstvideofilter
23 * @title: GstVideoFilter
24 * @short_description: Base class for video filters
26 * Provides useful functions and a base class for video filters.
28 * The videofilter will by default enable QoS on the parent GstBaseTransform
29 * to implement frame dropping.
37 #include "gstvideofilter.h"
39 #include <gst/video/video.h>
40 #include <gst/video/gstvideometa.h>
41 #include <gst/video/gstvideopool.h>
43 GST_DEBUG_CATEGORY_STATIC (gst_video_filter_debug);
44 #define GST_CAT_DEFAULT gst_video_filter_debug
46 #define gst_video_filter_parent_class parent_class
47 G_DEFINE_ABSTRACT_TYPE (GstVideoFilter, gst_video_filter,
48 GST_TYPE_BASE_TRANSFORM);
50 /* cached quark to avoid contention on the global quark table lock */
51 #define META_TAG_VIDEO meta_tag_video_quark
52 static GQuark meta_tag_video_quark;
54 /* Answer the allocation query downstream. */
56 gst_video_filter_propose_allocation (GstBaseTransform * trans,
57 GstQuery * decide_query, GstQuery * query)
59 GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans);
65 if (!GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans,
69 /* passthrough, we're done */
70 if (decide_query == NULL)
73 gst_query_parse_allocation (query, &caps, NULL);
78 if (!gst_video_info_from_caps (&info, caps))
81 size = GST_VIDEO_INFO_SIZE (&info);
83 if (gst_query_get_n_allocation_pools (query) == 0) {
84 GstStructure *structure;
85 GstAllocator *allocator = NULL;
86 GstAllocationParams params = { 0, 15, 0, 0, };
88 if (gst_query_get_n_allocation_params (query) > 0)
89 gst_query_parse_nth_allocation_param (query, 0, &allocator, ¶ms);
91 gst_query_add_allocation_param (query, allocator, ¶ms);
93 pool = gst_video_buffer_pool_new ();
95 structure = gst_buffer_pool_get_config (pool);
96 gst_buffer_pool_config_set_params (structure, caps, size, 0, 0);
97 gst_buffer_pool_config_set_allocator (structure, allocator, ¶ms);
100 gst_object_unref (allocator);
102 if (!gst_buffer_pool_set_config (pool, structure))
105 gst_query_add_allocation_pool (query, pool, size, 0, 0);
106 gst_object_unref (pool);
107 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
115 GST_ERROR_OBJECT (filter, "failed to set config");
116 gst_object_unref (pool);
121 /* configure the allocation query that was answered downstream, we can configure
122 * some properties on it. Only called when not in passthrough mode. */
124 gst_video_filter_decide_allocation (GstBaseTransform * trans, GstQuery * query)
126 GstBufferPool *pool = NULL;
127 GstStructure *config;
128 guint min, max, size;
129 gboolean update_pool;
130 GstCaps *outcaps = NULL;
132 if (gst_query_get_n_allocation_pools (query) > 0) {
133 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
136 gst_query_parse_allocation (query, &outcaps, NULL);
142 gst_query_parse_allocation (query, &outcaps, NULL);
143 gst_video_info_init (&vinfo);
144 gst_video_info_from_caps (&vinfo, outcaps);
151 pool = gst_video_buffer_pool_new ();
153 config = gst_buffer_pool_get_config (pool);
154 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
156 gst_buffer_pool_config_set_params (config, outcaps, size, 0, 0);
157 gst_buffer_pool_set_config (pool, config);
160 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
162 gst_query_add_allocation_pool (query, pool, size, min, max);
164 gst_object_unref (pool);
166 return GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans,
171 /* our output size only depends on the caps, not on the input caps */
173 gst_video_filter_transform_size (GstBaseTransform * btrans,
174 GstPadDirection direction, GstCaps * caps, gsize size,
175 GstCaps * othercaps, gsize * othersize)
182 ret = gst_video_info_from_caps (&info, othercaps);
184 *othersize = info.size;
190 gst_video_filter_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
195 if (!gst_video_info_from_caps (&info, caps)) {
196 GST_WARNING_OBJECT (btrans, "Failed to parse caps %" GST_PTR_FORMAT, caps);
202 GST_DEBUG_OBJECT (btrans, "Returning size %" G_GSIZE_FORMAT " bytes"
203 "for caps %" GST_PTR_FORMAT, *size, caps);
209 gst_video_filter_set_caps (GstBaseTransform * trans, GstCaps * incaps,
212 GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans);
213 GstVideoFilterClass *fclass;
214 GstVideoInfo in_info, out_info;
218 if (!gst_video_info_from_caps (&in_info, incaps))
222 if (!gst_video_info_from_caps (&out_info, outcaps))
225 fclass = GST_VIDEO_FILTER_GET_CLASS (filter);
226 if (fclass->set_info)
227 res = fclass->set_info (filter, incaps, &in_info, outcaps, &out_info);
232 filter->in_info = in_info;
233 filter->out_info = out_info;
234 if (fclass->transform_frame == NULL)
235 gst_base_transform_set_in_place (trans, TRUE);
236 if (fclass->transform_frame_ip == NULL)
237 GST_BASE_TRANSFORM_CLASS (fclass)->transform_ip_on_passthrough = FALSE;
239 filter->negotiated = res;
246 GST_ERROR_OBJECT (filter, "invalid caps");
247 filter->negotiated = FALSE;
253 gst_video_filter_transform (GstBaseTransform * trans, GstBuffer * inbuf,
257 GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans);
258 GstVideoFilterClass *fclass;
260 GstMapFlags map_flags;
263 if (G_UNLIKELY (!filter->negotiated))
266 fclass = GST_VIDEO_FILTER_GET_CLASS (filter);
267 if (fclass->transform_frame) {
268 GstVideoFrame in_frame, out_frame;
271 map_flags = GST_MAP_READ;
272 if (filter->in_info.finfo->format != GST_VIDEO_FORMAT_SN12 &&
273 filter->in_info.finfo->format != GST_VIDEO_FORMAT_SR32)
274 map_flags |= GST_VIDEO_FRAME_MAP_FLAG_NO_REF;
276 GST_LOG_OBJECT (trans, "IN format %d, flags 0x%x",
277 filter->in_info.finfo->format, map_flags);
279 if (!gst_video_frame_map (&in_frame, &filter->in_info, inbuf, map_flags))
282 map_flags = GST_MAP_WRITE;
283 if (filter->out_info.finfo->format != GST_VIDEO_FORMAT_SN12 &&
284 filter->out_info.finfo->format != GST_VIDEO_FORMAT_SR32)
285 map_flags |= GST_VIDEO_FRAME_MAP_FLAG_NO_REF;
287 GST_LOG_OBJECT (trans, "OUT format %d, flags 0x%x",
288 filter->out_info.finfo->format, map_flags);
290 if (!gst_video_frame_map (&out_frame, &filter->out_info, outbuf, map_flags)) {
291 gst_video_frame_unmap (&in_frame);
295 if (!gst_video_frame_map (&in_frame, &filter->in_info, inbuf,
296 GST_MAP_READ | GST_VIDEO_FRAME_MAP_FLAG_NO_REF))
299 if (!gst_video_frame_map (&out_frame, &filter->out_info, outbuf,
300 GST_MAP_WRITE | GST_VIDEO_FRAME_MAP_FLAG_NO_REF)) {
301 gst_video_frame_unmap (&in_frame);
305 res = fclass->transform_frame (filter, &in_frame, &out_frame);
307 gst_video_frame_unmap (&out_frame);
308 gst_video_frame_unmap (&in_frame);
310 GST_DEBUG_OBJECT (trans, "no transform_frame vmethod");
319 GST_ELEMENT_ERROR (filter, CORE, NOT_IMPLEMENTED, (NULL),
321 return GST_FLOW_NOT_NEGOTIATED;
325 GST_ELEMENT_WARNING (filter, CORE, NOT_IMPLEMENTED, (NULL),
326 ("invalid video buffer received"));
332 gst_video_filter_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
335 GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans);
336 GstVideoFilterClass *fclass;
338 if (G_UNLIKELY (!filter->negotiated))
341 fclass = GST_VIDEO_FILTER_GET_CLASS (filter);
342 if (fclass->transform_frame_ip) {
346 flags = GST_MAP_READ | GST_VIDEO_FRAME_MAP_FLAG_NO_REF;
348 if (!gst_base_transform_is_passthrough (trans))
349 flags |= GST_MAP_WRITE;
351 if (!gst_video_frame_map (&frame, &filter->in_info, buf, flags))
354 res = fclass->transform_frame_ip (filter, &frame);
356 gst_video_frame_unmap (&frame);
358 GST_DEBUG_OBJECT (trans, "no transform_frame_ip vmethod");
367 GST_ELEMENT_ERROR (filter, CORE, NOT_IMPLEMENTED, (NULL),
369 return GST_FLOW_NOT_NEGOTIATED;
373 GST_ELEMENT_WARNING (filter, CORE, NOT_IMPLEMENTED, (NULL),
374 ("invalid video buffer received"));
380 gst_video_filter_transform_meta (GstBaseTransform * trans, GstBuffer * outbuf,
381 GstMeta * meta, GstBuffer * inbuf)
383 const GstMetaInfo *info = meta->info;
384 const gchar *const *tags;
386 tags = gst_meta_api_type_get_tags (info->api);
388 if (!tags || (g_strv_length ((gchar **) tags) == 1
389 && gst_meta_api_type_has_tag (info->api, META_TAG_VIDEO)))
392 return GST_BASE_TRANSFORM_CLASS (parent_class)->transform_meta (trans, outbuf,
397 gst_video_filter_class_init (GstVideoFilterClass * g_class)
399 GstBaseTransformClass *trans_class;
400 GstVideoFilterClass *klass;
402 klass = (GstVideoFilterClass *) g_class;
403 trans_class = (GstBaseTransformClass *) klass;
405 trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_video_filter_set_caps);
406 trans_class->propose_allocation =
407 GST_DEBUG_FUNCPTR (gst_video_filter_propose_allocation);
408 trans_class->decide_allocation =
409 GST_DEBUG_FUNCPTR (gst_video_filter_decide_allocation);
410 trans_class->transform_size =
411 GST_DEBUG_FUNCPTR (gst_video_filter_transform_size);
412 trans_class->get_unit_size =
413 GST_DEBUG_FUNCPTR (gst_video_filter_get_unit_size);
414 trans_class->transform = GST_DEBUG_FUNCPTR (gst_video_filter_transform);
415 trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_video_filter_transform_ip);
416 trans_class->transform_meta =
417 GST_DEBUG_FUNCPTR (gst_video_filter_transform_meta);
419 GST_DEBUG_CATEGORY_INIT (gst_video_filter_debug, "videofilter", 0,
422 meta_tag_video_quark = g_quark_from_static_string (GST_META_TAG_VIDEO_STR);
426 gst_video_filter_init (GstVideoFilter * instance)
428 GstVideoFilter *videofilter = GST_VIDEO_FILTER (instance);
430 GST_DEBUG_OBJECT (videofilter, "gst_video_filter_init");
432 videofilter->negotiated = FALSE;
434 gst_base_transform_set_qos_enabled (GST_BASE_TRANSFORM (videofilter), TRUE);