2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
5 * Copyright (C) 2000 Donald A. Graft
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Library General Public License for more details.
12 * You should have received a copy of the GNU Library General Public
13 * License along with this library; if not, write to the
14 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15 * Boston, MA 02111-1307, USA.
24 #include "gstpngenc.h"
25 #include <gst/video/video.h>
27 #define MAX_HEIGHT 4096
30 GstElementDetails gst_pngenc_details = {
32 "Codec/Encoder/Image",
33 "Encode a video frame to a .png image",
34 "Jeremy SIMON <jsimon13@yahoo.fr>",
38 /* Filter signals and args */
50 static void gst_pngenc_base_init (gpointer g_class);
51 static void gst_pngenc_class_init (GstPngEncClass *klass);
52 static void gst_pngenc_init (GstPngEnc *pngenc);
54 static void gst_pngenc_chain (GstPad *pad, GstData *_data);
56 GstPadTemplate *pngenc_src_template, *pngenc_sink_template;
58 static GstElementClass *parent_class = NULL;
61 static void user_error_fn (png_structp png_ptr, png_const_charp error_msg)
63 g_warning("%s", error_msg);
66 static void user_warning_fn (png_structp png_ptr, png_const_charp warning_msg)
68 g_warning("%s", warning_msg);
72 GType gst_pngenc_get_type (void)
74 static GType pngenc_type = 0;
77 static const GTypeInfo pngenc_info = {
78 sizeof (GstPngEncClass),
81 (GClassInitFunc) gst_pngenc_class_init,
86 (GInstanceInitFunc) gst_pngenc_init,
89 pngenc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstPngEnc",
96 png_caps_factory (void)
98 return gst_caps_new_simple ("video/x-png",
99 "width", GST_TYPE_INT_RANGE, 16, 4096,
100 "height", GST_TYPE_INT_RANGE, 16, 4096,
101 "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE,
107 raw_caps_factory (void)
109 return gst_caps_from_string (GST_VIDEO_CAPS_RGB);
113 gst_pngenc_base_init (gpointer g_class)
115 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
116 GstCaps *raw_caps, *png_caps;
118 raw_caps = raw_caps_factory ();
119 png_caps = png_caps_factory ();
121 pngenc_sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
125 pngenc_src_template = gst_pad_template_new ("src", GST_PAD_SRC,
129 gst_element_class_add_pad_template (element_class, pngenc_sink_template);
130 gst_element_class_add_pad_template (element_class, pngenc_src_template);
131 gst_element_class_set_details (element_class, &gst_pngenc_details);
135 gst_pngenc_class_init (GstPngEncClass *klass)
137 GObjectClass *gobject_class;
138 GstElementClass *gstelement_class;
140 gobject_class = (GObjectClass *) klass;
141 gstelement_class = (GstElementClass *) klass;
143 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
147 static GstPadLinkReturn
148 gst_pngenc_sinklink (GstPad *pad, const GstCaps *caps)
152 GstStructure *structure;
154 pngenc = GST_PNGENC (gst_pad_get_parent (pad));
156 structure = gst_caps_get_structure (caps, 0);
157 gst_structure_get_int (structure, "width", &pngenc->width);
158 gst_structure_get_int (structure, "height", &pngenc->height);
159 gst_structure_get_double (structure, "framerate", &fps);
160 gst_structure_get_int (structure, "bpp", &pngenc->bpp);
162 caps = gst_caps_new_simple ("video/x-png",
163 "framerate", G_TYPE_DOUBLE, fps,
164 "width", G_TYPE_INT, pngenc->width,
165 "height", G_TYPE_INT, pngenc->height, NULL);
167 return gst_pad_try_set_caps (pngenc->srcpad, caps);
171 gst_pngenc_init (GstPngEnc * pngenc)
173 pngenc->sinkpad = gst_pad_new_from_template (pngenc_sink_template, "sink");
174 gst_element_add_pad (GST_ELEMENT (pngenc), pngenc->sinkpad);
176 pngenc->srcpad = gst_pad_new ("src", GST_PAD_SRC);
177 gst_element_add_pad (GST_ELEMENT (pngenc), pngenc->srcpad);
179 gst_pad_set_chain_function (pngenc->sinkpad, gst_pngenc_chain);
180 gst_pad_set_link_function (pngenc->sinkpad, gst_pngenc_sinklink);
182 pngenc->png_struct_ptr = NULL;
183 pngenc->png_info_ptr = NULL;
187 void user_flush_data (png_structp png_ptr)
191 pngenc = (GstPngEnc *) png_get_io_ptr (png_ptr);
193 gst_pad_push (pngenc->srcpad, GST_DATA (gst_event_new (GST_EVENT_FLUSH)));
197 void user_write_data (png_structp png_ptr, png_bytep data, png_uint_32 length)
202 pngenc = (GstPngEnc *) png_get_io_ptr (png_ptr);
204 buffer = gst_buffer_new();
205 GST_BUFFER_DATA (buffer) = g_memdup (data, length);
206 GST_BUFFER_SIZE (buffer) = length;
208 if (pngenc->buffer_out)
211 merge = gst_buffer_merge (pngenc->buffer_out, buffer);
212 gst_buffer_unref (buffer);
213 gst_buffer_unref (pngenc->buffer_out);
214 pngenc->buffer_out = merge;
217 pngenc->buffer_out = buffer;
221 gst_pngenc_chain (GstPad *pad, GstData *_data)
223 GstBuffer *buf = GST_BUFFER (_data);
226 png_byte *row_pointers[MAX_HEIGHT];
229 pngenc = GST_PNGENC (gst_pad_get_parent (pad));
231 pngenc->buffer_out = NULL;
232 if (!GST_PAD_IS_USABLE (pngenc->srcpad))
234 gst_buffer_unref (buf);
238 /* initialize png struct stuff */
239 pngenc->png_struct_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
240 (png_voidp) NULL, user_error_fn, user_warning_fn);
241 /* FIXME: better error handling */
242 if (pngenc->png_struct_ptr == NULL)
243 g_warning ("Failed to initialize png structure");
245 pngenc->png_info_ptr = png_create_info_struct (pngenc->png_struct_ptr);
246 if (!pngenc->png_info_ptr)
248 png_destroy_read_struct (&(pngenc->png_struct_ptr), (png_infopp) NULL,
252 /* non-0 return is from a longjmp inside of libpng */
253 if (setjmp (pngenc->png_struct_ptr->jmpbuf) != 0)
255 GST_DEBUG ("returning from longjmp");
256 png_destroy_write_struct (&pngenc->png_struct_ptr, &pngenc->png_info_ptr);
260 png_set_filter (pngenc->png_struct_ptr, 0,
261 PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE);
262 png_set_compression_level (pngenc->png_struct_ptr, 9);
265 pngenc->png_struct_ptr,
266 pngenc->png_info_ptr,
272 PNG_COMPRESSION_TYPE_DEFAULT,
273 PNG_FILTER_TYPE_DEFAULT
276 png_set_write_fn (pngenc->png_struct_ptr, pngenc,
277 (png_rw_ptr) user_write_data, user_flush_data);
279 for (row_index = 0; row_index < pngenc->height; row_index++)
280 row_pointers[row_index] = GST_BUFFER_DATA (buf) +
281 (pngenc->width * row_index * pngenc->bpp / 8);
283 png_write_info (pngenc->png_struct_ptr, pngenc->png_info_ptr);
284 png_write_image (pngenc->png_struct_ptr, row_pointers);
285 png_write_end (pngenc->png_struct_ptr, NULL);
287 user_flush_data (pngenc->png_struct_ptr);
289 png_destroy_info_struct (pngenc->png_struct_ptr, &pngenc->png_info_ptr);
290 png_destroy_write_struct (&pngenc->png_struct_ptr, (png_infopp) NULL);
292 gst_pad_push (pngenc->srcpad, GST_DATA (pngenc->buffer_out));
294 /* send EOS event, since a frame has been pushed out */
295 event = gst_event_new (GST_EVENT_EOS);
296 gst_pad_push (pngenc->srcpad, GST_DATA (event));
298 gst_buffer_unref (buf);