updating some plugin categories
[platform/upstream/gst-plugins-good.git] / ext / libpng / gstpngenc.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * Filter:
5  * Copyright (C) 2000 Donald A. Graft
6  *
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.
11  *
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.
16  *
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 #include <string.h>
23 #include <gst/gst.h>
24 #include "gstpngenc.h"
25
26 #define MAX_HEIGHT              4096
27
28
29 GstElementDetails gst_pngenc_details = {
30   "PNG encoder",
31   "Codec/Image",
32   "LGPL",
33   "Encode a video frame to a .png image",
34   VERSION,
35   "Jeremy SIMON <jsimon13@yahoo.fr>",
36   "(C) 2000 Donald Graft",
37 };
38
39
40 /* Filter signals and args */
41 enum
42 {
43   /* FILL ME */
44   LAST_SIGNAL
45 };
46
47 enum
48 {
49   ARG_0
50 };
51
52 static void     gst_pngenc_class_init   (GstPngEncClass *klass);
53 static void     gst_pngenc_init         (GstPngEnc *pngenc);
54
55 static void     gst_pngenc_chain        (GstPad *pad, GstBuffer *buf);
56
57 static GstElementClass *parent_class = NULL;
58
59
60 static void user_error_fn (png_structp png_ptr, png_const_charp error_msg)
61 {
62   g_warning("%s", error_msg);
63 }
64
65 static void user_warning_fn (png_structp png_ptr, png_const_charp warning_msg)
66 {
67   g_warning("%s", warning_msg);
68 }
69
70
71 GType gst_pngenc_get_type (void)
72 {
73   static GType pngenc_type = 0;
74
75   if (!pngenc_type) {
76     static const GTypeInfo pngenc_info = {
77       sizeof (GstPngEncClass), NULL,
78       NULL,
79       (GClassInitFunc) gst_pngenc_class_init,
80       NULL,
81       NULL,
82       sizeof (GstPngEnc),
83       0,
84       (GInstanceInitFunc) gst_pngenc_init,
85     };
86
87     pngenc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstPngEnc",
88                                           &pngenc_info, 0);
89   }
90   return pngenc_type;
91 }
92
93 static void
94 gst_pngenc_class_init (GstPngEncClass *klass)
95 {
96   GObjectClass *gobject_class;
97   GstElementClass *gstelement_class;
98
99   gobject_class = (GObjectClass *) klass;
100   gstelement_class = (GstElementClass *) klass;
101
102   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
103 }
104
105
106 static GstPadLinkReturn
107 gst_pngenc_sinklink (GstPad *pad, GstCaps *caps)
108 {
109   GstPngEnc *pngenc;
110   gfloat fps;
111
112   pngenc = GST_PNGENC (gst_pad_get_parent (pad));
113
114   if (!GST_CAPS_IS_FIXED (caps))
115     return GST_PAD_LINK_DELAYED;
116
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);
121
122   caps = GST_CAPS_NEW ("png_src",
123                        "video/x-png",
124                          "framerate", GST_PROPS_FLOAT (fps),
125                          "width",     GST_PROPS_INT (pngenc->width),
126                          "height",    GST_PROPS_INT (pngenc->height));
127
128   return gst_pad_try_set_caps (pngenc->srcpad, caps);
129 }
130
131 static void
132 gst_pngenc_init (GstPngEnc * pngenc)
133 {
134   pngenc->sinkpad = gst_pad_new_from_template (pngenc_sink_template, "sink");
135   gst_element_add_pad (GST_ELEMENT (pngenc), pngenc->sinkpad);
136
137   pngenc->srcpad = gst_pad_new ("src", GST_PAD_SRC);
138   gst_element_add_pad (GST_ELEMENT (pngenc), pngenc->srcpad);
139
140   gst_pad_set_chain_function (pngenc->sinkpad, gst_pngenc_chain);
141   gst_pad_set_link_function (pngenc->sinkpad, gst_pngenc_sinklink);
142
143   pngenc->png_struct_ptr = NULL;
144   pngenc->png_info_ptr = NULL;
145
146 }
147
148 void user_flush_data (png_structp png_ptr)
149 {
150 GstPngEnc *pngenc;
151
152   pngenc = (GstPngEnc *) png_get_io_ptr (png_ptr);
153
154   gst_pad_push (pngenc->srcpad, GST_BUFFER (gst_event_new (GST_EVENT_FLUSH)));
155 }
156
157
158 void user_write_data (png_structp png_ptr, png_bytep data, png_uint_32 length)
159 {
160   GstBuffer *buffer;
161   GstPngEnc *pngenc;
162
163   pngenc = (GstPngEnc *) png_get_io_ptr (png_ptr);
164
165   buffer = gst_buffer_new();
166   GST_BUFFER_DATA (buffer) = g_memdup (data, length);
167   GST_BUFFER_SIZE (buffer) = length;
168
169   if (pngenc->buffer_out)
170   {
171     pngenc->buffer_out = gst_buffer_merge (pngenc->buffer_out, buffer);
172     gst_buffer_unref (buffer);
173   }
174   else
175     pngenc->buffer_out = buffer;
176 }
177
178 static void
179 gst_pngenc_chain (GstPad *pad, GstBuffer *buf)
180 {
181   GstPngEnc *pngenc;
182   gint row_index;
183   png_byte *row_pointers[MAX_HEIGHT];
184   GstEvent *event;
185
186   pngenc = GST_PNGENC (gst_pad_get_parent (pad));
187
188   pngenc->buffer_out = NULL;
189   if (!GST_PAD_IS_USABLE (pngenc->srcpad))
190   {
191     gst_buffer_unref (buf);
192     return;
193   }
194
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");
201
202   pngenc->png_info_ptr = png_create_info_struct (pngenc->png_struct_ptr);
203   if (!pngenc->png_info_ptr)
204   {
205     png_destroy_read_struct (&(pngenc->png_struct_ptr), (png_infopp) NULL,
206                              (png_infopp) NULL);
207   }
208
209   /* non-0 return is from a longjmp inside of libpng */
210   if (setjmp (pngenc->png_struct_ptr->jmpbuf) != 0)
211   {
212     GST_DEBUG ("returning from longjmp");
213     png_destroy_write_struct (&pngenc->png_struct_ptr, &pngenc->png_info_ptr);
214     return;
215   }
216
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);
220
221   png_set_IHDR(
222     pngenc->png_struct_ptr,
223     pngenc->png_info_ptr,
224     pngenc->width,
225     pngenc->height,
226     pngenc->bpp / 3,
227     PNG_COLOR_TYPE_RGB,
228     PNG_INTERLACE_NONE,
229     PNG_COMPRESSION_TYPE_DEFAULT,
230     PNG_FILTER_TYPE_DEFAULT
231   );
232
233   png_set_write_fn (pngenc->png_struct_ptr, pngenc,
234                     (png_rw_ptr) user_write_data, user_flush_data);
235
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);
239
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);
243
244   user_flush_data (pngenc->png_struct_ptr);
245
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);
248
249   gst_pad_push (pngenc->srcpad, pngenc->buffer_out);
250
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));
254
255   gst_buffer_unref (buf);
256 }