ext/divx/gstdivxenc.c: remove bogus gst_caps_is_fixed() test
[platform/upstream/gstreamer.git] / gst / debug / efence.c
1 /*
2  * GStreamer
3  * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
4  * Copyright (C) 2002 David A. Schleef <ds@schleef.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <gst/gst.h>
26
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/mman.h>
30
31 #include "efence.h"
32
33 #ifndef MAP_ANONYMOUS
34 #define MAP_ANONYMOUS MAP_ANON
35 #endif
36
37 static GstElementDetails plugin_details = {
38   "Electric Fence",
39   "Testing/EFence",
40   "This element converts a stream of normal GStreamer buffers into a "
41 "stream of buffers that are allocated in such a way that out-of-bounds "
42 "access to data in the buffer is more likely to cause segmentation "
43 "faults.  This allocation method is very similar to the debugging tool "
44 "\"Electric Fence\".",
45   "David A. Schleef <ds@schleef.org>",
46 };
47
48 /* Filter signals and args */
49 enum {
50   /* FILL ME */
51   LAST_SIGNAL
52 };
53
54 enum {
55   ARG_0,
56   ARG_FENCE_TOP
57 };
58
59 static GstStaticPadTemplate gst_efence_sink_factory =
60 GST_STATIC_PAD_TEMPLATE (
61   "sink",
62   GST_PAD_SINK,
63   GST_PAD_ALWAYS,
64   GST_STATIC_CAPS_ANY
65 );
66
67 static GstStaticPadTemplate gst_efence_src_factory =
68 GST_STATIC_PAD_TEMPLATE (
69   "src",
70   GST_PAD_SRC,
71   GST_PAD_ALWAYS,
72   GST_STATIC_CAPS_ANY
73 );
74
75 static void     gst_efence_base_init    (gpointer g_class);
76 static void     gst_efence_class_init   (GstEFenceClass *klass);
77 static void     gst_efence_init (GstEFence *filter);
78
79 static void     gst_efence_set_property(GObject *object, guint prop_id,
80                                                  const GValue *value,
81                                                  GParamSpec *pspec);
82 static void     gst_efence_get_property(GObject *object, guint prop_id,
83                                                  GValue *value,
84                                                  GParamSpec *pspec);
85
86 static void     gst_efence_chain        (GstPad *pad, GstData *_data);
87
88 static GstElementClass *parent_class = NULL;
89
90 typedef struct _GstFencedBuffer GstFencedBuffer;
91 struct _GstFencedBuffer {
92   GstBuffer buffer;
93   void *region;
94   unsigned int length;
95 };
96
97 void gst_fenced_buffer_default_free (GstBuffer *buffer);
98 GstBuffer* gst_fenced_buffer_default_copy (GstBuffer *buffer);
99 void *gst_fenced_buffer_alloc(GstBuffer *buffer, unsigned int length,
100     gboolean fence_top);
101
102 GstBuffer *gst_fenced_buffer_new(void);
103
104 GType
105 gst_gst_efence_get_type (void)
106 {
107   static GType plugin_type = 0;
108
109   if (!plugin_type)
110   {
111     static const GTypeInfo plugin_info =
112     {
113       sizeof (GstEFenceClass),
114       gst_efence_base_init,
115       NULL,
116       (GClassInitFunc) gst_efence_class_init,
117       NULL,
118       NULL,
119       sizeof (GstEFence),
120       0,
121       (GInstanceInitFunc) gst_efence_init,
122     };
123     plugin_type = g_type_register_static (GST_TYPE_ELEMENT,
124                                           "GstEFence",
125                                           &plugin_info, 0);
126   }
127   return plugin_type;
128 }
129
130 static void
131 gst_efence_base_init (gpointer g_class)
132 {
133   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
134
135   gst_element_class_add_pad_template (element_class,
136       gst_static_pad_template_get(&gst_efence_sink_factory));
137   gst_element_class_add_pad_template (element_class,
138       gst_static_pad_template_get(&gst_efence_src_factory));
139   gst_element_class_set_details (element_class, &plugin_details);
140 }
141
142 /* initialize the plugin's class */
143 static void
144 gst_efence_class_init (GstEFenceClass *klass)
145 {
146   GObjectClass *gobject_class;
147   GstElementClass *gstelement_class;
148
149   gobject_class = (GObjectClass*) klass;
150   gstelement_class = (GstElementClass*) klass;
151
152   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
153
154   g_object_class_install_property (gobject_class, ARG_FENCE_TOP,
155     g_param_spec_boolean ("fence_top", "Fence Top", "Align buffers with top of fenced region",
156                           TRUE, G_PARAM_READWRITE));
157
158   gobject_class->set_property = gst_efence_set_property;
159   gobject_class->get_property = gst_efence_get_property;
160 }
161
162 /* initialize the new element
163  * instantiate pads and add them to element
164  * set functions
165  * initialize structure
166  */
167 static void
168 gst_efence_init (GstEFence *filter)
169 {
170   filter->sinkpad = gst_pad_new_from_template (
171       gst_static_pad_template_get(&gst_efence_sink_factory), "sink");
172   gst_pad_set_link_function (filter->sinkpad, gst_pad_proxy_pad_link);
173   filter->srcpad = gst_pad_new_from_template (
174       gst_static_pad_template_get(&gst_efence_src_factory), "src");
175   gst_pad_set_link_function (filter->srcpad, gst_pad_proxy_pad_link);
176
177   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
178   gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
179   gst_pad_set_chain_function (filter->sinkpad, gst_efence_chain);
180
181   filter->fence_top = TRUE;
182 }
183
184 /* chain function
185  * this function does the actual processing
186  */
187
188 static void
189 gst_efence_chain (GstPad *pad, GstData *_data)
190 {
191   GstBuffer *buffer = GST_BUFFER (_data);
192   GstEFence *efence;
193   GstBuffer *copy;
194   void *ptr;
195
196   GST_DEBUG ("gst_efence_chain");
197
198   g_return_if_fail (GST_IS_PAD (pad));
199   g_return_if_fail (buffer != NULL);
200
201   efence = GST_EFENCE (GST_OBJECT_PARENT (pad));
202   g_return_if_fail (GST_IS_EFENCE (efence));
203
204   copy = gst_fenced_buffer_new();
205
206   ptr = gst_fenced_buffer_alloc(copy, GST_BUFFER_SIZE(buffer),
207       efence->fence_top);
208   memcpy(ptr, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer));
209
210   GST_BUFFER_DATA (copy)         = ptr;
211   GST_BUFFER_SIZE (copy)         = GST_BUFFER_SIZE (buffer);
212   GST_BUFFER_MAXSIZE (copy)      = GST_BUFFER_SIZE (buffer);
213   GST_BUFFER_TIMESTAMP (copy)    = GST_BUFFER_TIMESTAMP (buffer);
214   GST_BUFFER_DURATION (copy)     = GST_BUFFER_DURATION (buffer);
215   GST_BUFFER_OFFSET (copy)       = GST_BUFFER_OFFSET (buffer);
216   GST_BUFFER_FREE_DATA_FUNC (copy) = NULL;
217   GST_BUFFER_PRIVATE (copy)      = NULL;
218
219   gst_buffer_unref(buffer);
220   gst_pad_push (efence->srcpad, GST_DATA (copy));
221 }
222
223 static void
224 gst_efence_set_property (GObject *object, guint prop_id,
225                                   const GValue *value, GParamSpec *pspec)
226 {
227   GstEFence *filter;
228
229   g_return_if_fail (GST_IS_EFENCE (object));
230   filter = GST_EFENCE (object);
231
232   switch (prop_id)
233   {
234   case ARG_FENCE_TOP:
235     filter->fence_top = g_value_get_boolean (value);
236     break;
237   default:
238     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
239     break;
240   }
241 }
242
243 static void
244 gst_efence_get_property (GObject *object, guint prop_id,
245                                   GValue *value, GParamSpec *pspec)
246 {
247   GstEFence *filter;
248
249   g_return_if_fail (GST_IS_EFENCE (object));
250   filter = GST_EFENCE (object);
251
252   switch (prop_id) {
253   case ARG_FENCE_TOP:
254     g_value_set_boolean (value, filter->fence_top);
255     break;
256   default:
257     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
258     break;
259   }
260 }
261
262 /* entry point to initialize the plug-in
263  * initialize the plug-in itself
264  * register the element factories and pad templates
265  * register the features
266  */
267 static gboolean
268 plugin_init (GstPlugin *plugin)
269 {
270   if (!gst_element_register (plugin, "efence", GST_RANK_NONE, GST_TYPE_EFENCE))
271     return FALSE;
272   
273   /* plugin initialisation succeeded */
274   return TRUE;
275 }
276
277 GST_PLUGIN_DEFINE (
278   GST_VERSION_MAJOR,
279   GST_VERSION_MINOR,
280   "efence",
281   "This element converts a stream of normal GStreamer buffers into a "
282   "stream of buffers that are allocated in such a way that out-of-bounds "
283   "access to data in the buffer is more likely to cause segmentation "
284   "faults.  This allocation method is very similar to the debugging tool "
285   "\"Electric Fence\".",
286   plugin_init,
287   VERSION,
288   "LGPL",
289   GST_PACKAGE,
290   GST_ORIGIN)
291
292 GstBuffer *gst_fenced_buffer_new(void)
293 {
294   GstBuffer *newbuf;
295
296   newbuf = (GstBuffer *) g_new0(GstFencedBuffer,1);
297
298   gst_data_init (GST_DATA (newbuf), _gst_buffer_type, 0,
299                   (GstDataFreeFunction) gst_fenced_buffer_default_free,
300                   (GstDataCopyFunction) gst_fenced_buffer_default_copy);
301
302   GST_BUFFER_DATA (newbuf)         = NULL;
303   GST_BUFFER_SIZE (newbuf)         = 0;
304   GST_BUFFER_MAXSIZE (newbuf)      = GST_BUFFER_MAXSIZE_NONE;
305   GST_BUFFER_TIMESTAMP (newbuf)    = GST_CLOCK_TIME_NONE;
306   GST_BUFFER_DURATION (newbuf)     = GST_CLOCK_TIME_NONE;
307   GST_BUFFER_OFFSET (newbuf)       = GST_BUFFER_OFFSET_NONE;
308   GST_BUFFER_FREE_DATA_FUNC (newbuf) = NULL;
309   GST_BUFFER_PRIVATE (newbuf)      = NULL;
310
311   GST_DEBUG ("new buffer=%p", newbuf);
312
313   return newbuf;
314 }
315
316 void gst_fenced_buffer_default_free (GstBuffer *buffer)
317 {
318   GstFencedBuffer *fenced_buffer;
319
320   GST_DEBUG ("free buffer=%p", buffer);
321
322   g_return_if_fail (buffer != NULL);
323
324   fenced_buffer = (GstFencedBuffer *) buffer;
325
326   /* free our data */
327   if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_DONTFREE) &&
328       GST_BUFFER_DATA (buffer)) {
329     GST_DEBUG ("free region %p %d", fenced_buffer->region,
330         fenced_buffer->length);
331     munmap(fenced_buffer->region, fenced_buffer->length);
332   }else{
333     GST_DEBUG ("not freeing region %p %d %p", fenced_buffer->region,
334         GST_BUFFER_FLAGS(buffer), GST_BUFFER_DATA(buffer));
335   }
336
337   /* set to safe values */
338   GST_BUFFER_DATA (buffer) = NULL;
339   GST_BUFFER_SIZE (buffer) = 0;
340   
341   g_free (buffer);
342 }
343
344 GstBuffer* gst_fenced_buffer_default_copy (GstBuffer *buffer)
345
346   GstBuffer *copy;
347   void *ptr;
348   
349   g_return_val_if_fail (buffer != NULL, NULL);
350   
351   /* create a fresh new buffer */
352   copy = (GstBuffer *) g_new0(GstFencedBuffer,1);
353   
354   gst_data_init (GST_DATA (copy), _gst_buffer_type, 0,
355                   (GstDataFreeFunction) gst_fenced_buffer_default_free,
356                   (GstDataCopyFunction) gst_fenced_buffer_default_copy);
357   
358   /* we simply copy everything from our parent */
359   ptr = gst_fenced_buffer_alloc(copy, GST_BUFFER_SIZE(buffer), TRUE);
360   memcpy(ptr, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer));
361
362   GST_BUFFER_SIZE (copy)         = GST_BUFFER_SIZE (buffer);
363   GST_BUFFER_MAXSIZE (copy)      = GST_BUFFER_SIZE (buffer);
364   GST_BUFFER_TIMESTAMP (copy)    = GST_BUFFER_TIMESTAMP (buffer);
365   GST_BUFFER_DURATION (copy)     = GST_BUFFER_DURATION (buffer);
366   GST_BUFFER_OFFSET (copy)       = GST_BUFFER_OFFSET (buffer);
367   GST_BUFFER_FREE_DATA_FUNC (copy) = NULL;
368   GST_BUFFER_PRIVATE (copy)      = NULL;
369   
370   return copy;
371 }
372
373 void *gst_fenced_buffer_alloc(GstBuffer *buffer, unsigned int length,
374     gboolean fence_top)
375 {
376   int alloc_size;
377   void *region;
378   GstFencedBuffer *fenced_buffer = (GstFencedBuffer *) buffer;
379   int page_size;
380
381   GST_DEBUG ("buffer=%p length=%d fence_top=%d", buffer, length, fence_top);
382
383   if(length==0)return NULL;
384
385 #ifdef _SC_PAGESIZE
386   page_size = sysconf(_SC_PAGESIZE);
387 #else
388   page_size = getpagesize();
389 #endif
390
391   alloc_size = ((length - 1) & ~(page_size - 1)) + page_size;
392   alloc_size += 2*page_size;
393
394   region = mmap(NULL, alloc_size, PROT_READ|PROT_WRITE,
395       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
396   if(region == MAP_FAILED){
397     g_warning("mmap failed");
398     return NULL;
399   }
400
401   munmap(region, page_size);
402   munmap(region + alloc_size - page_size, page_size);
403
404   fenced_buffer->region = region;
405   fenced_buffer->length = alloc_size;
406
407   GST_DEBUG ("new region %p %d", fenced_buffer->region,
408       fenced_buffer->length);
409   
410   if(fence_top){
411     int offset;
412     /* Align to top of region, but force alignment to 4 bytes */
413     offset = alloc_size - page_size - length;
414     offset &= ~0x3;
415     return region + offset;
416   }else{
417     return region + page_size;
418   }
419 }
420