1 /* GStreamer xvid encoder plugin
2 * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
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.
28 #include "gstxvidenc.h"
29 #include <gst/video/video.h>
32 /* elementfactory information */
33 GstElementDetails gst_xvidenc_details = {
35 "Codec/Video/Encoder",
37 "Xvid encoder based on xvidencore",
39 "Ronald Bultje <rbultje@ronald.bitfreak.net>",
43 GST_PAD_TEMPLATE_FACTORY(sink_template,
47 GST_CAPS_NEW("xvidenc_sink",
49 "format", GST_PROPS_LIST(
50 GST_PROPS_FOURCC(GST_MAKE_FOURCC('R','G','B',' ')),
51 GST_PROPS_FOURCC(GST_MAKE_FOURCC('I','4','2','0')),
52 GST_PROPS_FOURCC(GST_MAKE_FOURCC('I','Y','U','V')),
53 GST_PROPS_FOURCC(GST_MAKE_FOURCC('Y','U','Y','2')),
54 GST_PROPS_FOURCC(GST_MAKE_FOURCC('Y','V','1','2')),
55 GST_PROPS_FOURCC(GST_MAKE_FOURCC('Y','V','Y','U')),
56 GST_PROPS_FOURCC(GST_MAKE_FOURCC('U','Y','V','Y'))
58 "width", GST_PROPS_INT_RANGE(0, G_MAXINT),
59 "height", GST_PROPS_INT_RANGE(0, G_MAXINT),
63 GST_PAD_TEMPLATE_FACTORY(src_template,
67 GST_CAPS_NEW("xvidenc_src",
73 /* XvidEnc signals and args */
87 static void gst_xvidenc_class_init (GstXvidEncClass *klass);
88 static void gst_xvidenc_init (GstXvidEnc *xvidenc);
89 static void gst_xvidenc_chain (GstPad *pad,
91 static GstPadLinkReturn gst_xvidenc_connect (GstPad *pad,
95 static void gst_xvidenc_set_property (GObject *object,
99 static void gst_xvidenc_get_property (GObject *object,
104 static GstElementClass *parent_class = NULL;
105 static guint gst_xvidenc_signals[LAST_SIGNAL] = { 0 };
109 gst_xvidenc_get_type(void)
111 static GType xvidenc_type = 0;
115 static const GTypeInfo xvidenc_info = {
116 sizeof(GstXvidEncClass),
119 (GClassInitFunc) gst_xvidenc_class_init,
124 (GInstanceInitFunc) gst_xvidenc_init,
126 xvidenc_type = g_type_register_static(GST_TYPE_ELEMENT,
135 gst_xvidenc_class_init (GstXvidEncClass *klass)
137 GstElementClass *gstelement_class;
138 GObjectClass *gobject_class;
140 gobject_class = (GObjectClass *) klass;
141 gstelement_class = (GstElementClass *) klass;
143 parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
145 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BITRATE,
146 g_param_spec_ulong("bitrate","Bitrate",
147 "Target video bitrate",
148 0,G_MAXULONG,0,G_PARAM_READWRITE));
150 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MAXKEYINTERVAL,
151 g_param_spec_int("max_key_interval","Max. Key Interval",
152 "Maximum number of frames between two keyframes",
153 0,G_MAXINT,0,G_PARAM_READWRITE));
155 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFSIZE,
156 g_param_spec_ulong("buffer_size", "Buffer Size",
157 "Size of the video buffers",
158 0,G_MAXULONG,0,G_PARAM_READWRITE));
160 gobject_class->set_property = gst_xvidenc_set_property;
161 gobject_class->get_property = gst_xvidenc_get_property;
163 gst_xvidenc_signals[FRAME_ENCODED] =
164 g_signal_new ("frame_encoded", G_TYPE_FROM_CLASS(klass),
166 G_STRUCT_OFFSET (GstXvidEncClass, frame_encoded),
168 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
173 gst_xvidenc_init (GstXvidEnc *xvidenc)
175 /* create the sink pad */
176 xvidenc->sinkpad = gst_pad_new_from_template(
177 GST_PAD_TEMPLATE_GET(sink_template),
179 gst_element_add_pad(GST_ELEMENT(xvidenc), xvidenc->sinkpad);
181 gst_pad_set_chain_function(xvidenc->sinkpad, gst_xvidenc_chain);
182 gst_pad_set_link_function(xvidenc->sinkpad, gst_xvidenc_connect);
184 /* create the src pad */
185 xvidenc->srcpad = gst_pad_new_from_template(
186 GST_PAD_TEMPLATE_GET(src_template),
188 gst_element_add_pad(GST_ELEMENT(xvidenc), xvidenc->srcpad);
191 xvidenc->width = xvidenc->height = xvidenc->csp = -1;
192 xvidenc->bitrate = 512 * 1024;
193 xvidenc->max_key_interval = -1; /* default - 2*fps */
194 xvidenc->buffer_size = 512 * 1024;
196 /* set xvid handle to NULL */
197 xvidenc->handle = NULL;
202 gst_xvidenc_setup (GstXvidEnc *xvidenc)
208 fps = gst_video_frame_rate(GST_PAD_PEER(xvidenc->sinkpad));
210 /* set up xvid codec parameters - grab docs from
211 * xvid.org for more info */
212 memset(&xenc, 0, sizeof(XVID_ENC_PARAM));
213 xenc.width = xvidenc->width;
214 xenc.height = xvidenc->height;
215 xenc.fincr = (int)(fps * 1000);
217 xenc.rc_bitrate = xvidenc->bitrate;
218 xenc.rc_reaction_delay_factor = -1;
219 xenc.rc_averaging_period = -1;
221 xenc.min_quantizer = 1;
222 xenc.max_quantizer = 31;
223 xenc.max_key_interval = (xvidenc->max_key_interval == -1) ?
224 (2 * xenc.fincr / xenc.fbase) :
225 xvidenc->max_key_interval;
228 if ((ret = xvid_encore(NULL, XVID_ENC_CREATE,
229 &xenc, NULL)) != XVID_ERR_OK) {
230 gst_element_error(GST_ELEMENT(xvidenc),
231 "Error setting up xvid encoder: %s (%d)",
232 gst_xvid_error(ret), ret);
236 xvidenc->handle = xenc.handle;
243 gst_xvidenc_chain (GstPad *pad,
248 XVID_ENC_FRAME xframe;
251 g_return_if_fail(pad != NULL);
252 g_return_if_fail(GST_IS_PAD(pad));
253 g_return_if_fail(buf != NULL);
255 xvidenc = GST_XVIDENC(GST_OBJECT_PARENT(pad));
257 if (!xvidenc->handle) {
258 if (!gst_xvidenc_setup(xvidenc)) {
259 gst_buffer_unref(buf);
264 outbuf = gst_buffer_new_and_alloc(xvidenc->buffer_size);
265 GST_BUFFER_TIMESTAMP(outbuf) = GST_BUFFER_TIMESTAMP(buf);
267 /* encode and so ... */
268 xframe.image = GST_BUFFER_DATA(buf);
269 xframe.bitstream = (void *) GST_BUFFER_DATA(outbuf);
270 xframe.length = GST_BUFFER_MAXSIZE(outbuf);
273 xframe.colorspace = xvidenc->csp;
274 xframe.general = XVID_H263QUANT |
277 xframe.motion = PMV_EARLYSTOP16 |
278 PMV_HALFPELREFINE16 |
283 if ((ret = xvid_encore(xvidenc->handle, XVID_ENC_ENCODE,
284 &xframe, NULL)) != XVID_ERR_OK) {
285 gst_element_error(GST_ELEMENT(xvidenc),
286 "Error encoding xvid frame: %s (%d)",
287 gst_xvid_error(ret), ret);
288 gst_buffer_unref(buf);
292 GST_BUFFER_SIZE(outbuf) = xframe.length;
294 GST_BUFFER_FLAG_SET(outbuf, GST_BUFFER_KEY_UNIT);
296 /* go out, multiply! */
297 gst_pad_push(xvidenc->srcpad, outbuf);
299 /* proclaim destiny */
300 g_signal_emit(G_OBJECT(xvidenc),gst_xvidenc_signals[FRAME_ENCODED], 0);
302 /* until the final judgement */
303 gst_buffer_unref(buf);
307 static GstPadLinkReturn
308 gst_xvidenc_connect (GstPad *pad,
314 xvidenc = GST_XVIDENC(gst_pad_get_parent (pad));
316 /* if there's something old around, remove it */
317 if (xvidenc->handle) {
318 xvid_encore(xvidenc->handle, XVID_ENC_DESTROY, NULL, NULL);
319 xvidenc->handle = NULL;
322 /* we are not going to act on variable caps */
323 if (!GST_CAPS_IS_FIXED(vscaps))
324 return GST_PAD_LINK_DELAYED;
326 for (caps = vscaps; caps != NULL; caps = caps->next)
331 gst_caps_get_int(caps, "width", &w);
332 gst_caps_get_int(caps, "height", &h);
333 gst_caps_get_fourcc_int(caps, "format", &fourcc);
337 case GST_MAKE_FOURCC('I','4','2','0'):
338 case GST_MAKE_FOURCC('I','Y','U','V'):
339 xvid_cs = XVID_CSP_I420;
341 case GST_MAKE_FOURCC('Y','U','Y','2'):
342 xvid_cs = XVID_CSP_YUY2;
344 case GST_MAKE_FOURCC('Y','V','1','2'):
345 xvid_cs = XVID_CSP_YV12;
347 case GST_MAKE_FOURCC('U','Y','V','Y'):
348 xvid_cs = XVID_CSP_UYVY;
350 case GST_MAKE_FOURCC('Y','V','Y','U'):
351 xvid_cs = XVID_CSP_YVYU;
353 case GST_MAKE_FOURCC('R','G','B',' '):
354 gst_caps_get_int(caps, "depth", &d);
357 xvid_cs = XVID_CSP_RGB555;
360 xvid_cs = XVID_CSP_RGB565;
363 xvid_cs = XVID_CSP_RGB24;
366 xvid_cs = XVID_CSP_RGB32;
376 /* grmbl, we only know the peer pad *after*
377 * linking, so we accept here, get the fps on
378 * the first cycle and set it all up then */
379 xvidenc->csp = xvid_cs;
382 return gst_pad_try_set_caps(xvidenc->srcpad,
383 GST_CAPS_NEW("xvidenc_src_caps",
385 "width", GST_PROPS_INT(w),
386 "height", GST_PROPS_INT(h)));
392 /* if we got here - it's not good */
393 return GST_PAD_LINK_REFUSED;
398 gst_xvidenc_set_property (GObject *object,
405 /* it's not null if we got it, but it might not be ours */
406 g_return_if_fail (GST_IS_XVIDENC (object));
407 xvidenc = GST_XVIDENC(object);
412 xvidenc->bitrate = g_value_get_ulong(value);
415 xvidenc->buffer_size = g_value_get_ulong(value);
417 case ARG_MAXKEYINTERVAL:
418 xvidenc->max_key_interval = g_value_get_int(value);
421 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
428 gst_xvidenc_get_property (GObject *object,
435 /* it's not null if we got it, but it might not be ours */
436 g_return_if_fail (GST_IS_XVIDENC (object));
437 xvidenc = GST_XVIDENC(object);
441 g_value_set_ulong(value, xvidenc->bitrate);
444 g_value_set_ulong(value, xvidenc->buffer_size);
446 case ARG_MAXKEYINTERVAL:
447 g_value_set_int(value, xvidenc->max_key_interval);
450 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
457 gst_xvidenc_plugin_init (GModule *module,
460 GstElementFactory *factory;
462 if (!gst_library_load("gstvideo"))
465 /* create an elementfactory for the v4lmjpegsrcparse element */
466 factory = gst_element_factory_new("xvidenc", GST_TYPE_XVIDENC,
467 &gst_xvidenc_details);
468 g_return_val_if_fail(factory != NULL, FALSE);
470 /* add pad templates */
471 gst_element_factory_add_pad_template(factory,
472 GST_PAD_TEMPLATE_GET(sink_template));
473 gst_element_factory_add_pad_template(factory,
474 GST_PAD_TEMPLATE_GET(src_template));
476 gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));