From 57ce0321c8971f964008920003a3e8b19649df85 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 3 Feb 2002 16:30:31 +0000 Subject: Added a tarkin encoder/decoder plugin. Original commit message from CVS: Added a tarkin encoder/decoder plugin. I moved the tarking CVS code in here temporarily until they have a library (hence this plugin is in ext) test with: ./gst-launch filesrc location=/opt/data/shihad.mpg ! mpegdemux video_00! { queue ! mpeg2dec ! colorspace ! tarkinenc bitrate=3000 ! disksink location=out.ogg } ./gst-launch filesrc location=out.ogg ! tarkindec ! colorspace ! xvideosink --- ext/tarkin/gsttarkinenc.c | 371 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 ext/tarkin/gsttarkinenc.c (limited to 'ext/tarkin/gsttarkinenc.c') diff --git a/ext/tarkin/gsttarkinenc.c b/ext/tarkin/gsttarkinenc.c new file mode 100644 index 00000000..8042430a --- /dev/null +++ b/ext/tarkin/gsttarkinenc.c @@ -0,0 +1,371 @@ +/* Gnome-Streamer + * 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 "gsttarkinenc.h" + +extern GstPadTemplate *enc_src_template, *enc_sink_template; + +/* elementfactory information */ +GstElementDetails tarkinenc_details = { + "Ogg Tarkin encoder", + "Filter/Video/Encoder", + "Encodes video in OGG Tarkin format", + VERSION, + "Monty , " + "Wim Taymans ", + "(C) 2002", +}; + +/* TarkinEnc signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + ARG_0, + ARG_BITRATE, + ARG_S_MOMENTS, + ARG_A_MOMENTS, +}; + +static void gst_tarkinenc_class_init (TarkinEncClass *klass); +static void gst_tarkinenc_init (TarkinEnc *arkinenc); + +static void gst_tarkinenc_chain (GstPad *pad, GstBuffer *buf); +static void gst_tarkinenc_setup (TarkinEnc *tarkinenc); + +static void gst_tarkinenc_get_property (GObject *object, guint prop_id, GValue *value, + GParamSpec *pspec); +static void gst_tarkinenc_set_property (GObject *object, guint prop_id, const GValue *value, + GParamSpec *pspec); + +static GstElementClass *parent_class = NULL; +/*static guint gst_tarkinenc_signals[LAST_SIGNAL] = { 0 }; */ + +GType +tarkinenc_get_type (void) +{ + static GType tarkinenc_type = 0; + + if (!tarkinenc_type) { + static const GTypeInfo tarkinenc_info = { + sizeof (TarkinEncClass), + NULL, + NULL, + (GClassInitFunc) gst_tarkinenc_class_init, + NULL, + NULL, + sizeof (TarkinEnc), + 0, + (GInstanceInitFunc) gst_tarkinenc_init, + }; + + tarkinenc_type = g_type_register_static (GST_TYPE_ELEMENT, "TarkinEnc", &tarkinenc_info, 0); + } + return tarkinenc_type; +} + +static void +gst_tarkinenc_class_init (TarkinEncClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE, + g_param_spec_int ("bitrate", "bitrate", "bitrate", + G_MININT, G_MAXINT, 3000, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_S_MOMENTS, + g_param_spec_int ("s_moments", "Synthesis Moments", + "Number of vanishing moments for the synthesis filter", + 1, 4, 2, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_A_MOMENTS, + g_param_spec_int ("a_moments", "Analysis Moments", + "Number of vanishing moments for the analysis filter", + 1, 4, 2, G_PARAM_READWRITE)); + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + gobject_class->set_property = gst_tarkinenc_set_property; + gobject_class->get_property = gst_tarkinenc_get_property; +} + +static GstPadConnectReturn +gst_tarkinenc_sinkconnect (GstPad *pad, GstCaps *caps) +{ + TarkinEnc *tarkinenc; + + tarkinenc = GST_TARKINENC (gst_pad_get_parent (pad)); + + if (!GST_CAPS_IS_FIXED (caps)) + return GST_PAD_CONNECT_DELAYED; + + gst_caps_debug (caps); + + tarkinenc->layer[0].bitstream_len = tarkinenc->bitrate; + tarkinenc->layer[0].a_moments = tarkinenc->a_moments; + tarkinenc->layer[0].s_moments = tarkinenc->s_moments; + tarkinenc->layer[0].width = gst_caps_get_int (caps, "width"); + tarkinenc->layer[0].height = gst_caps_get_int (caps, "height"); + tarkinenc->layer[0].format = TARKIN_RGB24; + tarkinenc->layer[0].frames_per_buf = TARKIN_RGB24; + + gst_tarkinenc_setup (tarkinenc); + + if (tarkinenc->setup) + return GST_PAD_CONNECT_OK; + + return GST_PAD_CONNECT_REFUSED; +} + +static void +gst_tarkinenc_init (TarkinEnc * tarkinenc) +{ + tarkinenc->sinkpad = gst_pad_new_from_template (enc_sink_template, "sink"); + gst_element_add_pad (GST_ELEMENT (tarkinenc), tarkinenc->sinkpad); + gst_pad_set_chain_function (tarkinenc->sinkpad, gst_tarkinenc_chain); + gst_pad_set_connect_function (tarkinenc->sinkpad, gst_tarkinenc_sinkconnect); + + tarkinenc->srcpad = gst_pad_new_from_template (enc_src_template, "src"); + gst_element_add_pad (GST_ELEMENT (tarkinenc), tarkinenc->srcpad); + + tarkinenc->bitrate = 3000; + tarkinenc->s_moments = 2; + tarkinenc->a_moments = 2; + tarkinenc->setup = FALSE; +} + +TarkinError free_frame (void *s, void *ptr) +{ + return(TARKIN_OK); +} + +TarkinError packet_out (void *stream, ogg_packet *op) +{ + ogg_page og; + TarkinStream *s = stream; + TarkinEnc *te = s->user_ptr; + GstBuffer *outbuf; + + ogg_stream_packetin (&te->os, op); + + if(op->e_o_s){ + ogg_stream_flush (&te->os, &og); + outbuf = gst_buffer_new (); + GST_BUFFER_DATA (outbuf) = og.header; + GST_BUFFER_SIZE (outbuf) = og.header_len; + GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DONTFREE); + gst_pad_push (te->srcpad, outbuf); + outbuf = gst_buffer_new (); + GST_BUFFER_DATA (outbuf) = og.body; + GST_BUFFER_SIZE (outbuf) = og.body_len; + GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DONTFREE); + gst_pad_push (te->srcpad, outbuf); + } else { + while (ogg_stream_pageout (&te->os, &og)){ + outbuf = gst_buffer_new (); + GST_BUFFER_DATA (outbuf) = og.header; + GST_BUFFER_SIZE (outbuf) = og.header_len; + GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DONTFREE); + gst_pad_push (te->srcpad, outbuf); + outbuf = gst_buffer_new (); + GST_BUFFER_DATA (outbuf) = og.body; + GST_BUFFER_SIZE (outbuf) = og.body_len; + GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DONTFREE); + gst_pad_push (te->srcpad, outbuf); + } + } + return (TARKIN_OK); +} + + +static void +gst_tarkinenc_setup (TarkinEnc *tarkinenc) +{ + gint i; + GstBuffer *outbuf; + + ogg_stream_init (&tarkinenc->os, 1); + tarkin_info_init (&tarkinenc->ti); + + tarkinenc->ti.inter.numerator = 1; + tarkinenc->ti.inter.denominator = 1; + + tarkin_comment_init (&tarkinenc->tc); + tarkin_comment_add_tag (&tarkinenc->tc, "TITLE", "GStreamer produced file"); + tarkin_comment_add_tag (&tarkinenc->tc, "ARTIST", "C coders ;)"); + + tarkinenc->tarkin_stream = tarkin_stream_new (); + tarkin_analysis_init (tarkinenc->tarkin_stream, + &tarkinenc->ti, free_frame, packet_out, (void*)tarkinenc); + tarkin_analysis_add_layer(tarkinenc->tarkin_stream, &tarkinenc->layer[0]); + + tarkin_analysis_headerout (tarkinenc->tarkin_stream, &tarkinenc->tc, + tarkinenc->op, &tarkinenc->op[1], &tarkinenc->op[2]); + for(i = 0; i < 3; i++){ + ogg_stream_packetin(&tarkinenc->os, &tarkinenc->op[i]); + } + + ogg_stream_flush (&tarkinenc->os, &tarkinenc->og); + + tarkinenc->frame_num = 0; + + outbuf = gst_buffer_new (); + GST_BUFFER_DATA (outbuf) = tarkinenc->og.header; + GST_BUFFER_SIZE (outbuf) = tarkinenc->og.header_len; + GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DONTFREE); + gst_pad_push (tarkinenc->srcpad, outbuf); + + outbuf = gst_buffer_new (); + GST_BUFFER_DATA (outbuf) = tarkinenc->og.body; + GST_BUFFER_SIZE (outbuf) = tarkinenc->og.body_len; + GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DONTFREE); + gst_pad_push (tarkinenc->srcpad, outbuf); + + tarkinenc->setup = TRUE; +} + +static void +gst_tarkinenc_chain (GstPad *pad, GstBuffer *buf) +{ + TarkinEnc *tarkinenc; + + g_return_if_fail (pad != NULL); + g_return_if_fail (GST_IS_PAD (pad)); + g_return_if_fail (buf != NULL); + + tarkinenc = GST_TARKINENC (gst_pad_get_parent (pad)); + + if (!tarkinenc->setup) { + gst_element_error (GST_ELEMENT (tarkinenc), "encoder not initialized (input is not audio?)"); + if (GST_IS_BUFFER (buf)) + gst_buffer_unref (buf); + else + gst_pad_event_default (pad, GST_EVENT (buf)); + return; + } + + if (GST_IS_EVENT (buf)) { + switch (GST_EVENT_TYPE (buf)) { + case GST_EVENT_EOS: + tarkin_analysis_framein (tarkinenc->tarkin_stream, NULL, 0, NULL); /* EOS */ + tarkin_comment_clear (&tarkinenc->tc); + tarkin_stream_destroy (tarkinenc->tarkin_stream); + default: + gst_pad_event_default (pad, GST_EVENT (buf)); + break; + } + } + else { + gchar *data; + gulong size; + TarkinTime date; + + /* data to encode */ + data = GST_BUFFER_DATA (buf); + size = GST_BUFFER_SIZE (buf); + + date.numerator = tarkinenc->frame_num; + date.denominator = 1; + tarkin_analysis_framein (tarkinenc->tarkin_stream, data, 0, &date); + tarkinenc->frame_num++; + + gst_buffer_unref (buf); + } +} + +static void +gst_tarkinenc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + TarkinEnc *tarkinenc; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_TARKINENC (object)); + + tarkinenc = GST_TARKINENC (object); + + switch (prop_id) { + case ARG_BITRATE: + g_value_set_int (value, tarkinenc->bitrate); + break; + case ARG_S_MOMENTS: + g_value_set_int (value, tarkinenc->s_moments); + break; + case ARG_A_MOMENTS: + g_value_set_int (value, tarkinenc->a_moments); + break; + default: + break; + } +} + +static void +gst_tarkinenc_set_property (GObject *object, guint prop_id, const GValue *value, + GParamSpec *pspec) +{ + TarkinEnc *tarkinenc; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_TARKINENC (object)); + + tarkinenc = GST_TARKINENC (object); + + switch (prop_id) { + case ARG_BITRATE: + tarkinenc->bitrate = g_value_get_int (value); + break; + case ARG_S_MOMENTS: + { + gint s_moments; + + s_moments = g_value_get_int (value); + if (s_moments != 1 || s_moments != 2 || s_moments != 4) { + g_warning ("tarkinenc: s_moments must be 1, 2 or 4"); + } + else { + tarkinenc->s_moments = s_moments; + } + break; + } + case ARG_A_MOMENTS: + { + gint a_moments; + + a_moments = g_value_get_int (value); + if (a_moments != 1 || a_moments != 2 || a_moments != 4) { + g_warning ("tarkinenc: a_moments must be 1, 2 or 4"); + } + else { + tarkinenc->a_moments = a_moments; + } + break; + } + default: + break; + } +} -- cgit v1.2.1