2 * Copyright (C) 2008 David Schleef <ds@entropywave.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 #define SCHRO_ENABLE_UNSTABLE_API
27 #include <gst/base/gstbasetransform.h>
28 #include <gst/video/video.h>
30 #include <schroedinger/schro.h>
31 #include <schroedinger/schrovirtframe.h>
32 #include <liboil/liboil.h>
34 #include <libpng/png.h>
35 #include "gstschroutils.h"
37 #define GST_TYPE_LOGOINSERT \
38 (gst_logoinsert_get_type())
39 #define GST_LOGOINSERT(obj) \
40 (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_LOGOINSERT,GstLogoinsert))
41 #define GST_LOGOINSERT_CLASS(klass) \
42 (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_LOGOINSERT,GstLogoinsertClass))
43 #define GST_IS_LOGOINSERT(obj) \
44 (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_LOGOINSERT))
45 #define GST_IS_LOGOINSERT_CLASS(obj) \
46 (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_LOGOINSERT))
48 typedef struct _GstLogoinsert GstLogoinsert
;
49 typedef struct _GstLogoinsertClass GstLogoinsertClass
;
53 GstBaseTransform base_transform
;
57 GstVideoFormat format
;
63 SchroFrame
*overlay_frame
;
64 SchroFrame
*ayuv_frame
;
65 SchroFrame
*alpha_frame
;
69 struct _GstLogoinsertClass
71 GstBaseTransformClass parent_class
;
76 /* GstLogoinsert signals and args */
89 GType
gst_logoinsert_get_type (void);
91 static void gst_logoinsert_base_init (gpointer g_class
);
92 static void gst_logoinsert_class_init (gpointer g_class
,
94 static void gst_logoinsert_init (GTypeInstance
* instance
, gpointer g_class
);
96 static void gst_logoinsert_set_property (GObject
* object
, guint prop_id
,
97 const GValue
* value
, GParamSpec
* pspec
);
98 static void gst_logoinsert_get_property (GObject
* object
, guint prop_id
,
99 GValue
* value
, GParamSpec
* pspec
);
101 static void gst_logoinsert_set_location (GstLogoinsert
*li
, const gchar
*location
);
103 static gboolean
gst_logoinsert_set_caps (GstBaseTransform
*base_transform
,
104 GstCaps
*incaps
, GstCaps
*outcaps
);
105 static GstFlowReturn
gst_logoinsert_transform_ip (GstBaseTransform
* base_transform
,
107 static SchroFrame
* schro_frame_new_from_png (void *data
, int size
);
108 static SchroFrame
* schro_virt_frame_extract_alpha_take (SchroFrame
*frame
);
109 static SchroFrame
* schro_frame_realize (SchroFrame
*frame
);
111 static GstStaticPadTemplate gst_logoinsert_sink_template
=
112 GST_STATIC_PAD_TEMPLATE ("sink",
115 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
118 static GstStaticPadTemplate gst_logoinsert_src_template
=
119 GST_STATIC_PAD_TEMPLATE ("src",
122 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{I420,YUY2,UYVY,AYUV}"))
126 gst_logoinsert_get_type (void)
128 static GType compress_type
= 0;
130 if (!compress_type
) {
131 static const GTypeInfo compress_info
= {
132 sizeof (GstLogoinsertClass
),
133 gst_logoinsert_base_init
,
135 gst_logoinsert_class_init
,
138 sizeof (GstLogoinsert
),
143 compress_type
= g_type_register_static (GST_TYPE_BASE_TRANSFORM
,
144 "GstLogoinsert", &compress_info
, 0);
146 return compress_type
;
151 gst_logoinsert_base_init (gpointer g_class
)
153 static GstElementDetails compress_details
=
154 GST_ELEMENT_DETAILS ("Video Filter Template",
155 "Filter/Effect/Video",
156 "Template for a video filter",
157 "David Schleef <ds@schleef.org>");
158 GstElementClass
*element_class
= GST_ELEMENT_CLASS (g_class
);
159 //GstBaseTransformClass *base_transform_class = GST_BASE_TRANSFORM_CLASS (g_class);
161 gst_element_class_add_pad_template (element_class
,
162 gst_static_pad_template_get (&gst_logoinsert_src_template
));
163 gst_element_class_add_pad_template (element_class
,
164 gst_static_pad_template_get (&gst_logoinsert_sink_template
));
166 gst_element_class_set_details (element_class
, &compress_details
);
170 gst_logoinsert_class_init (gpointer g_class
, gpointer class_data
)
172 GObjectClass
*gobject_class
;
173 GstBaseTransformClass
*base_transform_class
;
174 GstLogoinsertClass
*filter_class
;
176 gobject_class
= G_OBJECT_CLASS (g_class
);
177 base_transform_class
= GST_BASE_TRANSFORM_CLASS (g_class
);
178 filter_class
= GST_LOGOINSERT_CLASS (g_class
);
180 gobject_class
->set_property
= gst_logoinsert_set_property
;
181 gobject_class
->get_property
= gst_logoinsert_get_property
;
183 g_object_class_install_property (gobject_class
, ARG_LOCATION
,
184 g_param_spec_string ("location", "location",
185 "location of PNG file to overlay",
186 "", G_PARAM_READWRITE
));
188 base_transform_class
->set_caps
= gst_logoinsert_set_caps
;
189 base_transform_class
->transform_ip
= gst_logoinsert_transform_ip
;
193 gst_logoinsert_init (GTypeInstance
* instance
, gpointer g_class
)
195 //GstLogoinsert *compress = GST_LOGOINSERT (instance);
196 //GstBaseTransform *btrans = GST_BASE_TRANSFORM (instance);
198 GST_DEBUG ("gst_logoinsert_init");
202 gst_logoinsert_set_property (GObject
* object
, guint prop_id
,
203 const GValue
* value
, GParamSpec
* pspec
)
207 g_return_if_fail (GST_IS_LOGOINSERT (object
));
208 src
= GST_LOGOINSERT (object
);
210 GST_DEBUG ("gst_logoinsert_set_property");
213 gst_logoinsert_set_location (src
, g_value_get_string (value
));
221 gst_logoinsert_get_property (GObject
* object
, guint prop_id
, GValue
* value
,
226 g_return_if_fail (GST_IS_LOGOINSERT (object
));
227 src
= GST_LOGOINSERT (object
);
231 g_value_set_string (value
, src
->location
);
234 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
240 gst_logoinsert_set_caps (GstBaseTransform
*base_transform
,
241 GstCaps
*incaps
, GstCaps
*outcaps
)
245 g_return_val_if_fail (GST_IS_LOGOINSERT (base_transform
), GST_FLOW_ERROR
);
246 li
= GST_LOGOINSERT (base_transform
);
248 gst_video_format_parse_caps (incaps
, &li
->format
, &li
->width
,
255 gst_logoinsert_transform_ip (GstBaseTransform
* base_transform
,
261 g_return_val_if_fail (GST_IS_LOGOINSERT (base_transform
), GST_FLOW_ERROR
);
262 li
= GST_LOGOINSERT (base_transform
);
264 frame
= gst_schro_buffer_wrap (buf
, li
->format
, li
->width
, li
->height
);
266 if (li
->ayuv_frame
== NULL
) return GST_FLOW_OK
;
268 if (li
->overlay_frame
== NULL
) {
271 f
= schro_virt_frame_extract_alpha_take (
272 schro_frame_ref (li
->ayuv_frame
));
273 f
= schro_virt_frame_new_subsample_take (f
, frame
->format
);
274 li
->alpha_frame
= schro_frame_realize (f
);
276 f
= schro_virt_frame_new_unpack_take (schro_frame_ref (li
->ayuv_frame
));
277 f
= schro_virt_frame_new_color_matrix_take (f
);
278 f
= schro_virt_frame_new_subsample_take (f
, frame
->format
);
279 li
->overlay_frame
= schro_frame_realize (f
);
288 int offset_x
, offset_y
;
291 offset_x
= frame
->components
[k
].width
-
292 li
->alpha_frame
->components
[k
].width
;
293 offset_y
= frame
->components
[k
].height
-
294 li
->alpha_frame
->components
[k
].height
;
296 for(j
=0;j
<li
->overlay_frame
->components
[k
].height
;j
++){
297 dest
= SCHRO_FRAME_DATA_GET_LINE (frame
->components
+ k
, j
+ offset_y
);
298 src
= SCHRO_FRAME_DATA_GET_LINE (li
->overlay_frame
->components
+ k
, j
);
299 alpha
= SCHRO_FRAME_DATA_GET_LINE (li
->alpha_frame
->components
+ k
, j
);
301 #define oil_divide_255(x) ((((x)+128) + (((x)+128)>>8))>>8)
303 for(i
=0;i
<li
->overlay_frame
->components
[k
].width
;i
++){
304 dest
[i
+offset_x
] = oil_divide_255 (src
[i
]*alpha
[i
] + dest
[i
+offset_x
]*(255-alpha
[i
]));
315 gst_logoinsert_set_location (GstLogoinsert
*li
, const gchar
*location
)
318 GError
*error
= NULL
;
320 g_free (li
->location
);
322 if (li
->overlay_frame
) {
323 schro_frame_unref (li
->overlay_frame
);
324 li
->overlay_frame
= NULL
;
327 li
->location
= g_strdup (location
);
329 ret
= g_file_get_contents (li
->location
, &li
->data
, &li
->size
, &error
);
336 li
->ayuv_frame
= schro_frame_new_from_png (li
->data
, li
->size
);
338 if (li
->alpha_frame
) {
339 schro_frame_unref (li
->alpha_frame
);
340 li
->alpha_frame
= NULL
;
342 if (li
->overlay_frame
) {
343 schro_frame_unref (li
->overlay_frame
);
344 li
->overlay_frame
= NULL
;
349 /* load PNG into SchroFrame */
351 struct png_data_struct
{
358 read_data(png_structp png_ptr
, png_bytep data
, png_size_t length
)
360 struct png_data_struct
*s
= png_ptr
->io_ptr
;
362 memcpy (data
, s
->data
+ s
->offset
, length
);
367 schro_frame_new_from_png (void *data
, int size
)
369 struct png_data_struct s
= { 0 };
380 png_ptr
= png_create_read_struct(PNG_LIBPNG_VER_STRING
,
382 info_ptr
= png_create_info_struct(png_ptr
);
386 png_set_read_fn(png_ptr
, (void *)&s
, read_data
);
388 png_read_info (png_ptr
, info_ptr
);
390 width
= png_get_image_width (png_ptr
, info_ptr
);
391 height
= png_get_image_height (png_ptr
, info_ptr
);
392 color_type
= png_get_color_type (png_ptr
, info_ptr
);
393 GST_DEBUG("PNG size %dx%d color_type %d", width
, height
, color_type
);
395 png_set_strip_16 (png_ptr
);
396 png_set_packing (png_ptr
);
397 if (color_type
== PNG_COLOR_TYPE_RGB
) {
398 png_set_filler (png_ptr
, 0xff, PNG_FILLER_BEFORE
);
400 if (color_type
== PNG_COLOR_TYPE_RGB_ALPHA
) {
401 png_set_swap_alpha(png_ptr
);
404 frame_data
= g_malloc (width
* height
* 4);
405 frame
= schro_frame_new_from_data_AYUV (frame_data
, width
, height
);
407 rowbytes
= png_get_rowbytes (png_ptr
, info_ptr
);
408 rows
= (png_bytep
*) g_malloc (sizeof (png_bytep
) * height
);
410 for (j
= 0; j
< height
; j
++) {
411 rows
[j
] = SCHRO_FRAME_DATA_GET_LINE (frame
->components
+0, j
);
413 png_read_image (png_ptr
, rows
);
416 // PNG_TRANSFORM_STRP_16 | PNG_TRANSFORM_PACKING,
418 png_destroy_read_struct(&png_ptr
, &info_ptr
, png_infopp_NULL
);
425 extract_alpha (SchroFrame
*frame
, void *_dest
, int component
, int j
)
427 uint8_t *dest
= _dest
;
431 src
= SCHRO_FRAME_DATA_GET_LINE (frame
->virt_frame1
->components
+ 0, j
);
432 for(i
=0;i
<frame
->width
;i
++){
433 dest
[i
] = src
[i
*4 + 0];
438 schro_virt_frame_extract_alpha_take (SchroFrame
*frame
)
440 SchroFrame
*virt_frame
;
442 /* FIXME check that frame is a real AYUV frame */
444 virt_frame
= schro_frame_new_virtual (NULL
, SCHRO_FRAME_FORMAT_U8_444
,
445 frame
->width
, frame
->height
);
446 virt_frame
->virt_frame1
= frame
;
447 virt_frame
->render_line
= extract_alpha
;
453 schro_frame_realize (SchroFrame
*frame
)
457 dest
= schro_frame_clone (NULL
, frame
);
458 schro_virt_frame_render (frame
, dest
);
459 schro_frame_unref (frame
);