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"
26 #define MAX_HEIGHT 4096
29 GstElementDetails gst_pngenc_details = {
33 "Encode a video frame to a .png image",
35 "Jeremy SIMON <jsimon13@yahoo.fr>",
36 "(C) 2000 Donald Graft",
40 /* Filter signals and args */
52 static void gst_pngenc_class_init (GstPngEncClass *klass);
53 static void gst_pngenc_init (GstPngEnc *pngenc);
55 static void gst_pngenc_chain (GstPad *pad, GstBuffer *buf);
57 static GstElementClass *parent_class = NULL;
60 static void user_error_fn (png_structp png_ptr, png_const_charp error_msg)
62 g_warning("%s", error_msg);
65 static void user_warning_fn (png_structp png_ptr, png_const_charp warning_msg)
67 g_warning("%s", warning_msg);
71 GType gst_pngenc_get_type (void)
73 static GType pngenc_type = 0;
76 static const GTypeInfo pngenc_info = {
77 sizeof (GstPngEncClass), NULL,
79 (GClassInitFunc) gst_pngenc_class_init,
84 (GInstanceInitFunc) gst_pngenc_init,
87 pngenc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstPngEnc",
94 gst_pngenc_class_init (GstPngEncClass *klass)
96 GObjectClass *gobject_class;
97 GstElementClass *gstelement_class;
99 gobject_class = (GObjectClass *) klass;
100 gstelement_class = (GstElementClass *) klass;
102 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
106 static GstPadLinkReturn
107 gst_pngenc_sinklink (GstPad *pad, GstCaps *caps)
112 pngenc = GST_PNGENC (gst_pad_get_parent (pad));
114 if (!GST_CAPS_IS_FIXED (caps))
115 return GST_PAD_LINK_DELAYED;
117 gst_caps_get_int (caps, "width", &pngenc->width);
118 gst_caps_get_int (caps, "height", &pngenc->height);
119 gst_caps_get_float (caps, "framerate", &fps);
120 gst_caps_get_int (caps, "bpp", &pngenc->bpp);
122 caps = GST_CAPS_NEW ("png_src",
124 "framerate", GST_PROPS_FLOAT (fps),
125 "width", GST_PROPS_INT (pngenc->width),
126 "height", GST_PROPS_INT (pngenc->height));
128 return gst_pad_try_set_caps (pngenc->srcpad, caps);
132 gst_pngenc_init (GstPngEnc * pngenc)
134 pngenc->sinkpad = gst_pad_new_from_template (pngenc_sink_template, "sink");
135 gst_element_add_pad (GST_ELEMENT (pngenc), pngenc->sinkpad);
137 pngenc->srcpad = gst_pad_new ("src", GST_PAD_SRC);
138 gst_element_add_pad (GST_ELEMENT (pngenc), pngenc->srcpad);
140 gst_pad_set_chain_function (pngenc->sinkpad, gst_pngenc_chain);
141 gst_pad_set_link_function (pngenc->sinkpad, gst_pngenc_sinklink);
143 pngenc->png_struct_ptr = NULL;
144 pngenc->png_info_ptr = NULL;
148 void user_flush_data (png_structp png_ptr)
152 pngenc = (GstPngEnc *) png_get_io_ptr (png_ptr);
154 gst_pad_push (pngenc->srcpad, GST_BUFFER (gst_event_new (GST_EVENT_FLUSH)));
158 void user_write_data (png_structp png_ptr, png_bytep data, png_uint_32 length)
163 pngenc = (GstPngEnc *) png_get_io_ptr (png_ptr);
165 buffer = gst_buffer_new();
166 GST_BUFFER_DATA (buffer) = g_memdup (data, length);
167 GST_BUFFER_SIZE (buffer) = length;
169 if (pngenc->buffer_out)
171 pngenc->buffer_out = gst_buffer_merge (pngenc->buffer_out, buffer);
172 gst_buffer_unref (buffer);
175 pngenc->buffer_out = buffer;
179 gst_pngenc_chain (GstPad *pad, GstBuffer *buf)
183 png_byte *row_pointers[MAX_HEIGHT];
186 pngenc = GST_PNGENC (gst_pad_get_parent (pad));
188 pngenc->buffer_out = NULL;
189 if (!GST_PAD_IS_USABLE (pngenc->srcpad))
191 gst_buffer_unref (buf);
195 /* initialize png struct stuff */
196 pngenc->png_struct_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
197 (png_voidp) NULL, user_error_fn, user_warning_fn);
198 /* FIXME: better error handling */
199 if (pngenc->png_struct_ptr == NULL)
200 g_warning ("Failed to initialize png structure");
202 pngenc->png_info_ptr = png_create_info_struct (pngenc->png_struct_ptr);
203 if (!pngenc->png_info_ptr)
205 png_destroy_read_struct (&(pngenc->png_struct_ptr), (png_infopp) NULL,
209 /* non-0 return is from a longjmp inside of libpng */
210 if (setjmp (pngenc->png_struct_ptr->jmpbuf) != 0)
212 GST_DEBUG ("returning from longjmp");
213 png_destroy_write_struct (&pngenc->png_struct_ptr, &pngenc->png_info_ptr);
217 png_set_filter (pngenc->png_struct_ptr, 0,
218 PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE);
219 png_set_compression_level (pngenc->png_struct_ptr, 9);
222 pngenc->png_struct_ptr,
223 pngenc->png_info_ptr,
229 PNG_COMPRESSION_TYPE_DEFAULT,
230 PNG_FILTER_TYPE_DEFAULT
233 png_set_write_fn (pngenc->png_struct_ptr, pngenc,
234 (png_rw_ptr) user_write_data, user_flush_data);
236 for (row_index = 0; row_index < pngenc->height; row_index++)
237 row_pointers[row_index] = GST_BUFFER_DATA (buf) +
238 (pngenc->width * row_index * pngenc->bpp / 8);
240 png_write_info (pngenc->png_struct_ptr, pngenc->png_info_ptr);
241 png_write_image (pngenc->png_struct_ptr, row_pointers);
242 png_write_end (pngenc->png_struct_ptr, NULL);
244 user_flush_data (pngenc->png_struct_ptr);
246 png_destroy_info_struct (pngenc->png_struct_ptr, &pngenc->png_info_ptr);
247 png_destroy_write_struct (&pngenc->png_struct_ptr, (png_infopp) NULL);
249 gst_pad_push (pngenc->srcpad, pngenc->buffer_out);
251 /* send EOS event, since a frame has been pushed out */
252 event = gst_event_new (GST_EVENT_EOS);
253 gst_pad_push (pngenc->srcpad, GST_BUFFER (event));
255 gst_buffer_unref (buf);