From f78820adc859cfc3ad90e1063da4ca908ea7bcf2 Mon Sep 17 00:00:00 2001 From: Thomas Vander Stichele Date: Sat, 1 Jun 2002 10:50:03 +0000 Subject: adding preliminary libfame plugin it's still too green to be useful, literally and needs some major fixing up Original commit message from CVS: adding preliminary libfame plugin it's still too green to be useful, literally and needs some major fixing up --- ext/libfame/Makefile.am | 9 + ext/libfame/gstlibfame.c | 441 +++++++++++++++++++++++++++++++++++++++++++++++ ext/libfame/gstlibfame.h | 85 +++++++++ 3 files changed, 535 insertions(+) create mode 100644 ext/libfame/Makefile.am create mode 100644 ext/libfame/gstlibfame.c create mode 100644 ext/libfame/gstlibfame.h diff --git a/ext/libfame/Makefile.am b/ext/libfame/Makefile.am new file mode 100644 index 00000000..e272082e --- /dev/null +++ b/ext/libfame/Makefile.am @@ -0,0 +1,9 @@ +plugindir = $(libdir)/gst + +plugin_LTLIBRARIES = libgstlibfame.la + +libgstlibfame_la_SOURCES = gstlibfame.c +libgstlibfame_la_CFLAGS = $(GST_CFLAGS) +libgstlibfame_la_LIBADD = $(LIBFAME_LIBS) +libgstlibfame_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + diff --git a/ext/libfame/gstlibfame.c b/ext/libfame/gstlibfame.c new file mode 100644 index 00000000..dd63a7b2 --- /dev/null +++ b/ext/libfame/gstlibfame.c @@ -0,0 +1,441 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include + +#include "gstlibfame.h" + +#define LIBFAME_BUFFER_SIZE (1024 * 1024) /* FIXME: do this properly */ + +/* elementfactory information */ +static GstElementDetails gst_libfame_details = { + "MPEG1 and MPEG4 video encoder using the libfame library", + "Codec/Video/Encoder", + "Uses libfame to encode MPEG video streams", + VERSION, + "(C) 1996, MPEG Software Simulation Group\n" + "Thomas Vander Stichele ", + "(C) 2002", +}; + +/* Libfame signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_VERSION, + ARG_FPS, + ARG_QUALITY, + ARG_BITRATE, + /* FILL ME */ +}; + +/* FIXME: either use or delete this */ +/* +static double video_rates[16] = +{ + 0.0, + 24000.0/1001., + 24.0, + 25.0, + 30000.0/1001., + 30.0, + 50.0, + 60000.0/1001., + 60.0, + 1, + 5, + 10, + 12, + 15, + 0, + 0 +}; +*/ + +GST_PAD_TEMPLATE_FACTORY (sink_template_factory, + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "libfame_sink_caps", + "video/raw", + "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')), + "width", GST_PROPS_INT_RANGE (16, 4096), + "height", GST_PROPS_INT_RANGE (16, 4096) + ) +) + +GST_PAD_TEMPLATE_FACTORY (src_template_factory, + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "libfame_src_caps", + "video/mpeg", + "mpegversion", GST_PROPS_LIST ( + GST_PROPS_INT (1), GST_PROPS_INT (4)), + "systemstream", GST_PROPS_BOOLEAN (FALSE) + ) +); + +static void gst_libfame_class_init (GstLibfameClass *klass); +static void gst_libfame_init (GstLibfame *libfame); +static void gst_libfame_dispose (GObject *object); + +static void gst_libfame_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec); +static void gst_libfame_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec); + +static void gst_libfame_chain (GstPad *pad, GstBuffer *buf); + +static GstElementClass *parent_class = NULL; +/*static guint gst_libfame_signals[LAST_SIGNAL] = { 0 };*/ + +GType +gst_libfame_get_type (void) +{ + static GType libfame_type = 0; + + if (!libfame_type) { + static const GTypeInfo libfame_info = { + sizeof (GstLibfameClass), + NULL, + NULL, + (GClassInitFunc) gst_libfame_class_init, + NULL, + NULL, + sizeof (GstLibfame), + 0, + (GInstanceInitFunc) gst_libfame_init, + }; + libfame_type = g_type_register_static (GST_TYPE_ELEMENT, + "GstLibfame", &libfame_info, 0); + } + return libfame_type; +} + +static void +gst_libfame_class_init (GstLibfameClass *klass) +{ + GObjectClass *gobject_class = NULL; + GstElementClass *gstelement_class = NULL; + + gobject_class = (GObjectClass*) klass; + gstelement_class = (GstElementClass*) klass; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + gobject_class->set_property = gst_libfame_set_property; + gobject_class->get_property = gst_libfame_get_property; + gobject_class->dispose = gst_libfame_dispose; + + g_object_class_install_property (gobject_class, ARG_VERSION, + g_param_spec_int ("mpeg_version", "MPEG Version", + "MPEG Codec Version (1 or 4)", + 1, 4, 1, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, ARG_FPS, + g_param_spec_double ("frames_per_second", "Frames per second", + "Number of frames per second", + -G_MAXDOUBLE, G_MAXDOUBLE, 25.0, G_PARAM_READWRITE)); +/* + g_object_class_install_property (gobject_class, ARG_BITRATE, + g_param_spec_int ("bitrate", "bitrate", "bitrate", + 0, 1500000, 10, G_PARAM_READWRITE)); */ + /* CHECKME */ + g_object_class_install_property (gobject_class, ARG_QUALITY, + g_param_spec_int ("quality", "Quality", + "Percentage of quality of compression (versus size)", + 0, 100, 75, G_PARAM_READWRITE)); /* CHECKME */ +} + +static GstPadConnectReturn +gst_libfame_sinkconnect (GstPad *pad, GstCaps *caps) +{ + gint width, height; + GstLibfame *libfame; + + libfame = GST_LIBFAME (gst_pad_get_parent (pad)); + + if (!GST_CAPS_IS_FIXED (caps)) + return GST_PAD_CONNECT_DELAYED; + + if (libfame->initialized) + { + GST_DEBUG(0, "error: libfame encoder already initialized !"); + return GST_PAD_CONNECT_REFUSED; + } + + gst_caps_get_int (caps, "width", &width); + gst_caps_get_int (caps, "height", &height); + + /* FIXME: do better error handling here */ + /* libfame requires width and height to be multiples of 16 */ + g_assert (width % 16 == 0); + g_assert (height % 16 == 0); + + libfame->fp.width = width; + libfame->fp.height = height; + libfame->fp.coding = "I"; + + /* FIXME: choose good parameters */ + libfame->fp.slices_per_frame = 1; + libfame->fp.frames_per_sequence = 0xffffffff; /* infinite */ + /* FIXME: 25 fps */ + libfame->fp.frame_rate_num = 25; + libfame->fp.frame_rate_den = 1; + + /* FIXME: handle these properly */ + libfame->fp.shape_quality = 100; + libfame->fp.search_range = 0; + libfame->fp.verbose = 1; + libfame->fp.profile = "mpeg1"; + libfame->fp.total_frames = 0; + libfame->fp.retrieve_cb = NULL; + + fame_init (libfame->fc, &libfame->fp, libfame->buffer, libfame->buffer_size); + + g_print ("libfame: init done.\n"); + g_assert (libfame->fc != NULL); /* FIXME */ + libfame->initialized = TRUE; + return GST_PAD_CONNECT_OK; +} + +static void +gst_libfame_init (GstLibfame *libfame) +{ + g_assert (libfame != NULL); + g_assert (GST_IS_LIBFAME (libfame)); + + /* open libfame */ + libfame->fc = fame_open (); + g_assert (libfame->fc != NULL); + + /* create the sink and src pads */ + libfame->sinkpad = gst_pad_new_from_template ( + GST_PAD_TEMPLATE_GET (sink_template_factory), "sink"); + gst_element_add_pad (GST_ELEMENT (libfame), libfame->sinkpad); + gst_pad_set_chain_function (libfame->sinkpad, gst_libfame_chain); + gst_pad_set_connect_function (libfame->sinkpad, gst_libfame_sinkconnect); + + libfame->srcpad = gst_pad_new_from_template ( + GST_PAD_TEMPLATE_GET (src_template_factory), "src"); + gst_element_add_pad (GST_ELEMENT (libfame), libfame->srcpad); + /* FIXME: set some more handler functions here */ + + /* reset the initial video state */ + libfame->width = -1; + libfame->height = -1; + libfame->initialized = FALSE; + + /* defaults */ + libfame->fp.quality = 75; + libfame->fp.frame_rate_num = 25; + libfame->fp.frame_rate_den = 1; /* avoid floating point exceptions */ + libfame->fp.profile = g_strdup_printf ("mpeg1"); + + /* allocate space for the buffer */ + libfame->buffer_size = LIBFAME_BUFFER_SIZE; /* FIXME */ + libfame->buffer = (unsigned char *) g_malloc (libfame->buffer_size); +} + +static void +gst_libfame_dispose (GObject *object) +{ + GstLibfame *libfame = GST_LIBFAME (object); + + G_OBJECT_CLASS (parent_class)->dispose (object); + + g_free (libfame->buffer); +} + +static void +gst_libfame_chain (GstPad *pad, GstBuffer *buf) +{ + GstLibfame *libfame = NULL; + guchar *data = NULL; + gulong size; + GstBuffer *outbuf = NULL; + int length; + + g_return_if_fail (pad != NULL); + g_return_if_fail (GST_IS_PAD (pad)); + g_return_if_fail (buf != NULL); + g_return_if_fail (GST_IS_BUFFER (buf)); + + libfame = GST_LIBFAME (gst_pad_get_parent (pad)); + + data = (guchar *) GST_BUFFER_DATA (buf); + size = GST_BUFFER_SIZE (buf); + GST_DEBUG (0,"gst_libfame_chain: got buffer of %ld bytes in '%s'", + size, GST_OBJECT_NAME (libfame)); + + /* the data contains the three planes side by side, with size w * h, w * h /4, + * w * h / 4 */ + libfame->fy.w = libfame->fp.width; + libfame->fy.h = libfame->fp.height; + libfame->fy.p = 0; /* FIXME: is this pointing to previous data ? */ + libfame->fy.y = data; + libfame->fy.u = data + libfame->width * libfame->height; + libfame->fy.v = data + 5 * libfame->width * libfame->height / 4; + fame_start_frame (libfame->fc, &libfame->fy, NULL); + + while ((length = fame_encode_slice (libfame->fc)) != 0) + { + outbuf = gst_buffer_new (); + + /* FIXME: safeguard, remove me when a better way is found */ + if (length > LIBFAME_BUFFER_SIZE) + g_warning ("LIBFAME_BUFFER_SIZE is defined too low, encoded slice has size %d !\n", length); + GST_BUFFER_SIZE (outbuf) = length; + GST_BUFFER_DATA (outbuf) = g_malloc (length); + memcpy (GST_BUFFER_DATA(outbuf), libfame->buffer, length); + GST_DEBUG (0,"gst_libfame_chain: pushing buffer of size %d", + GST_BUFFER_SIZE(outbuf)); + gst_pad_push (libfame->srcpad, outbuf); + gst_buffer_unref(buf); + } + + fame_end_frame (libfame->fc, NULL); /* FIXME: get stats */ +} + +static void +gst_libfame_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + GstLibfame *src; + + g_return_if_fail (GST_IS_LIBFAME (object)); + src = GST_LIBFAME (object); + + if (src->initialized) + { + GST_DEBUG(0, "error: libfame encoder already initialized, cannot set properties !"); + return; + } + + switch (prop_id) { + case ARG_VERSION: + { + int version = g_value_get_int (value); + if (version != 1 && version != 4) + { + g_warning ("libfame: only use MPEG version 1 or 4 !"); + break; + } + /* + if (src->fp.profile) + { g_free (src->fp.profile); src->fp.profile = NULL; } + src->fp.profile = g_strdup_printf ("mpeg%d", version); + */ + /* FIXME: this should be done using fame_register */ + break; + } + case ARG_FPS: + /* FIXME: we could do a much better job of finding num and den here */ + src->fp.frame_rate_num = g_value_get_double (value); + src->fp.frame_rate_den = 1; + gst_info ("libfame: setting framerate for encoding to %f (%d/%d)\n", + (float) src->fp.frame_rate_num / src->fp.frame_rate_den, + src->fp.frame_rate_num, src->fp.frame_rate_den); + break; + + case ARG_QUALITY: + { + int quality; + + quality = g_value_get_int (value); + /* quality is a percentage */ + if (quality < 0) quality = 0; + if (quality > 100) quality = 100; + src->fp.quality = quality; + gst_info ("libfame: setting quality for encoding to %d\n", quality); + g_warning ("libfame: setting quality for encoding to %d\n", quality); + break; + } + case ARG_BITRATE: + g_warning ("bitrate not implemented yet !\n"); + /* + src->encoder->seq.bit_rate = g_value_get_int (value); + */ + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_libfame_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + GstLibfame *src; + + g_return_if_fail (GST_IS_LIBFAME (object)); + src = GST_LIBFAME (object); + + switch (prop_id) { + case ARG_FPS: + g_value_set_double (value, (src->fp.frame_rate_num / + src->fp.frame_rate_den)); + break; + case ARG_QUALITY: + g_value_set_int (value, src->fp.quality); + break; + case ARG_BITRATE: + g_warning ("You think you WANT to know bitrate ? Think AGAIN !\n"); + /* g_value_set_int (value, src->encoder->seq.bit_rate); */ + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + + /* create an elementfactory for the libfame element */ + factory = gst_element_factory_new ("libfame", GST_TYPE_LIBFAME, + &gst_libfame_details); + g_return_val_if_fail (factory != NULL, FALSE); + + gst_element_factory_add_pad_template (factory, + GST_PAD_TEMPLATE_GET (sink_template_factory)); + gst_element_factory_add_pad_template (factory, + GST_PAD_TEMPLATE_GET (src_template_factory)); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "libfame", + plugin_init +}; diff --git a/ext/libfame/gstlibfame.h b/ext/libfame/gstlibfame.h new file mode 100644 index 00000000..f56f651d --- /dev/null +++ b/ext/libfame/gstlibfame.h @@ -0,0 +1,85 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_LIBFAME_H__ +#define __GST_LIBFAME_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_LIBFAME \ + (gst_libfame_get_type()) +#define GST_LIBFAME(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_LIBFAME,GstLibfame)) +#define GST_LIBFAME_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_LIBFAME,GstLibfame)) +#define GST_IS_LIBFAME(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_LIBFAME)) +#define GST_IS_LIBFAME_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_LIBFAME)) + +typedef struct _GstLibfame GstLibfame; +typedef struct _GstLibfameClass GstLibfameClass; + +struct _GstLibfame { + GstElement element; + + /* pads */ + GstPad *sinkpad, *srcpad; + + /* the timestamp of the next frame */ + guint64 next_time; + /* the interval between frames */ + guint64 time_interval; + + /* video state */ + gint format; + gint width; + gint height; + /* the size of the output buffer */ + gint outsize; + + /* libfame stuff */ + fame_context_t *fc; + fame_parameters_t fp; + fame_yuv_t fy; + gulong buffer_size; + unsigned char *buffer; + gboolean initialized; +}; + +struct _GstLibfameClass { + GstElementClass parent_class; +}; + +GType gst_libfame_get_type (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_LIBFAME_H__ */ -- cgit v1.2.1