2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
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.
27 #include "gsttarkinenc.h"
29 extern GstPadTemplate *enc_src_template, *enc_sink_template;
31 /* elementfactory information */
32 GstElementDetails tarkinenc_details = {
34 "Filter/Video/Encoder",
36 "Encodes video in OGG Tarkin format",
38 "Monty <monty@xiph.org>, "
39 "Wim Taymans <wim.taymans@chello.be>",
43 /* TarkinEnc signals and args */
58 static void gst_tarkinenc_class_init (TarkinEncClass *klass);
59 static void gst_tarkinenc_init (TarkinEnc *arkinenc);
61 static void gst_tarkinenc_chain (GstPad *pad, GstBuffer *buf);
62 static void gst_tarkinenc_setup (TarkinEnc *tarkinenc);
64 static void gst_tarkinenc_get_property (GObject *object, guint prop_id, GValue *value,
66 static void gst_tarkinenc_set_property (GObject *object, guint prop_id, const GValue *value,
69 static GstElementClass *parent_class = NULL;
70 /*static guint gst_tarkinenc_signals[LAST_SIGNAL] = { 0 }; */
73 tarkinenc_get_type (void)
75 static GType tarkinenc_type = 0;
77 if (!tarkinenc_type) {
78 static const GTypeInfo tarkinenc_info = {
79 sizeof (TarkinEncClass),
82 (GClassInitFunc) gst_tarkinenc_class_init,
87 (GInstanceInitFunc) gst_tarkinenc_init,
90 tarkinenc_type = g_type_register_static (GST_TYPE_ELEMENT, "TarkinEnc", &tarkinenc_info, 0);
92 return tarkinenc_type;
96 gst_tarkinenc_class_init (TarkinEncClass *klass)
98 GObjectClass *gobject_class;
99 GstElementClass *gstelement_class;
101 gobject_class = (GObjectClass *) klass;
102 gstelement_class = (GstElementClass *) klass;
104 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
105 g_param_spec_int ("bitrate", "bitrate", "bitrate",
106 G_MININT, G_MAXINT, 3000, G_PARAM_READWRITE));
107 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_S_MOMENTS,
108 g_param_spec_int ("s_moments", "Synthesis Moments",
109 "Number of vanishing moments for the synthesis filter",
110 1, 4, 2, G_PARAM_READWRITE));
111 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_A_MOMENTS,
112 g_param_spec_int ("a_moments", "Analysis Moments",
113 "Number of vanishing moments for the analysis filter",
114 1, 4, 2, G_PARAM_READWRITE));
116 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
118 gobject_class->set_property = gst_tarkinenc_set_property;
119 gobject_class->get_property = gst_tarkinenc_get_property;
122 static GstPadLinkReturn
123 gst_tarkinenc_sinkconnect (GstPad *pad, GstCaps *caps)
125 TarkinEnc *tarkinenc;
127 tarkinenc = GST_TARKINENC (gst_pad_get_parent (pad));
129 if (!GST_CAPS_IS_FIXED (caps))
130 return GST_PAD_LINK_DELAYED;
132 gst_caps_debug (caps, "caps to be set on tarkin sink pad");
134 tarkinenc->layer[0].bitstream_len = tarkinenc->bitrate;
135 tarkinenc->layer[0].a_moments = tarkinenc->a_moments;
136 tarkinenc->layer[0].s_moments = tarkinenc->s_moments;
137 gst_caps_get_int (caps, "width", &tarkinenc->layer[0].width);
138 gst_caps_get_int (caps, "height", &tarkinenc->layer[0].height);
139 tarkinenc->layer[0].format = TARKIN_RGB24;
140 tarkinenc->layer[0].frames_per_buf = TARKIN_RGB24;
142 gst_tarkinenc_setup (tarkinenc);
144 if (tarkinenc->setup)
145 return GST_PAD_LINK_OK;
147 return GST_PAD_LINK_REFUSED;
151 gst_tarkinenc_init (TarkinEnc * tarkinenc)
153 tarkinenc->sinkpad = gst_pad_new_from_template (enc_sink_template, "sink");
154 gst_element_add_pad (GST_ELEMENT (tarkinenc), tarkinenc->sinkpad);
155 gst_pad_set_chain_function (tarkinenc->sinkpad, gst_tarkinenc_chain);
156 gst_pad_set_link_function (tarkinenc->sinkpad, gst_tarkinenc_sinkconnect);
158 tarkinenc->srcpad = gst_pad_new_from_template (enc_src_template, "src");
159 gst_element_add_pad (GST_ELEMENT (tarkinenc), tarkinenc->srcpad);
161 tarkinenc->bitrate = 3000;
162 tarkinenc->s_moments = 2;
163 tarkinenc->a_moments = 2;
164 tarkinenc->setup = FALSE;
167 TarkinError free_frame (void *s, void *ptr)
172 TarkinError packet_out (void *stream, ogg_packet *op)
175 TarkinStream *s = stream;
176 TarkinEnc *te = s->user_ptr;
179 ogg_stream_packetin (&te->os, op);
182 ogg_stream_flush (&te->os, &og);
183 outbuf = gst_buffer_new ();
184 GST_BUFFER_DATA (outbuf) = og.header;
185 GST_BUFFER_SIZE (outbuf) = og.header_len;
186 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DONTFREE);
187 gst_pad_push (te->srcpad, outbuf);
188 outbuf = gst_buffer_new ();
189 GST_BUFFER_DATA (outbuf) = og.body;
190 GST_BUFFER_SIZE (outbuf) = og.body_len;
191 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DONTFREE);
192 gst_pad_push (te->srcpad, outbuf);
194 while (ogg_stream_pageout (&te->os, &og)){
195 outbuf = gst_buffer_new ();
196 GST_BUFFER_DATA (outbuf) = og.header;
197 GST_BUFFER_SIZE (outbuf) = og.header_len;
198 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DONTFREE);
199 gst_pad_push (te->srcpad, outbuf);
200 outbuf = gst_buffer_new ();
201 GST_BUFFER_DATA (outbuf) = og.body;
202 GST_BUFFER_SIZE (outbuf) = og.body_len;
203 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DONTFREE);
204 gst_pad_push (te->srcpad, outbuf);
212 gst_tarkinenc_setup (TarkinEnc *tarkinenc)
217 ogg_stream_init (&tarkinenc->os, 1);
218 tarkin_info_init (&tarkinenc->ti);
220 tarkinenc->ti.inter.numerator = 1;
221 tarkinenc->ti.inter.denominator = 1;
223 tarkin_comment_init (&tarkinenc->tc);
224 tarkin_comment_add_tag (&tarkinenc->tc, "TITLE", "GStreamer produced file");
225 tarkin_comment_add_tag (&tarkinenc->tc, "ARTIST", "C coders ;)");
227 tarkinenc->tarkin_stream = tarkin_stream_new ();
228 tarkin_analysis_init (tarkinenc->tarkin_stream,
229 &tarkinenc->ti, free_frame, packet_out, (void*)tarkinenc);
230 tarkin_analysis_add_layer(tarkinenc->tarkin_stream, &tarkinenc->layer[0]);
232 tarkin_analysis_headerout (tarkinenc->tarkin_stream, &tarkinenc->tc,
233 tarkinenc->op, &tarkinenc->op[1], &tarkinenc->op[2]);
234 for(i = 0; i < 3; i++){
235 ogg_stream_packetin(&tarkinenc->os, &tarkinenc->op[i]);
238 ogg_stream_flush (&tarkinenc->os, &tarkinenc->og);
240 tarkinenc->frame_num = 0;
242 outbuf = gst_buffer_new ();
243 GST_BUFFER_DATA (outbuf) = tarkinenc->og.header;
244 GST_BUFFER_SIZE (outbuf) = tarkinenc->og.header_len;
245 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DONTFREE);
246 gst_pad_push (tarkinenc->srcpad, outbuf);
248 outbuf = gst_buffer_new ();
249 GST_BUFFER_DATA (outbuf) = tarkinenc->og.body;
250 GST_BUFFER_SIZE (outbuf) = tarkinenc->og.body_len;
251 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DONTFREE);
252 gst_pad_push (tarkinenc->srcpad, outbuf);
254 tarkinenc->setup = TRUE;
258 gst_tarkinenc_chain (GstPad *pad, GstBuffer *buf)
260 TarkinEnc *tarkinenc;
262 g_return_if_fail (pad != NULL);
263 g_return_if_fail (GST_IS_PAD (pad));
264 g_return_if_fail (buf != NULL);
266 tarkinenc = GST_TARKINENC (gst_pad_get_parent (pad));
268 if (!tarkinenc->setup) {
269 gst_element_error (GST_ELEMENT (tarkinenc), "encoder not initialized (input is not audio?)");
270 if (GST_IS_BUFFER (buf))
271 gst_buffer_unref (buf);
273 gst_pad_event_default (pad, GST_EVENT (buf));
277 if (GST_IS_EVENT (buf)) {
278 switch (GST_EVENT_TYPE (buf)) {
280 tarkin_analysis_framein (tarkinenc->tarkin_stream, NULL, 0, NULL); /* EOS */
281 tarkin_comment_clear (&tarkinenc->tc);
282 tarkin_stream_destroy (tarkinenc->tarkin_stream);
284 gst_pad_event_default (pad, GST_EVENT (buf));
294 data = GST_BUFFER_DATA (buf);
295 size = GST_BUFFER_SIZE (buf);
297 date.numerator = tarkinenc->frame_num;
298 date.denominator = 1;
299 tarkin_analysis_framein (tarkinenc->tarkin_stream, data, 0, &date);
300 tarkinenc->frame_num++;
302 gst_buffer_unref (buf);
307 gst_tarkinenc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
309 TarkinEnc *tarkinenc;
311 /* it's not null if we got it, but it might not be ours */
312 g_return_if_fail (GST_IS_TARKINENC (object));
314 tarkinenc = GST_TARKINENC (object);
318 g_value_set_int (value, tarkinenc->bitrate);
321 g_value_set_int (value, tarkinenc->s_moments);
324 g_value_set_int (value, tarkinenc->a_moments);
332 gst_tarkinenc_set_property (GObject *object, guint prop_id, const GValue *value,
335 TarkinEnc *tarkinenc;
337 /* it's not null if we got it, but it might not be ours */
338 g_return_if_fail (GST_IS_TARKINENC (object));
340 tarkinenc = GST_TARKINENC (object);
344 tarkinenc->bitrate = g_value_get_int (value);
350 s_moments = g_value_get_int (value);
351 if (s_moments != 1 || s_moments != 2 || s_moments != 4) {
352 g_warning ("tarkinenc: s_moments must be 1, 2 or 4");
355 tarkinenc->s_moments = s_moments;
363 a_moments = g_value_get_int (value);
364 if (a_moments != 1 || a_moments != 2 || a_moments != 4) {
365 g_warning ("tarkinenc: a_moments must be 1, 2 or 4");
368 tarkinenc->a_moments = a_moments;