• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2003> David Schleef <ds@schleef.org>
4  *
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.
9  *
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.
14  *
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.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "gstnavigationtest.h"
26 #include <string.h>
27 #include <math.h>
28 
29 #include <gst/video/video.h>
30 
31 #ifdef _MSC_VER
32 #define rint(x) (floor((x)+0.5))
33 #endif
34 
35 GST_DEBUG_CATEGORY_STATIC (navigationtest_debug);
36 #define GST_CAT_DEFAULT navigationtest_debug
37 
38 static GstStaticPadTemplate gst_navigationtest_src_template =
39 GST_STATIC_PAD_TEMPLATE ("src",
40     GST_PAD_SRC,
41     GST_PAD_ALWAYS,
42     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420"))
43     );
44 
45 static GstStaticPadTemplate gst_navigationtest_sink_template =
46 GST_STATIC_PAD_TEMPLATE ("sink",
47     GST_PAD_SINK,
48     GST_PAD_ALWAYS,
49     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420"))
50     );
51 
52 #define gst_navigationtest_parent_class parent_class
53 G_DEFINE_TYPE (GstNavigationtest, gst_navigationtest, GST_TYPE_VIDEO_FILTER);
54 GST_ELEMENT_REGISTER_DEFINE (navigationtest, "navigationtest", GST_RANK_NONE,
55     GST_TYPE_NAVIGATIONTEST);
56 
57 static gboolean
gst_navigationtest_src_event(GstBaseTransform * trans,GstEvent * event)58 gst_navigationtest_src_event (GstBaseTransform * trans, GstEvent * event)
59 {
60   GstVideoInfo *info;
61   GstNavigationtest *navtest;
62   const gchar *type;
63 
64   navtest = GST_NAVIGATIONTEST (trans);
65 
66   info = &GST_VIDEO_FILTER (trans)->in_info;
67 
68   switch (GST_EVENT_TYPE (event)) {
69     case GST_EVENT_NAVIGATION:
70     {
71       const GstStructure *s = gst_event_get_structure (event);
72       gint fps_n, fps_d;
73 
74       fps_n = GST_VIDEO_INFO_FPS_N (info);
75       fps_d = GST_VIDEO_INFO_FPS_D (info);
76 
77       type = gst_structure_get_string (s, "event");
78       if (g_str_equal (type, "mouse-move")) {
79         gst_structure_get_double (s, "pointer_x", &navtest->x);
80         gst_structure_get_double (s, "pointer_y", &navtest->y);
81       } else if (g_str_equal (type, "mouse-button-press")) {
82         ButtonClick *click = g_new (ButtonClick, 1);
83 
84         gst_structure_get_double (s, "pointer_x", &click->x);
85         gst_structure_get_double (s, "pointer_y", &click->y);
86         click->images_left = (fps_n + fps_d - 1) / fps_d;
87         /* green */
88         click->cy = 150;
89         click->cu = 46;
90         click->cv = 21;
91         navtest->clicks = g_slist_prepend (navtest->clicks, click);
92       } else if (g_str_equal (type, "mouse-button-release")) {
93         ButtonClick *click = g_new (ButtonClick, 1);
94 
95         gst_structure_get_double (s, "pointer_x", &click->x);
96         gst_structure_get_double (s, "pointer_y", &click->y);
97         click->images_left = (fps_n + fps_d - 1) / fps_d;
98         /* red */
99         click->cy = 76;
100         click->cu = 85;
101         click->cv = 255;
102         navtest->clicks = g_slist_prepend (navtest->clicks, click);
103       }
104       break;
105     }
106     default:
107       break;
108   }
109   return GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event);
110 }
111 
112 /* Useful macros */
113 #define GST_VIDEO_I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
114 #define GST_VIDEO_I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
115 #define GST_VIDEO_I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(GST_VIDEO_I420_Y_ROWSTRIDE(width)))/2)
116 
117 #define GST_VIDEO_I420_Y_OFFSET(w,h) (0)
118 #define GST_VIDEO_I420_U_OFFSET(w,h) (GST_VIDEO_I420_Y_OFFSET(w,h)+(GST_VIDEO_I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
119 #define GST_VIDEO_I420_V_OFFSET(w,h) (GST_VIDEO_I420_U_OFFSET(w,h)+(GST_VIDEO_I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
120 
121 #define GST_VIDEO_I420_SIZE(w,h)     (GST_VIDEO_I420_V_OFFSET(w,h)+(GST_VIDEO_I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
122 
123 static void
draw_box_planar411(GstVideoFrame * frame,int x,int y,guint8 colory,guint8 coloru,guint8 colorv)124 draw_box_planar411 (GstVideoFrame * frame, int x, int y,
125     guint8 colory, guint8 coloru, guint8 colorv)
126 {
127   gint width, height;
128   int x1, x2, y1, y2;
129   guint8 *d;
130   gint stride;
131 
132   width = GST_VIDEO_FRAME_WIDTH (frame);
133   height = GST_VIDEO_FRAME_HEIGHT (frame);
134 
135   if (x < 0 || y < 0 || x >= width || y >= height)
136     return;
137 
138   x1 = MAX (x - 5, 0);
139   x2 = MIN (x + 5, width);
140   y1 = MAX (y - 5, 0);
141   y2 = MIN (y + 5, height);
142 
143   d = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
144   stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
145 
146   for (y = y1; y < y2; y++) {
147     for (x = x1; x < x2; x++) {
148       d[y * stride + x] = colory;
149     }
150   }
151 
152   d = GST_VIDEO_FRAME_PLANE_DATA (frame, 1);
153   stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 1);
154 
155   x1 /= 2;
156   x2 /= 2;
157   y1 /= 2;
158   y2 /= 2;
159   for (y = y1; y < y2; y++) {
160     for (x = x1; x < x2; x++) {
161       d[y * stride + x] = coloru;
162     }
163   }
164 
165   d = GST_VIDEO_FRAME_PLANE_DATA (frame, 2);
166   stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 2);
167 
168   for (y = y1; y < y2; y++) {
169     for (x = x1; x < x2; x++) {
170       d[y * stride + x] = colorv;
171     }
172   }
173 }
174 
175 static GstFlowReturn
gst_navigationtest_transform_frame(GstVideoFilter * filter,GstVideoFrame * in_frame,GstVideoFrame * out_frame)176 gst_navigationtest_transform_frame (GstVideoFilter * filter,
177     GstVideoFrame * in_frame, GstVideoFrame * out_frame)
178 {
179   GstNavigationtest *navtest = GST_NAVIGATIONTEST (filter);
180   GSList *walk;
181 
182   gst_video_frame_copy (out_frame, in_frame);
183 
184   walk = navtest->clicks;
185   while (walk) {
186     ButtonClick *click = walk->data;
187 
188     walk = g_slist_next (walk);
189     draw_box_planar411 (out_frame,
190         rint (click->x), rint (click->y), click->cy, click->cu, click->cv);
191     if (--click->images_left < 1) {
192       navtest->clicks = g_slist_remove (navtest->clicks, click);
193       g_free (click);
194     }
195   }
196   draw_box_planar411 (out_frame,
197       rint (navtest->x), rint (navtest->y), 0, 128, 128);
198 
199   return GST_FLOW_OK;
200 }
201 
202 static GstStateChangeReturn
gst_navigationtest_change_state(GstElement * element,GstStateChange transition)203 gst_navigationtest_change_state (GstElement * element,
204     GstStateChange transition)
205 {
206   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
207   GstNavigationtest *navtest = GST_NAVIGATIONTEST (element);
208 
209   if (GST_ELEMENT_CLASS (parent_class)->change_state)
210     ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
211 
212   /* downwards state changes */
213   switch (transition) {
214     case GST_STATE_CHANGE_PAUSED_TO_READY:
215     {
216       g_slist_foreach (navtest->clicks, (GFunc) g_free, NULL);
217       g_slist_free (navtest->clicks);
218       navtest->clicks = NULL;
219       break;
220     }
221     default:
222       break;
223   }
224 
225   return ret;
226 }
227 
228 static void
gst_navigationtest_class_init(GstNavigationtestClass * klass)229 gst_navigationtest_class_init (GstNavigationtestClass * klass)
230 {
231   GstElementClass *element_class;
232   GstBaseTransformClass *trans_class;
233   GstVideoFilterClass *vfilter_class;
234 
235   element_class = (GstElementClass *) klass;
236   trans_class = (GstBaseTransformClass *) klass;
237   vfilter_class = (GstVideoFilterClass *) klass;
238 
239   element_class->change_state =
240       GST_DEBUG_FUNCPTR (gst_navigationtest_change_state);
241 
242   gst_element_class_set_static_metadata (element_class, "Video navigation test",
243       "Filter/Effect/Video",
244       "Handle navigation events showing a black square following mouse pointer",
245       "David Schleef <ds@schleef.org>");
246 
247   gst_element_class_add_static_pad_template (element_class,
248       &gst_navigationtest_sink_template);
249   gst_element_class_add_static_pad_template (element_class,
250       &gst_navigationtest_src_template);
251 
252   trans_class->src_event = GST_DEBUG_FUNCPTR (gst_navigationtest_src_event);
253 
254   vfilter_class->transform_frame =
255       GST_DEBUG_FUNCPTR (gst_navigationtest_transform_frame);
256 }
257 
258 static void
gst_navigationtest_init(GstNavigationtest * navtest)259 gst_navigationtest_init (GstNavigationtest * navtest)
260 {
261   navtest->x = -1;
262   navtest->y = -1;
263 }
264 
265 static gboolean
plugin_init(GstPlugin * plugin)266 plugin_init (GstPlugin * plugin)
267 {
268   GST_DEBUG_CATEGORY_INIT (navigationtest_debug, "navigationtest", 0,
269       "navigationtest");
270 
271   return GST_ELEMENT_REGISTER (navigationtest, plugin);
272 }
273 
274 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
275     GST_VERSION_MINOR,
276     navigationtest,
277     "Template for a video filter",
278     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
279