From ef3ed344af7d0eb330f68c85d31acfa9471d1573 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Thu, 18 Dec 2003 09:49:50 +0000 Subject: Merge HEAD from CAPS-ROOT to CAPS-MERGE-3 Original commit message from CVS: Merge HEAD from CAPS-ROOT to CAPS-MERGE-3 --- ext/Makefile.am | 8 + ext/arts/gst_arts.c | 1 - ext/artsd/gstartsdsink.c | 1 - ext/audiofile/gstaf.c | 1 - ext/divx/gstdivxdec.c | 1 - ext/divx/gstdivxenc.c | 1 - ext/faac/gstfaac.c | 1 - ext/faad/gstfaad.c | 1 - ext/gsm/gstgsm.c | 1 - ext/hermes/gstcolorspace.c | 1 - ext/ivorbis/vorbis.c | 1 - ext/jack/gstjack.c | 1 - ext/jack/gstjackbin.c | 2 +- ext/ladspa/gstladspa.c | 15 +- ext/libfame/gstlibfame.c | 1 - ext/mas/massink.c | 1 - ext/mpeg2enc/Makefile.am | 18 + ext/mpeg2enc/gstmpeg2enc.cc | 319 +++++++ ext/mpeg2enc/gstmpeg2enc.hh | 63 ++ ext/mpeg2enc/gstmpeg2encoder.cc | 95 ++ ext/mpeg2enc/gstmpeg2encoder.hh | 44 + ext/mpeg2enc/gstmpeg2encoptions.cc | 703 ++++++++++++++ ext/mpeg2enc/gstmpeg2encoptions.hh | 42 + ext/mpeg2enc/gstmpeg2encpicturereader.cc | 129 +++ ext/mpeg2enc/gstmpeg2encpicturereader.hh | 49 + ext/mpeg2enc/gstmpeg2encstreamwriter.cc | 99 ++ ext/mpeg2enc/gstmpeg2encstreamwriter.hh | 45 + ext/mplex/gstmplex.cc | 1 - ext/sdl/sdlvideosink.c | 15 +- ext/shout/gstshout.c | 1 - ext/smoothwave/gstsmoothwave.c | 1 - ext/snapshot/gstsnapshot.c | 1 - ext/sndfile/gstsf.c | 1 - ext/swfdec/gstswfdec.c | 1 - ext/tarkin/gsttarkin.c | 1 - ext/xvid/gstxvid.c | 1 - gst-libs/gst/Makefile.am | 18 +- gst-libs/gst/audio/audio.c | 1 - gst-libs/gst/audio/audioclock.h | 4 +- gst-libs/gst/audio/gstaudiofilter.c | 2 +- gst-libs/gst/audio/gstaudiofilterexample.c | 1 - gst-libs/gst/colorbalance/Makefile.am | 22 +- gst-libs/gst/colorbalance/colorbalance.c | 37 +- gst-libs/gst/colorbalance/colorbalance.h | 18 +- gst-libs/gst/colorbalance/colorbalancechannel.c | 3 +- gst-libs/gst/colorbalance/colorbalancechannel.h | 2 + gst-libs/gst/colorbalance/colorbalancemarshal.list | 1 + gst-libs/gst/idct/idct.c | 1 - gst-libs/gst/media-info/media-info.h | 4 +- gst-libs/gst/mixer/Makefile.am | 22 +- gst-libs/gst/mixer/mixer.c | 82 +- gst-libs/gst/mixer/mixer.h | 54 +- gst-libs/gst/mixer/mixermarshal.list | 2 + gst-libs/gst/mixer/mixertrack.h | 7 +- gst-libs/gst/navigation/navigation.h | 2 +- gst-libs/gst/play/Makefile.am | 8 +- gst-libs/gst/play/gstplay.c | 1004 ++++++++++++++++++++ gst-libs/gst/play/gstplay.h | 89 ++ gst-libs/gst/play/play.c | 1004 ++++++++++++++++++++ gst-libs/gst/play/play.h | 89 ++ gst-libs/gst/play/play.old.h | 4 +- gst-libs/gst/propertyprobe/propertyprobe.h | 2 +- gst-libs/gst/resample/resample.c | 1 - gst-libs/gst/riff/Makefile.am | 11 +- gst-libs/gst/riff/riff-ids.h | 319 +++++++ gst-libs/gst/riff/riff-media.c | 369 +++++++ gst-libs/gst/riff/riff-media.h | 55 ++ gst-libs/gst/riff/riff-read.c | 868 +++++++++++++++++ gst-libs/gst/riff/riff-read.h | 100 ++ gst-libs/gst/riff/riff.c | 17 +- gst-libs/gst/riff/riff.h | 448 --------- gst-libs/gst/riff/riffencode.c | 181 ---- gst-libs/gst/riff/riffparse.c | 250 ----- gst-libs/gst/riff/riffutil.c | 47 - gst-libs/gst/tag/Makefile.am | 5 + gst-libs/gst/tag/tag.h | 62 ++ gst-libs/gst/tuner/Makefile.am | 21 +- gst-libs/gst/tuner/tuner.c | 94 +- gst-libs/gst/tuner/tuner.h | 30 +- gst-libs/gst/tuner/tunerchannel.h | 6 +- gst-libs/gst/tuner/tunermarshal.list | 2 + gst-libs/gst/tuner/tunernorm.h | 2 + gst-libs/gst/video/gstvideosink.h | 4 +- gst-libs/gst/video/video.c | 1 - gst-libs/gst/video/videosink.h | 4 +- gst-libs/gst/xoverlay/xoverlay.c | 5 +- gst-libs/gst/xoverlay/xoverlay.h | 7 +- gst-libs/gst/xwindowlistener/xwindowlistener.c | 1 - gst/smoothwave/gstsmoothwave.c | 1 - 89 files changed, 6021 insertions(+), 1040 deletions(-) create mode 100644 ext/mpeg2enc/Makefile.am create mode 100644 ext/mpeg2enc/gstmpeg2enc.cc create mode 100644 ext/mpeg2enc/gstmpeg2enc.hh create mode 100644 ext/mpeg2enc/gstmpeg2encoder.cc create mode 100644 ext/mpeg2enc/gstmpeg2encoder.hh create mode 100644 ext/mpeg2enc/gstmpeg2encoptions.cc create mode 100644 ext/mpeg2enc/gstmpeg2encoptions.hh create mode 100644 ext/mpeg2enc/gstmpeg2encpicturereader.cc create mode 100644 ext/mpeg2enc/gstmpeg2encpicturereader.hh create mode 100644 ext/mpeg2enc/gstmpeg2encstreamwriter.cc create mode 100644 ext/mpeg2enc/gstmpeg2encstreamwriter.hh create mode 100644 gst-libs/gst/colorbalance/colorbalancemarshal.list create mode 100644 gst-libs/gst/mixer/mixermarshal.list create mode 100644 gst-libs/gst/play/gstplay.c create mode 100644 gst-libs/gst/play/gstplay.h create mode 100644 gst-libs/gst/play/play.c create mode 100644 gst-libs/gst/play/play.h create mode 100644 gst-libs/gst/riff/riff-ids.h create mode 100644 gst-libs/gst/riff/riff-media.c create mode 100644 gst-libs/gst/riff/riff-media.h create mode 100644 gst-libs/gst/riff/riff-read.c create mode 100644 gst-libs/gst/riff/riff-read.h delete mode 100644 gst-libs/gst/riff/riff.h delete mode 100644 gst-libs/gst/riff/riffencode.c delete mode 100644 gst-libs/gst/riff/riffparse.c delete mode 100644 gst-libs/gst/riff/riffutil.c create mode 100644 gst-libs/gst/tag/Makefile.am create mode 100644 gst-libs/gst/tag/tag.h create mode 100644 gst-libs/gst/tuner/tunermarshal.list diff --git a/ext/Makefile.am b/ext/Makefile.am index a26660d71..cdcfefe7e 100644 --- a/ext/Makefile.am +++ b/ext/Makefile.am @@ -190,6 +190,12 @@ else MPEG2DEC_DIR= endif +if USE_MPEG2ENC +MPEG2ENC_DIR=mpeg2enc +else +MPEG2ENC_DIR= +endif + if USE_MPLEX MPLEX_DIR=mplex else @@ -318,6 +324,7 @@ SUBDIRS=\ $(MAS_DIR) \ $(MIKMOD_DIR) \ $(MPEG2DEC_DIR) \ + $(MPEG2ENC_DIR) \ $(MPLEX_DIR) \ $(OGG_DIR) \ $(PANGO_DIR) \ @@ -367,6 +374,7 @@ DIST_SUBDIRS=\ mad \ mikmod \ mpeg2dec \ + mpeg2enc \ mplex \ ogg \ pango \ diff --git a/ext/arts/gst_arts.c b/ext/arts/gst_arts.c index 85e31e1aa..196bd7c1c 100644 --- a/ext/arts/gst_arts.c +++ b/ext/arts/gst_arts.c @@ -171,7 +171,6 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN ) diff --git a/ext/artsd/gstartsdsink.c b/ext/artsd/gstartsdsink.c index 7bb917576..6012f9337 100644 --- a/ext/artsd/gstartsdsink.c +++ b/ext/artsd/gstartsdsink.c @@ -275,7 +275,6 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN) diff --git a/ext/audiofile/gstaf.c b/ext/audiofile/gstaf.c index 1d05ae3ff..188caf423 100644 --- a/ext/audiofile/gstaf.c +++ b/ext/audiofile/gstaf.c @@ -48,6 +48,5 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN) diff --git a/ext/divx/gstdivxdec.c b/ext/divx/gstdivxdec.c index 049691f4e..c68d12dce 100644 --- a/ext/divx/gstdivxdec.c +++ b/ext/divx/gstdivxdec.c @@ -479,7 +479,6 @@ GST_PLUGIN_DEFINE ( plugin_init, "5.03", GST_LICENSE_UNKNOWN, - "(c) 2002 DivX Networks", "divx4linux", "http://www.divx.com/" ) diff --git a/ext/divx/gstdivxenc.c b/ext/divx/gstdivxenc.c index b5a0458e3..ba9c03513 100644 --- a/ext/divx/gstdivxenc.c +++ b/ext/divx/gstdivxenc.c @@ -582,7 +582,6 @@ GST_PLUGIN_DEFINE ( plugin_init, "5.03", GST_LICENSE_UNKNOWN, - "(c) 2002 DivX Networks", "divx4linux", "http://www.divx.com/" ) diff --git a/ext/faac/gstfaac.c b/ext/faac/gstfaac.c index e5dddc17a..be4c56cba 100644 --- a/ext/faac/gstfaac.c +++ b/ext/faac/gstfaac.c @@ -674,7 +674,6 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN ) diff --git a/ext/faad/gstfaad.c b/ext/faad/gstfaad.c index c14ba44e8..56f38a4e4 100644 --- a/ext/faad/gstfaad.c +++ b/ext/faad/gstfaad.c @@ -472,7 +472,6 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "GPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN ) diff --git a/ext/gsm/gstgsm.c b/ext/gsm/gstgsm.c index c186ed1b2..346cf219a 100644 --- a/ext/gsm/gstgsm.c +++ b/ext/gsm/gstgsm.c @@ -43,6 +43,5 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN) diff --git a/ext/hermes/gstcolorspace.c b/ext/hermes/gstcolorspace.c index de1bd88f7..837c24e41 100644 --- a/ext/hermes/gstcolorspace.c +++ b/ext/hermes/gstcolorspace.c @@ -679,7 +679,6 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN) diff --git a/ext/ivorbis/vorbis.c b/ext/ivorbis/vorbis.c index 4098e53f9..b104ec663 100644 --- a/ext/ivorbis/vorbis.c +++ b/ext/ivorbis/vorbis.c @@ -48,6 +48,5 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN) diff --git a/ext/jack/gstjack.c b/ext/jack/gstjack.c index 3aff6d7cd..85d57658c 100644 --- a/ext/jack/gstjack.c +++ b/ext/jack/gstjack.c @@ -519,6 +519,5 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "GPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN) diff --git a/ext/jack/gstjackbin.c b/ext/jack/gstjackbin.c index cb1839c41..b0cea9bc3 100644 --- a/ext/jack/gstjackbin.c +++ b/ext/jack/gstjackbin.c @@ -279,7 +279,7 @@ process (jack_nframes_t nframes, void *arg) bin->nframes = nframes; JACK_DEBUG ("jackbin: iterating to process %ld frames of audio...", nframes); - if (!gst_bin_iterate (GST_BIN_CAST (bin))) { + if (!gst_bin_iterate (GST_BIN (bin))) { g_warning ("bin failed to iterate"); return -1; } diff --git a/ext/ladspa/gstladspa.c b/ext/ladspa/gstladspa.c index 6dc8763f9..6ecb3ce16 100644 --- a/ext/ladspa/gstladspa.c +++ b/ext/ladspa/gstladspa.c @@ -1,6 +1,7 @@ /* GStreamer * Copyright (C) <1999> Erik Walthinsen * <2001> Steve Baker + * 2003 Andy Wingo * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -30,6 +31,11 @@ #include /* main ladspa sdk include file */ #include "utils.h" /* ladspa sdk utility functions */ +/* 1.0 and the 1.1 preliminary headers don't define a version, but 1.1 final + does */ +#ifndef LADSPA_VERSION +#define LADSPA_VERSION "1.0" +#endif /* takes ownership of the name */ static GstPadTemplate* @@ -1038,9 +1044,8 @@ GST_PLUGIN_DEFINE ( "ladspa", "All LADSPA plugins", plugin_init, - LADSPA_VERSION, - "LGPL", - "(c) 2003 The LADSPA team", - "LADSPA", - "http://www.ladspa.org/" + VERSION, + GST_LICENSE, + GST_PACKAGE, + GST_ORIGIN ) diff --git a/ext/libfame/gstlibfame.c b/ext/libfame/gstlibfame.c index 17ea96691..be2404d5d 100644 --- a/ext/libfame/gstlibfame.c +++ b/ext/libfame/gstlibfame.c @@ -612,7 +612,6 @@ GST_PLUGIN_DEFINE ( plugin_init, LIBFAME_VERSION, "LGPL", - "(c) 2000-2001, Vivien Chappelier", "libfame", "http://fame.sourceforge.net/" ) diff --git a/ext/mas/massink.c b/ext/mas/massink.c index 67ca47b4e..0a87c9c86 100644 --- a/ext/mas/massink.c +++ b/ext/mas/massink.c @@ -349,7 +349,6 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN ); diff --git a/ext/mpeg2enc/Makefile.am b/ext/mpeg2enc/Makefile.am new file mode 100644 index 000000000..da5d01d1f --- /dev/null +++ b/ext/mpeg2enc/Makefile.am @@ -0,0 +1,18 @@ +plugin_LTLIBRARIES = libgstmpeg2enc.la + +libgstmpeg2enc_la_SOURCES = \ + gstmpeg2enc.cc \ + gstmpeg2encoptions.cc \ + gstmpeg2encoder.cc \ + gstmpeg2encstreamwriter.cc \ + gstmpeg2encpicturereader.cc +libgstmpeg2enc_la_CXXFLAGS = $(MPEG2ENC_CFLAGS) $(GST_CFLAGS) +libgstmpeg2enc_la_LIBADD = $(MPEG2ENC_LIBS) +libgstmpeg2enc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +noinst_HEADERS = \ + gstmpeg2enc.hh \ + gstmpeg2encoder.hh \ + gstmpeg2encoptions.hh \ + gstmpeg2encstreamwriter.hh \ + gstmpeg2encpicturereader.hh diff --git a/ext/mpeg2enc/gstmpeg2enc.cc b/ext/mpeg2enc/gstmpeg2enc.cc new file mode 100644 index 000000000..5e5e028df --- /dev/null +++ b/ext/mpeg2enc/gstmpeg2enc.cc @@ -0,0 +1,319 @@ +/* GStreamer mpeg2enc (mjpegtools) wrapper + * (c) 2003 Ronald Bultje + * + * gstmpeg2enc.cc: gstreamer wrapping + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstmpeg2enc.hh" + +GST_PAD_TEMPLATE_FACTORY (sink_templ, + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "mpeg2enc_sink", + "video/x-raw-yuv", + "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), + "framerate", GST_PROPS_LIST ( + GST_PROPS_FLOAT (24/1.001), + GST_PROPS_FLOAT (24.), + GST_PROPS_FLOAT (25.), + GST_PROPS_FLOAT (30/1.001), + GST_PROPS_FLOAT (30.), + GST_PROPS_FLOAT (50.), + GST_PROPS_FLOAT (60/1.001), + GST_PROPS_FLOAT (60.) + ) + ) +) + +GST_PAD_TEMPLATE_FACTORY (src_templ, + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "mpeg2enc_src", + "video/mpeg", + "systemstream", GST_PROPS_BOOLEAN (FALSE), + "mpegversion", GST_PROPS_INT_RANGE (1, 2), + "width", GST_PROPS_INT_RANGE (16, 4096), + "height", GST_PROPS_INT_RANGE (16, 4096), + "framerate", GST_PROPS_LIST ( + GST_PROPS_FLOAT (24/1.001), + GST_PROPS_FLOAT (24.), + GST_PROPS_FLOAT (25.), + GST_PROPS_FLOAT (30/1.001), + GST_PROPS_FLOAT (30.), + GST_PROPS_FLOAT (50.), + GST_PROPS_FLOAT (60/1.001), + GST_PROPS_FLOAT (60.) + ) + ) +) + +static void gst_mpeg2enc_base_init (GstMpeg2encClass *klass); +static void gst_mpeg2enc_class_init (GstMpeg2encClass *klass); +static void gst_mpeg2enc_init (GstMpeg2enc *enc); +static void gst_mpeg2enc_dispose (GObject *object); + +static void gst_mpeg2enc_loop (GstElement *element); + +static GstPadLinkReturn + gst_mpeg2enc_sink_link (GstPad *pad, + GstCaps *caps); +static GstCaps * + gst_mpeg2enc_src_getcaps (GstPad *pad, + GstCaps *caps); + +static GstElementStateReturn + gst_mpeg2enc_change_state (GstElement *element); + +static void gst_mpeg2enc_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void gst_mpeg2enc_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); + +static GstElementClass *parent_class = NULL; + +GType +gst_mpeg2enc_get_type (void) +{ + static GType gst_mpeg2enc_type = 0; + + if (!gst_mpeg2enc_type) { + static const GTypeInfo gst_mpeg2enc_info = { + sizeof (GstMpeg2encClass), + (GBaseInitFunc) gst_mpeg2enc_base_init, + NULL, + (GClassInitFunc) gst_mpeg2enc_class_init, + NULL, + NULL, + sizeof (GstMpeg2enc), + 0, + (GInstanceInitFunc) gst_mpeg2enc_init, + }; + + gst_mpeg2enc_type = + g_type_register_static (GST_TYPE_ELEMENT, + "GstMpeg2enc", + &gst_mpeg2enc_info, + (GTypeFlags) 0); + } + + return gst_mpeg2enc_type; +} + +static void +gst_mpeg2enc_base_init (GstMpeg2encClass *klass) +{ + static GstElementDetails gst_mpeg2enc_details = { + "mpeg2enc video encoder", + "Codec/Video/Encoder", + "High-quality MPEG-1/2 video encoder", + "Ronald Bultje ", + }; + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + GST_PAD_TEMPLATE_GET (src_templ)); + gst_element_class_add_pad_template (element_class, + GST_PAD_TEMPLATE_GET (sink_templ)); + gst_element_class_set_details (element_class, + &gst_mpeg2enc_details); +} + +static void +gst_mpeg2enc_class_init (GstMpeg2encClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + parent_class = GST_ELEMENT_CLASS (g_type_class_ref (GST_TYPE_ELEMENT)); + + /* register arguments */ + mjpeg_default_handler_verbosity (0); + GstMpeg2EncOptions::initProperties (object_class); + + object_class->set_property = gst_mpeg2enc_set_property; + object_class->get_property = gst_mpeg2enc_get_property; + + object_class->dispose = gst_mpeg2enc_dispose; + + element_class->change_state = gst_mpeg2enc_change_state; +} + +static void +gst_mpeg2enc_dispose (GObject *object) +{ + GstMpeg2enc *enc = GST_MPEG2ENC (object); + + if (enc->encoder) { + delete enc->encoder; + enc->encoder = NULL; + } + delete enc->options; +} + +static void +gst_mpeg2enc_init (GstMpeg2enc *enc) +{ + GstElement *element = GST_ELEMENT (enc); + + enc->sinkpad = gst_pad_new_from_template ( + gst_element_get_pad_template (element, "sink"), "sink"); + gst_pad_set_link_function (enc->sinkpad, gst_mpeg2enc_sink_link); + gst_element_add_pad (element, enc->sinkpad); + + enc->srcpad = gst_pad_new_from_template ( + gst_element_get_pad_template (element, "src"), "src"); + gst_pad_set_getcaps_function (enc->srcpad, gst_mpeg2enc_src_getcaps); + gst_element_add_pad (element, enc->srcpad); + + enc->options = new GstMpeg2EncOptions (); + + gst_element_set_loop_function (element, gst_mpeg2enc_loop); + + enc->encoder = NULL; +} + +static void +gst_mpeg2enc_loop (GstElement *element) +{ + GstMpeg2enc *enc = GST_MPEG2ENC (element); + + if (!enc->encoder) { + GstCaps *caps; + + /* create new encoder with these settings */ + enc->encoder = new GstMpeg2Encoder (enc->options, + enc->sinkpad, + GST_PAD_CAPS (enc->sinkpad), + enc->srcpad); + + /* and set caps on other side */ + caps = enc->encoder->getFormat (); + if (gst_pad_try_set_caps (enc->srcpad, caps) <= 0) { + gst_element_error (element, + "Failed to set up encoder properly"); + delete enc->encoder; + enc->encoder = NULL; + return; + } + } + + enc->encoder->encodePicture (); +} + +static GstPadLinkReturn +gst_mpeg2enc_sink_link (GstPad *pad, + GstCaps *caps) +{ + GstMpeg2enc *enc = GST_MPEG2ENC (gst_pad_get_parent (pad)); + + if (!GST_CAPS_IS_FIXED (caps)) + return GST_PAD_LINK_DELAYED; + + if (enc->encoder) { + delete enc->encoder; + enc->encoder = NULL; + } + + return GST_PAD_LINK_OK; +} + +static GstCaps * +gst_mpeg2enc_src_getcaps (GstPad *pad, + GstCaps *caps) +{ + GstMpeg2enc *enc = GST_MPEG2ENC (gst_pad_get_parent (pad)); + + if (enc->encoder) { + return enc->encoder->getFormat (); + } + + return gst_caps_ref (gst_pad_template_get_caps ( + gst_element_get_pad_template (gst_pad_get_parent (pad), "src"))); +} + +static void +gst_mpeg2enc_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GST_MPEG2ENC (object)->options->getProperty (prop_id, value); +} + +static void +gst_mpeg2enc_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GST_MPEG2ENC (object)->options->setProperty (prop_id, value); +} + +static GstElementStateReturn +gst_mpeg2enc_change_state (GstElement *element) +{ + GstMpeg2enc *enc = GST_MPEG2ENC (element); + + switch (GST_STATE_TRANSITION (element)) { + case GST_STATE_PAUSED_TO_READY: + delete enc->encoder; + enc->encoder = NULL; + break; + default: + break; + } + + if (parent_class->change_state) + return parent_class->change_state (element); + + return GST_STATE_SUCCESS; +} + +static gboolean +plugin_init (GstPlugin *plugin) +{ + return gst_element_register (plugin, "mpeg2enc", + GST_RANK_NONE, + GST_TYPE_MPEG2ENC); +} + +GST_PLUGIN_DEFINE ( + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "mpeg2enc", + "High-quality MPEG-1/2 video encoder", + plugin_init, + VERSION, + "GPL", + GST_PACKAGE, + GST_ORIGIN +) diff --git a/ext/mpeg2enc/gstmpeg2enc.hh b/ext/mpeg2enc/gstmpeg2enc.hh new file mode 100644 index 000000000..25c61e61a --- /dev/null +++ b/ext/mpeg2enc/gstmpeg2enc.hh @@ -0,0 +1,63 @@ +/* GStreamer mpeg2enc (mjpegtools) wrapper + * (c) 2003 Ronald Bultje + * + * gstmpeg2enc.hh: object definition + * + * 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_MPEG2ENC_H__ +#define __GST_MPEG2ENC_H__ + +#include +#include "gstmpeg2encoptions.hh" +#include "gstmpeg2encoder.hh" + +G_BEGIN_DECLS + +#define GST_TYPE_MPEG2ENC \ + (gst_mpeg2enc_get_type ()) +#define GST_MPEG2ENC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MPEG2ENC, GstMpeg2enc)) +#define GST_MPEG2ENC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MPEG2ENC, GstMpeg2enc)) +#define GST_IS_MPEG2ENC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MPEG2ENC)) +#define GST_IS_MPEG2ENC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MPEG2ENC)) + +typedef struct _GstMpeg2enc { + GstElement parent; + + /* pads */ + GstPad *sinkpad, *srcpad; + + /* options wrapper */ + GstMpeg2EncOptions *options; + + /* general encoding object (contains rest) */ + GstMpeg2Encoder *encoder; +} GstMpeg2enc; + +typedef struct _GstMpeg2encClass { + GstElementClass parent; +} GstMpeg2encClass; + +GType gst_mpeg2enc_get_type (void); + +G_END_DECLS + +#endif /* __GST_MPEG2ENC_H__ */ diff --git a/ext/mpeg2enc/gstmpeg2encoder.cc b/ext/mpeg2enc/gstmpeg2encoder.cc new file mode 100644 index 000000000..e0952db13 --- /dev/null +++ b/ext/mpeg2enc/gstmpeg2encoder.cc @@ -0,0 +1,95 @@ +/* GStreamer mpeg2enc (mjpegtools) wrapper + * (c) 2003 Ronald Bultje + * + * gstmpeg2encoder.cc: gstreamer/mpeg2enc encoder class + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "gstmpeg2encoder.hh" + +/* + * Class init stuff. + */ + +GstMpeg2Encoder::GstMpeg2Encoder (GstMpeg2EncOptions *options, + GstPad *sinkpad, + GstCaps *caps, + GstPad *srcpad) : + MPEG2Encoder (*options) +{ + MPEG2EncInVidParams strm; + + /* I/O */ + reader = new GstMpeg2EncPictureReader (sinkpad, caps, &parms); + reader->StreamPictureParams (strm); + if (options->SetFormatPresets (strm)) { + g_warning ("Eek! Format presets failed. This is really bad!"); + } + writer = new GstMpeg2EncStreamWriter (srcpad, &parms); + + /* encoding internals */ + quantizer = new Quantizer (parms); + coder = new MPEG2Coder (parms, *writer); + bitrate_controller = new OnTheFlyRateCtl (parms); + + /* sequencer */ + seqencoder = new SeqEncoder (parms, *reader, *quantizer, + *writer, *coder, *bitrate_controller); + + parms.Init (*options); + reader->Init (); + quantizer->Init (); +} + +/* + * One image. + */ + +void +GstMpeg2Encoder::encodePicture () +{ + /* hm, this is all... eek! */ + seqencoder->Encode (); +} + +/* + * Get current output format. + */ + +GstCaps * +GstMpeg2Encoder::getFormat () +{ + gdouble fps = Y4M_RATIO_DBL (mpeg_framerate (options.frame_rate)); + + return GST_CAPS_NEW ("mpeg2enc_src", + "video/mpeg", + "systemstream", GST_PROPS_BOOLEAN (FALSE), + "mpegversion", GST_PROPS_INT (options.mpeg), + "width", GST_PROPS_INT (options.in_img_width), + "height", GST_PROPS_INT (options.in_img_height), + "framerate", GST_PROPS_FLOAT (fps)); +} diff --git a/ext/mpeg2enc/gstmpeg2encoder.hh b/ext/mpeg2enc/gstmpeg2encoder.hh new file mode 100644 index 000000000..ebe296927 --- /dev/null +++ b/ext/mpeg2enc/gstmpeg2encoder.hh @@ -0,0 +1,44 @@ +/* GStreamer mpeg2enc (mjpegtools) wrapper + * (c) 2003 Ronald Bultje + * + * gstmpeg2encoder.hh: gstreamer/mpeg2enc encoder class + * + * 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_MPEG2ENCODER_H__ +#define __GST_MPEG2ENCODER_H__ + +#include +#include "gstmpeg2encoptions.hh" +#include "gstmpeg2encpicturereader.hh" +#include "gstmpeg2encstreamwriter.hh" + +class GstMpeg2Encoder : public MPEG2Encoder { +public: + GstMpeg2Encoder (GstMpeg2EncOptions *options, + GstPad *sinkpad, + GstCaps *caps, + GstPad *srcpad); + + /* one image */ + void encodePicture (); + + /* get current output format */ + GstCaps *getFormat (); +}; + +#endif /* __GST_MPEG2ENCODER_H__ */ diff --git a/ext/mpeg2enc/gstmpeg2encoptions.cc b/ext/mpeg2enc/gstmpeg2encoptions.cc new file mode 100644 index 000000000..5dbf9ac73 --- /dev/null +++ b/ext/mpeg2enc/gstmpeg2encoptions.cc @@ -0,0 +1,703 @@ +/* GStreamer mpeg2enc (mjpegtools) wrapper + * (c) 2003 Ronald Bultje + * + * gstmpeg2encoptions.cc: gobject/mpeg2enc option wrapping class + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstmpeg2encoptions.hh" + +/* + * Property enumeration. + */ + +enum { + ARG_0, + ARG_FORMAT, + ARG_FRAMERATE, + ARG_ASPECT, + ARG_INTERLACE_MODE, + ARG_BITRATE, + ARG_NONVIDEO_BITRATE, + ARG_QUANTISATION, + ARG_VCD_STILL_SIZE, + ARG_MOTION_SEARCH_RADIUS, + ARG_REDUCTION_4_4, + ARG_REDUCTION_2_2, + ARG_UNIT_COEFF_ELIM, + ARG_MIN_GOP_SIZE, + ARG_MAX_GOP_SIZE, + ARG_CLOSED_GOP, + ARG_FORCE_B_B_P, + ARG_B_PER_REFFRAME, + ARG_QUANTISATION_REDUCTION, + ARG_QUANT_REDUCTION_MAX_VAR, + ARG_INTRA_DC_PRECISION, + ARG_REDUCE_HF, + ARG_KEEP_HF, + ARG_QUANTISATION_MATRIX, + ARG_BUFSIZE, + ARG_VIDEO_NORM, + ARG_SEQUENCE_LENGTH, + ARG_3_2_PULLDOWN, + ARG_SEQUENCE_HEADER_EVERY_GOP, + ARG_PLAYBACK_FIELD_ORDER, + ARG_DUMMY_SVCD_SOF, + ARG_CORRECT_SVCD_HDS, + ARG_ALTSCAN_MPEG2, + ARG_CONSTRAINTS + /* FILL ME */ +}; + +/* + * Property enumeration types. + */ + +#define GST_TYPE_MPEG2ENC_FORMAT \ + (gst_mpeg2enc_format_get_type ()) + +static GType +gst_mpeg2enc_format_get_type (void) +{ + static GType mpeg2enc_format_type = 0; + + if (!mpeg2enc_format_type) { + static const GEnumValue mpeg2enc_formats[] = { + { 0, "0", "Generic MPEG-1" }, + { 1, "1", "Standard VCD" }, + { 2, "2", "User VCD" }, + { 3, "3", "Generic MPEG-2" }, + { 4, "4", "Standard SVCD" }, + { 5, "5", "User SVCD" }, + { 6, "6", "VCD Stills sequences" }, + { 7, "7", "SVCD Stills sequences" }, + { 8, "8", "DVD MPEG-2 for dvdauthor" }, + { 9, "9", "DVD MPEG-2" }, + { 0, NULL, NULL }, + }; + + mpeg2enc_format_type = + g_enum_register_static ("GstMpeg2encFormat", + mpeg2enc_formats); + } + + return mpeg2enc_format_type; +} + +#define GST_TYPE_MPEG2ENC_FRAMERATE \ + (gst_mpeg2enc_framerate_get_type ()) + +static GType +gst_mpeg2enc_framerate_get_type (void) +{ + static GType mpeg2enc_framerate_type = 0; + + if (!mpeg2enc_framerate_type) { + static const GEnumValue mpeg2enc_framerates[] = { + { 0, "0", "Same as input" }, + { 1, "1", "24/1.001 (NTSC 3:2 pulldown converted film)" }, + { 2, "2", "24 (native film)" }, + { 3, "3", "25 (PAL/SECAM video)" }, + { 4, "4", "30/1.001 (NTSC video)" }, + { 5, "5", "30" }, + { 6, "6", "50 (PAL/SECAM fields)" }, + { 7, "7", "60/1.001 (NTSC fields)" }, + { 8, "8", "60" }, + { 0, NULL, NULL }, + }; + + mpeg2enc_framerate_type = + g_enum_register_static ("GstMpeg2encFramerate", + mpeg2enc_framerates); + } + + return mpeg2enc_framerate_type; +} + +#define GST_TYPE_MPEG2ENC_ASPECT \ + (gst_mpeg2enc_aspect_get_type ()) + +static GType +gst_mpeg2enc_aspect_get_type (void) +{ + static GType mpeg2enc_aspect_type = 0; + + if (!mpeg2enc_aspect_type) { + static const GEnumValue mpeg2enc_aspects[] = { + { 0, "0", "Deduce from input" }, + { 1, "1", "1:1" }, + { 2, "2", "4:3" }, + { 3, "3", "16:9" }, + { 4, "4", "2.21:1" }, + { 0, NULL, NULL }, + }; + + mpeg2enc_aspect_type = + g_enum_register_static ("GstMpeg2encAspect", + mpeg2enc_aspects); + } + + return mpeg2enc_aspect_type; +} + +#define GST_TYPE_MPEG2ENC_INTERLACE_MODE \ + (gst_mpeg2enc_interlace_mode_get_type ()) + +static GType +gst_mpeg2enc_interlace_mode_get_type (void) +{ + static GType mpeg2enc_interlace_mode_type = 0; + + if (!mpeg2enc_interlace_mode_type) { + static const GEnumValue mpeg2enc_interlace_modes[] = { + { -1, "-1", "Format default mode" }, + { 0, "0", "Progressive" }, + { 1, "1", "Interlaced, per-frame encoding" }, + { 2, "2", "Interlaced, per-field-encoding" }, + { 0, NULL, NULL }, + }; + + mpeg2enc_interlace_mode_type = + g_enum_register_static ("GstMpeg2encInterlaceMode", + mpeg2enc_interlace_modes); + } + + return mpeg2enc_interlace_mode_type; +} + +#define GST_TYPE_MPEG2ENC_QUANTISATION_MATRIX \ + (gst_mpeg2enc_quantisation_matrix_get_type ()) + +#define GST_MPEG2ENC_QUANTISATION_MATRIX_DEFAULT 0 +#define GST_MPEG2ENC_QUANTISATION_MATRIX_HI_RES 1 +#define GST_MPEG2ENC_QUANTISATION_MATRIX_KVCD 2 +#define GST_MPEG2ENC_QUANTISATION_MATRIX_TMPGENC 3 + +static GType +gst_mpeg2enc_quantisation_matrix_get_type (void) +{ + static GType mpeg2enc_quantisation_matrix_type = 0; + + if (!mpeg2enc_quantisation_matrix_type) { + static const GEnumValue mpeg2enc_quantisation_matrixes[] = { + { GST_MPEG2ENC_QUANTISATION_MATRIX_DEFAULT, + "0", "Default" }, + { GST_MPEG2ENC_QUANTISATION_MATRIX_HI_RES, + "1", "High resolution" }, + { GST_MPEG2ENC_QUANTISATION_MATRIX_KVCD, + "2", "KVCD" }, + { GST_MPEG2ENC_QUANTISATION_MATRIX_TMPGENC, + "3", "TMPGEnc" }, + { 0, NULL, NULL }, + }; + + mpeg2enc_quantisation_matrix_type = + g_enum_register_static ("GstMpeg2encQuantisationMatrix", + mpeg2enc_quantisation_matrixes); + } + + return mpeg2enc_quantisation_matrix_type; +} + +#define GST_TYPE_MPEG2ENC_VIDEO_NORM \ + (gst_mpeg2enc_video_norm_get_type ()) + +static GType +gst_mpeg2enc_video_norm_get_type (void) +{ + static GType mpeg2enc_video_norm_type = 0; + + if (!mpeg2enc_video_norm_type) { + static const GEnumValue mpeg2enc_video_norms[] = { + { 0, "0", "Unspecified" }, + { 'p', "p", "PAL" }, + { 'n', "n", "NTSC" }, + { 's', "s", "SECAM" }, + { 0, NULL, NULL }, + }; + + mpeg2enc_video_norm_type = + g_enum_register_static ("GstMpeg2encVideoNorm", + mpeg2enc_video_norms); + } + + return mpeg2enc_video_norm_type; +} + +#define GST_TYPE_MPEG2ENC_PLAYBACK_FIELD_ORDER \ + (gst_mpeg2enc_playback_field_order_get_type ()) + +static GType +gst_mpeg2enc_playback_field_order_get_type (void) +{ + static GType mpeg2enc_playback_field_order_type = 0; + + if (!mpeg2enc_playback_field_order_type) { + static const GEnumValue mpeg2enc_playback_field_orders[] = { + { Y4M_UNKNOWN, "0", "Unspecified" }, + { Y4M_ILACE_TOP_FIRST, "1", "Top-field first" }, + { Y4M_ILACE_BOTTOM_FIRST, "2", "Bottom-field first" }, + { 0, NULL, NULL }, + }; + + mpeg2enc_playback_field_order_type = + g_enum_register_static ("GstMpeg2encPlaybackFieldOrders", + mpeg2enc_playback_field_orders); + } + + return mpeg2enc_playback_field_order_type; +} + +/* + * Class init stuff. + */ + +GstMpeg2EncOptions::GstMpeg2EncOptions () : + MPEG2EncOptions () +{ + /* autodetect number of CPUs */ + num_cpus = sysconf (_SC_NPROCESSORS_ONLN); + if (num_cpus < 0) + num_cpus = 1; + if (num_cpus > 32) + num_cpus = 32; +} + +/* + * Init properties (call once). + */ + +void +GstMpeg2EncOptions::initProperties (GObjectClass *klass) +{ + /* encoding profile */ + g_object_class_install_property (klass, ARG_FORMAT, + g_param_spec_enum ("format", "Format", "Encoding profile format", + GST_TYPE_MPEG2ENC_FORMAT, 0, + (GParamFlags) G_PARAM_READWRITE)); + + /* input/output stream overrides */ + g_object_class_install_property (klass, ARG_FRAMERATE, + g_param_spec_enum ("framerate", "Framerate", "Output framerate", + GST_TYPE_MPEG2ENC_FRAMERATE, 0, + (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_ASPECT, + g_param_spec_enum ("aspect", "Aspect", "Display aspect ratio", + GST_TYPE_MPEG2ENC_ASPECT, 0, + (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_INTERLACE_MODE, + g_param_spec_enum ("interlace-mode", "Interlace mode", + "MPEG-2 motion estimation and encoding modes", + GST_TYPE_MPEG2ENC_INTERLACE_MODE, 0, + (GParamFlags) G_PARAM_READWRITE)); + + /* general encoding stream options */ + g_object_class_install_property (klass, ARG_BITRATE, + g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)", + 0, 10*1024, 1125, (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_NONVIDEO_BITRATE, + g_param_spec_int ("non-video-bitrate", "Non-video bitrate", + "Assumed bitrate of non-video for sequence splitting (kbps)", + 0, 10*1024, 0, (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_QUANTISATION, + g_param_spec_int ("quantisation", "Quantisation", + "Quantisation factor (0=default, 1=best, 31=worst)", + 0, 31, 0, (GParamFlags) G_PARAM_READWRITE)); + + /* stills options */ + g_object_class_install_property (klass, ARG_VCD_STILL_SIZE, + g_param_spec_int ("vcd-still-size", "VCD stills size", + "Size of VCD stills (in kB)", + 0, 512, 0, (GParamFlags) G_PARAM_READWRITE)); + + /* motion estimation options */ + g_object_class_install_property (klass, ARG_MOTION_SEARCH_RADIUS, + g_param_spec_int ("motion-search-radius", "Motion search radius", + "Motion compensation search radius", + 0, 32, 16, (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_REDUCTION_4_4, + g_param_spec_int ("reduction-4x4", "4x4 reduction", + "Reduction factor for 4x4 subsampled candidate motion estimates" + " (1=max. quality, 4=max. speed)", + 1, 4, 2, (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_REDUCTION_2_2, + g_param_spec_int ("reduction-2x2", "2x2 reduction", + "Reduction factor for 2x2 subsampled candidate motion estimates" + " (1=max. quality, 4=max. speed)", + 1, 4, 3, (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_UNIT_COEFF_ELIM, + g_param_spec_int ("unit-coeff-elim", "Unit coefficience elimination", + "How agressively small-unit picture blocks should be skipped", + -40, 40, 0, (GParamFlags) G_PARAM_READWRITE)); + + /* GOP options */ + g_object_class_install_property (klass, ARG_MIN_GOP_SIZE, + g_param_spec_int ("min-gop-size", "Min. GOP size", + "Minimal size per Group-of-Pictures (-1=default)", + -1, 250, 0, (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_MAX_GOP_SIZE, + g_param_spec_int ("max-gop-size", "Max. GOP size", + "Maximal size per Group-of-Pictures (-1=default)", + -1, 250, 0, (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_CLOSED_GOP, + g_param_spec_boolean ("closed-gop", "Closed GOP", + "All Group-of-Pictures are closed (for multi-angle DVDs)", + FALSE, (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_FORCE_B_B_P, + g_param_spec_boolean ("force-b-b-p", "Force B-B-P", + "Force two B frames between I/P frames when closing GOP boundaries", + FALSE, (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_B_PER_REFFRAME, + g_param_spec_int ("b-per-refframe", "B per ref. frame", + "Number of B frames between each I/P frame", + 0, 2, 2, (GParamFlags) G_PARAM_READWRITE)); + + /* quantisation options */ + g_object_class_install_property (klass, ARG_QUANTISATION_REDUCTION, + g_param_spec_float ("quantisation-reduction", "Quantisation reduction", + "Max. quantisation reduction for highly active blocks", + -4., 10., 0., (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_QUANT_REDUCTION_MAX_VAR, + g_param_spec_float ("quant-reduction-max-var", "Max. quant. reduction variance", + "Maximal luma variance below which quantisation boost is used", + 0., 2500., 0., (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_INTRA_DC_PRECISION, + g_param_spec_int ("intra-dc-prec", "Intra. DC precision", + "Number of bits precision for DC (base colour) in MPEG-2 blocks", + 8, 11, 9, (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_REDUCE_HF, + g_param_spec_float ("reduce-hf", "Reduce HF", + "How much to reduce high-frequency resolution (by increasing quantisation)", + 0., 2., 0., (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_KEEP_HF, + g_param_spec_boolean ("keep-hf", "Keep HF", + "Maximize high-frequency resolution (for high-quality sources)", + FALSE, (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_QUANTISATION_MATRIX, + g_param_spec_enum ("quant-matrix", "Quant. matrix", + "Quantisation matrix to use for encoding", + GST_TYPE_MPEG2ENC_QUANTISATION_MATRIX, 0, + (GParamFlags) G_PARAM_READWRITE)); + + /* general options */ + g_object_class_install_property (klass, ARG_BUFSIZE, + g_param_spec_int ("bufsize", "Decoder buf. size", + "Target decoders video buffer size (kB)", + 20, 4000, 46, (GParamFlags) G_PARAM_READWRITE)); + + /* header flag settings */ + g_object_class_install_property (klass, ARG_VIDEO_NORM, + g_param_spec_enum ("norm", "Norm", + "Tag output for specific video norm", + GST_TYPE_MPEG2ENC_VIDEO_NORM, 0, + (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_SEQUENCE_LENGTH, + g_param_spec_int ("sequence-length", "Sequence length", + "Place a sequence boundary after each MB (0=disable)", + 0, 10*1024, 0, (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_3_2_PULLDOWN, + g_param_spec_boolean ("pulldown-3-2", "3-2 pull down", + "Generate header flags for 3-2 pull down 24fps movies", + FALSE, (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_SEQUENCE_HEADER_EVERY_GOP, + g_param_spec_boolean ("sequence-header-every-gop", + "Sequence hdr. every GOP", + "Include a sequence header in every GOP", + FALSE, (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_DUMMY_SVCD_SOF, + g_param_spec_boolean ("dummy-svcd-sof", "Dummy SVCD SOF", + "Generate dummy SVCD scan-data (for vcdimager)", + TRUE, (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_PLAYBACK_FIELD_ORDER, + g_param_spec_enum ("playback-field-order", "Playback field order", + "Force specific playback field order", + GST_TYPE_MPEG2ENC_PLAYBACK_FIELD_ORDER, Y4M_UNKNOWN, + (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_CORRECT_SVCD_HDS, + g_param_spec_boolean ("correct-svcd-hds", "Correct SVCD hor. size", + "Force SVCD width to 480 instead of 540/720", + FALSE, (GParamFlags) G_PARAM_READWRITE)); + g_object_class_install_property (klass, ARG_ALTSCAN_MPEG2, + g_param_spec_boolean ("altscan-mpeg2", "Alt. MPEG-2 scan", + "Alternate MPEG-2 block scanning. Disabling this might " + "make buggy players play SVCD streams", + TRUE, (GParamFlags) G_PARAM_READWRITE)); +#if 0 +"--dxr2-hack" +#endif + + /* dangerous/experimental stuff */ + g_object_class_install_property (klass, ARG_CONSTRAINTS, + g_param_spec_boolean ("constraints", "Constraints", + "Use strict video resolution and bitrate checks", + TRUE, (GParamFlags) G_PARAM_READWRITE)); +} + +/* + * GObject property foo, C++ style. + */ + +void +GstMpeg2EncOptions::getProperty (guint prop_id, + GValue *value) +{ + switch (prop_id) { + case ARG_FORMAT: + g_value_set_enum (value, format); + break; + case ARG_FRAMERATE: + g_value_set_enum (value, frame_rate); + break; + case ARG_ASPECT: + g_value_set_enum (value, aspect_ratio); + break; + case ARG_INTERLACE_MODE: + g_value_set_enum (value, fieldenc); + break; + case ARG_BITRATE: + g_value_set_int (value, bitrate/1024); + break; + case ARG_NONVIDEO_BITRATE: + g_value_set_int (value, nonvid_bitrate/1024); + break; + case ARG_QUANTISATION: + g_value_set_int (value, quant); + break; + case ARG_VCD_STILL_SIZE: + g_value_set_int (value, still_size / 1024); + break; + case ARG_MOTION_SEARCH_RADIUS: + g_value_set_int (value, searchrad); + break; + case ARG_REDUCTION_4_4: + g_value_set_int (value, me44_red); + break; + case ARG_REDUCTION_2_2: + g_value_set_int (value, me22_red); + break; + case ARG_UNIT_COEFF_ELIM: + g_value_set_int (value, unit_coeff_elim); + break; + case ARG_MIN_GOP_SIZE: + g_value_set_int (value, min_GOP_size); + break; + case ARG_MAX_GOP_SIZE: + g_value_set_int (value, max_GOP_size); + break; + case ARG_CLOSED_GOP: + g_value_set_boolean (value, closed_GOPs); + break; + case ARG_FORCE_B_B_P: + g_value_set_boolean (value, preserve_B); + break; + case ARG_B_PER_REFFRAME: + g_value_set_int (value, Bgrp_size - 1); + break; + case ARG_QUANTISATION_REDUCTION: + g_value_set_float (value, act_boost); + break; + case ARG_QUANT_REDUCTION_MAX_VAR: + g_value_set_float (value, boost_var_ceil); + break; + case ARG_INTRA_DC_PRECISION: + g_value_set_int (value, mpeg2_dc_prec - 8); + break; + case ARG_REDUCE_HF: + g_value_set_float (value, hf_q_boost); + break; + case ARG_KEEP_HF: + g_value_set_boolean (value, hf_quant == 2); + break; + case ARG_QUANTISATION_MATRIX: + switch (hf_quant) { + case 0: + g_value_set_enum (value, GST_MPEG2ENC_QUANTISATION_MATRIX_DEFAULT); + break; + case 2: + g_value_set_enum (value, GST_MPEG2ENC_QUANTISATION_MATRIX_HI_RES); + break; + case 3: + g_value_set_enum (value, GST_MPEG2ENC_QUANTISATION_MATRIX_KVCD); + break; + case 4: + g_value_set_enum (value, GST_MPEG2ENC_QUANTISATION_MATRIX_TMPGENC); + break; + } + break; + case ARG_BUFSIZE: + g_value_set_int (value, video_buffer_size); + break; + case ARG_VIDEO_NORM: + g_value_set_enum (value, norm); + break; + case ARG_SEQUENCE_LENGTH: + g_value_set_int (value, seq_length_limit); + break; + case ARG_3_2_PULLDOWN: + g_value_set_boolean (value, vid32_pulldown); + break; + case ARG_SEQUENCE_HEADER_EVERY_GOP: + g_value_set_boolean (value, seq_hdr_every_gop); + break; + case ARG_DUMMY_SVCD_SOF: + g_value_set_boolean (value, svcd_scan_data); + break; + case ARG_PLAYBACK_FIELD_ORDER: + g_value_set_enum (value, force_interlacing); + break; + case ARG_CORRECT_SVCD_HDS: + g_value_set_boolean (value, !hack_svcd_hds_bug); + break; + case ARG_ALTSCAN_MPEG2: + g_value_set_boolean (value, !hack_altscan_bug); + break; + case ARG_CONSTRAINTS: + g_value_set_boolean (value, !ignore_constraints); + break; + default: + break; + } +} + +void +GstMpeg2EncOptions::setProperty (guint prop_id, + const GValue *value) +{ + switch (prop_id) { + case ARG_FORMAT: + format = g_value_get_enum (value); + break; + case ARG_FRAMERATE: + frame_rate = g_value_get_enum (value); + break; + case ARG_ASPECT: + aspect_ratio = g_value_get_enum (value); + break; + case ARG_INTERLACE_MODE: + fieldenc = g_value_get_enum (value); + break; + case ARG_BITRATE: + bitrate = g_value_get_int (value) * 1024; + break; + case ARG_NONVIDEO_BITRATE: + nonvid_bitrate = g_value_get_int (value) * 1024; + break; + case ARG_QUANTISATION: + quant = g_value_get_int (value); + break; + case ARG_VCD_STILL_SIZE: + still_size = g_value_get_int (value) * 1024; + break; + case ARG_MOTION_SEARCH_RADIUS: + searchrad = g_value_get_int (value); + break; + case ARG_REDUCTION_4_4: + me44_red = g_value_get_int (value); + break; + case ARG_REDUCTION_2_2: + me22_red = g_value_get_int (value); + break; + case ARG_UNIT_COEFF_ELIM: + unit_coeff_elim = g_value_get_int (value); + break; + case ARG_MIN_GOP_SIZE: + min_GOP_size = g_value_get_int (value); + break; + case ARG_MAX_GOP_SIZE: + max_GOP_size = g_value_get_int (value); + break; + case ARG_CLOSED_GOP: + closed_GOPs = g_value_get_boolean (value); + break; + case ARG_FORCE_B_B_P: + preserve_B = g_value_get_boolean (value); + break; + case ARG_B_PER_REFFRAME: + Bgrp_size = g_value_get_int (value) + 1; + break; + case ARG_QUANTISATION_REDUCTION: + act_boost = g_value_get_float (value); + break; + case ARG_QUANT_REDUCTION_MAX_VAR: + boost_var_ceil = g_value_get_float (value); + break; + case ARG_INTRA_DC_PRECISION: + mpeg2_dc_prec = g_value_get_int (value) + 8; + break; + case ARG_REDUCE_HF: + hf_q_boost = g_value_get_float (value); + if (hf_quant == 0 && hf_q_boost != 0.) + hf_quant = 1; + break; + case ARG_KEEP_HF: + hf_quant = g_value_get_boolean (value) ? 2 : 0; + break; + case ARG_QUANTISATION_MATRIX: + switch (g_value_get_enum (value)) { + case GST_MPEG2ENC_QUANTISATION_MATRIX_DEFAULT: + hf_quant = 0; + hf_q_boost = 0; + break; + case GST_MPEG2ENC_QUANTISATION_MATRIX_HI_RES: + hf_quant = 2; + break; + case GST_MPEG2ENC_QUANTISATION_MATRIX_KVCD: + hf_quant = 3; + break; + case GST_MPEG2ENC_QUANTISATION_MATRIX_TMPGENC: + hf_quant = 4; + break; + } + break; + case ARG_BUFSIZE: + video_buffer_size = g_value_get_int (value); + break; + case ARG_VIDEO_NORM: + norm = g_value_get_enum (value); + break; + case ARG_SEQUENCE_LENGTH: + seq_length_limit = g_value_get_int (value); + break; + case ARG_3_2_PULLDOWN: + vid32_pulldown = g_value_get_boolean (value); + break; + case ARG_SEQUENCE_HEADER_EVERY_GOP: + seq_hdr_every_gop = g_value_get_boolean (value); + break; + case ARG_DUMMY_SVCD_SOF: + svcd_scan_data = g_value_get_boolean (value); + break; + case ARG_PLAYBACK_FIELD_ORDER: + force_interlacing = g_value_get_enum (value); + break; + case ARG_CORRECT_SVCD_HDS: + hack_svcd_hds_bug = !g_value_get_boolean (value); + break; + case ARG_ALTSCAN_MPEG2: + hack_altscan_bug = !g_value_get_boolean (value); + break; + case ARG_CONSTRAINTS: + ignore_constraints = !g_value_get_boolean (value); + break; + default: + break; + } +} diff --git a/ext/mpeg2enc/gstmpeg2encoptions.hh b/ext/mpeg2enc/gstmpeg2encoptions.hh new file mode 100644 index 000000000..ccacd9518 --- /dev/null +++ b/ext/mpeg2enc/gstmpeg2encoptions.hh @@ -0,0 +1,42 @@ +/* GStreamer mpeg2enc (mjpegtools) wrapper + * (c) 2003 Ronald Bultje + * + * gstmpeg2encoptions.hh: gobject/mpeg2enc option wrapping class + * + * 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_MPEG2ENCOPTIONS_H__ +#define __GST_MPEG2ENCOPTIONS_H__ + +#include +#include + +class GstMpeg2EncOptions : public MPEG2EncOptions { +public: + GstMpeg2EncOptions (); + + /* Init properties (call once) */ + static void initProperties (GObjectClass *klass); + + /* GObject property foo, C++ style */ + void getProperty (guint prop_id, + GValue *value); + void setProperty (guint prop_id, + const GValue *value); +}; + +#endif /* __GST_MPEG2ENCOPTIONS_H__ */ diff --git a/ext/mpeg2enc/gstmpeg2encpicturereader.cc b/ext/mpeg2enc/gstmpeg2encpicturereader.cc new file mode 100644 index 000000000..226acc8dc --- /dev/null +++ b/ext/mpeg2enc/gstmpeg2encpicturereader.cc @@ -0,0 +1,129 @@ +/* GStreamer mpeg2enc (mjpegtools) wrapper + * (c) 2003 Ronald Bultje + * + * gstmpeg2encpicturereader.cc: GStreamer/mpeg2enc input wrapper + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "gstmpeg2encpicturereader.hh" + +/* + * Class init stuff. + */ + +GstMpeg2EncPictureReader::GstMpeg2EncPictureReader (GstPad *in_pad, + GstCaps *in_caps, + EncoderParams *params) : + PictureReader (*params) +{ + pad = in_pad; + caps = gst_caps_copy (in_caps); +} + +GstMpeg2EncPictureReader::~GstMpeg2EncPictureReader () +{ + gst_caps_unref (caps); +} + +/* + * Get input picture parameters (width/height etc.). + */ + +void +GstMpeg2EncPictureReader::StreamPictureParams (MPEG2EncInVidParams &strm) +{ + gint width, height; + gfloat fps; + + gst_caps_get (caps, "width", &width, + "height", &height, + "framerate", &fps, NULL); + + strm.horizontal_size = width; + strm.vertical_size = height; + strm.frame_rate_code = mpeg_framerate_code (mpeg_conform_framerate (fps)); + strm.interlacing_code = Y4M_ILACE_NONE; + strm.aspect_ratio_code = mpeg_guess_mpeg_aspect_code (2, y4m_sar_SQUARE, + strm.horizontal_size, + strm.vertical_size); + + /* FIXME: + * strm.interlacing_code = y4m_si_get_interlace(&si); + * sar = y4m_si_get_sampleaspect(&si); + * strm.aspect_ratio_code = + * mpeg_guess_mpeg_aspect_code(2, sar, + * strm.horizontal_size, + * strm.vertical_size); + */ +} + +/* + * Read a frame. + */ + +bool +GstMpeg2EncPictureReader::LoadFrame () +{ + GstData *data; + GstBuffer *buf = NULL; + gint i, x, y, n; + guint8 *frame; + + do { + if (!(data = gst_pad_pull (pad))) { + return true; + } else if (GST_IS_EVENT (data)) { + if (GST_EVENT_TYPE (data) == GST_EVENT_EOS) { + gst_pad_event_default (pad, GST_EVENT (data)); + return true; + } + gst_pad_event_default (pad, GST_EVENT (data)); + } else { + buf = GST_BUFFER (data); + } + } while (!buf); + + frame = GST_BUFFER_DATA (buf); + n = frames_read % input_imgs_buf_size; + x = encparams.horizontal_size; + y = encparams.vertical_size; + + for (i = 0; i < y; i++) { + memcpy (input_imgs_buf[n][0]+i*encparams.phy_width, frame, x); + frame += x; + } + lum_mean[n] = LumMean (input_imgs_buf[n][0]); + x >>= 1; + y >>= 1; + for (i = 0; i < y; i++) { + memcpy (input_imgs_buf[n][1]+i*encparams.phy_chrom_width, frame, x); + frame += x; + } + for (i = 0; i < y; i++) { + memcpy (input_imgs_buf[n][2]+i*encparams.phy_chrom_width, frame, x); + frame += x; + } + gst_buffer_unref (buf); + + return false; +} diff --git a/ext/mpeg2enc/gstmpeg2encpicturereader.hh b/ext/mpeg2enc/gstmpeg2encpicturereader.hh new file mode 100644 index 000000000..93ed8bdc0 --- /dev/null +++ b/ext/mpeg2enc/gstmpeg2encpicturereader.hh @@ -0,0 +1,49 @@ +/* GStreamer mpeg2enc (mjpegtools) wrapper + * (c) 2003 Ronald Bultje + * + * gstmpeg2encpicturereader.hh: GStreamer/mpeg2enc input wrapper + * + * 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_MPEG2ENCPICTUREREADER_H__ +#define __GST_MPEG2ENCPICTUREREADER_H__ + +#include + +#include +#include "gstmpeg2encoptions.hh" + +class GstMpeg2EncPictureReader : public PictureReader { +public: + GstMpeg2EncPictureReader (GstPad *pad, + GstCaps *caps, + EncoderParams *params); + ~GstMpeg2EncPictureReader (); + + /* get input picture parameters (width/height etc.) */ + void StreamPictureParams (MPEG2EncInVidParams &strm); + +protected: + /* read a frame */ + bool LoadFrame (); + +private: + GstPad *pad; + GstCaps *caps; +}; + +#endif /* __GST_MPEG2ENCPICTUREREADER_H__ */ diff --git a/ext/mpeg2enc/gstmpeg2encstreamwriter.cc b/ext/mpeg2enc/gstmpeg2encstreamwriter.cc new file mode 100644 index 000000000..ba59f3d49 --- /dev/null +++ b/ext/mpeg2enc/gstmpeg2encstreamwriter.cc @@ -0,0 +1,99 @@ +/* GStreamer mpeg2enc (mjpegtools) wrapper + * (c) 2003 Ronald Bultje + * + * gstmpeg2encstreamwriter.cc: GStreamer/mpeg2enc output wrapper + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstmpeg2encstreamwriter.hh" + +#define BUFSIZE (128*1024) + +/* + * Class init stuff. + */ + +GstMpeg2EncStreamWriter::GstMpeg2EncStreamWriter (GstPad *in_pad, + EncoderParams *params) : + ElemStrmWriter (*params) +{ + pad = in_pad; + buf = NULL; +} + +/* + * Output functions. + */ + +void +GstMpeg2EncStreamWriter::PutBits (guint32 val, + gint n) +{ + /* only relevant bits. Note that (according to Andrew), + * some CPUs do bitshifts modulo wordsize (32), which + * means that we have to check for n != 32 before + * bitshifting to the relevant bits (i.e. 0xffffffff << + * 32 == 0xffffffff). */ + if (n != 32) + val &= ~(0xffffffffU << n); + + /* write data */ + while (n >= outcnt) { + if (!buf) { + buf = gst_buffer_new_and_alloc (BUFSIZE); + GST_BUFFER_SIZE (buf) = 0; + } + + outbfr = (outbfr << outcnt ) | (val >> (n - outcnt)); + GST_BUFFER_DATA (buf)[GST_BUFFER_SIZE (buf)++] = outbfr; + n -= outcnt; + outcnt = 8; + bytecnt++; + + if (GST_BUFFER_SIZE (buf) >= GST_BUFFER_MAXSIZE (buf)) + FrameFlush (); + } + + /* cache remaining bits */ + if (n != 0) { + outbfr = (outbfr << n) | val; + outcnt -= n; + } +} + +void +GstMpeg2EncStreamWriter::FrameBegin () +{ +} + +void +GstMpeg2EncStreamWriter::FrameFlush () +{ + if (buf) { + gst_pad_push (pad, GST_DATA (buf)); + buf = NULL; + } +} + +void +GstMpeg2EncStreamWriter::FrameDiscard () +{ +} diff --git a/ext/mpeg2enc/gstmpeg2encstreamwriter.hh b/ext/mpeg2enc/gstmpeg2encstreamwriter.hh new file mode 100644 index 000000000..708b942e0 --- /dev/null +++ b/ext/mpeg2enc/gstmpeg2encstreamwriter.hh @@ -0,0 +1,45 @@ +/* GStreamer mpeg2enc (mjpegtools) wrapper + * (c) 2003 Ronald Bultje + * + * gstmpeg2encstreamwriter.hh: GStreamer/mpeg2enc output wrapper + * + * 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_MPEG2ENCSTREAMWRITER_H__ +#define __GST_MPEG2ENCSTREAMWRITER_H__ + +#include + +#include + +class GstMpeg2EncStreamWriter : public ElemStrmWriter { +public: + GstMpeg2EncStreamWriter (GstPad *pad, + EncoderParams *params); + + /* output functions */ + void PutBits (guint32 val, gint n); + void FrameBegin (); + void FrameFlush (); + void FrameDiscard (); + +private: + GstPad *pad; + GstBuffer *buf; +}; + +#endif /* __GST_MPEG2ENCSTREAMWRITER_H__ */ diff --git a/ext/mplex/gstmplex.cc b/ext/mplex/gstmplex.cc index 6ef731708..535b058fd 100644 --- a/ext/mplex/gstmplex.cc +++ b/ext/mplex/gstmplex.cc @@ -598,7 +598,6 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN) diff --git a/ext/sdl/sdlvideosink.c b/ext/sdl/sdlvideosink.c index 659c88c6a..b71142677 100644 --- a/ext/sdl/sdlvideosink.c +++ b/ext/sdl/sdlvideosink.c @@ -44,8 +44,8 @@ static void gst_sdlvideosink_base_init (gpointer g_class); static void gst_sdlvideosink_class_init (GstSDLVideoSinkClass *klass); static void gst_sdlvideosink_init (GstSDLVideoSink *sdl); -static void gst_sdlvideosink_interface_init (GstInterfaceClass *klass); -static gboolean gst_sdlvideosink_interface_supported (GstInterface *iface, +static void gst_sdlvideosink_interface_init (GstImplementsInterfaceClass *klass); +static gboolean gst_sdlvideosink_supported (GstImplementsInterface *iface, GType type); static void gst_sdlvideosink_xoverlay_init (GstXOverlayClass *klass); @@ -115,7 +115,7 @@ gst_sdlvideosink_get_type (void) sdlvideosink_type = g_type_register_static(GST_TYPE_VIDEOSINK, "GstSDLVideoSink", &sdlvideosink_info, 0); - g_type_add_interface_static(sdlvideosink_type, GST_TYPE_INTERFACE, + g_type_add_interface_static(sdlvideosink_type, GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info); g_type_add_interface_static(sdlvideosink_type, GST_TYPE_X_OVERLAY, &xoverlay_info); @@ -293,14 +293,14 @@ gst_sdlvideosink_init (GstSDLVideoSink *sdlvideosink) } static void -gst_sdlvideosink_interface_init (GstInterfaceClass *klass) +gst_sdlvideosink_interface_init (GstImplementsInterfaceClass *klass) { - klass->supported = gst_sdlvideosink_interface_supported; + klass->supported = gst_sdlvideosink_supported; } static gboolean -gst_sdlvideosink_interface_supported (GstInterface *interface, - GType iface_type) +gst_sdlvideosink_supported (GstImplementsInterface *interface, + GType iface_type) { g_assert (iface_type == GST_TYPE_X_OVERLAY); @@ -701,6 +701,5 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN) diff --git a/ext/shout/gstshout.c b/ext/shout/gstshout.c index cda20e7fe..2af0bc993 100644 --- a/ext/shout/gstshout.c +++ b/ext/shout/gstshout.c @@ -473,7 +473,6 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "GPL", - GST_COPYRIGHT, "libshout", "http://developer.icecast.org/libshout/" ) diff --git a/ext/smoothwave/gstsmoothwave.c b/ext/smoothwave/gstsmoothwave.c index a113bc539..57c267e51 100644 --- a/ext/smoothwave/gstsmoothwave.c +++ b/ext/smoothwave/gstsmoothwave.c @@ -310,6 +310,5 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN) diff --git a/ext/snapshot/gstsnapshot.c b/ext/snapshot/gstsnapshot.c index 8408a1503..eac0cdf86 100644 --- a/ext/snapshot/gstsnapshot.c +++ b/ext/snapshot/gstsnapshot.c @@ -385,6 +385,5 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN) diff --git a/ext/sndfile/gstsf.c b/ext/sndfile/gstsf.c index af961a8ca..34a8b60f7 100644 --- a/ext/sndfile/gstsf.c +++ b/ext/sndfile/gstsf.c @@ -829,6 +829,5 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN) diff --git a/ext/swfdec/gstswfdec.c b/ext/swfdec/gstswfdec.c index 74a731cda..4cf19378d 100644 --- a/ext/swfdec/gstswfdec.c +++ b/ext/swfdec/gstswfdec.c @@ -630,7 +630,6 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, GST_LICENSE, - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN ) diff --git a/ext/tarkin/gsttarkin.c b/ext/tarkin/gsttarkin.c index e4619c663..c98873f38 100644 --- a/ext/tarkin/gsttarkin.c +++ b/ext/tarkin/gsttarkin.c @@ -44,6 +44,5 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN) diff --git a/ext/xvid/gstxvid.c b/ext/xvid/gstxvid.c index 44f40b852..4ed5733cb 100644 --- a/ext/xvid/gstxvid.c +++ b/ext/xvid/gstxvid.c @@ -101,6 +101,5 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "GPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN) diff --git a/gst-libs/gst/Makefile.am b/gst-libs/gst/Makefile.am index 68d20eb74..c54b55fef 100644 --- a/gst-libs/gst/Makefile.am +++ b/gst-libs/gst/Makefile.am @@ -1,25 +1,27 @@ if USE_GCONF -GCONF_DIR=gconf +GCONF_DIR = gconf else -GCONF_DIR= +GCONF_DIR = endif if USE_X -X_DIR=xwindowlistener +X_DIR = xwindowlistener xoverlay +X_INTERFACE_LIBS = xoverlay/libgstxoverlay.la else -X_DIR= +X_DIR = +X_INTERFACE_LIBS = endif SUBDIRS = audio colorbalance floatcast \ $(GCONF_DIR) idct media-info \ mixer navigation play propertyprobe \ - resample riff tuner video \ - xoverlay $(X_DIR) + resample riff tag tuner video \ + $(X_DIR) DIST_SUBDIRS = audio colorbalance floatcast \ gconf idct media-info \ mixer navigation play propertyprobe \ - resample riff tuner video \ + resample riff tag tuner video \ xoverlay xwindowlistener @@ -33,7 +35,7 @@ libgstinterfaces_@GST_MAJORMINOR@_la_LIBADD = \ navigation/libgstnavigation.la \ propertyprobe/libgstpropertyprobe.la \ tuner/libgsttuner.la \ - xoverlay/libgstxoverlay.la \ + $(X_INTERFACE_LIBS) \ $(GST_LIBS) libgstinterfaces_@GST_MAJORMINOR@_la_LDFLAGS = @GST_PLUGINS_LT_LDFLAGS@ -version-info @GST_PLUGINS_LIBVERSION@ diff --git a/gst-libs/gst/audio/audio.c b/gst-libs/gst/audio/audio.c index 3ae47b1e2..f3c85a59f 100644 --- a/gst-libs/gst/audio/audio.c +++ b/gst-libs/gst/audio/audio.c @@ -199,7 +199,6 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, GST_LICENSE, - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN ); diff --git a/gst-libs/gst/audio/audioclock.h b/gst-libs/gst/audio/audioclock.h index f588dee86..17439242b 100644 --- a/gst-libs/gst/audio/audioclock.h +++ b/gst-libs/gst/audio/audioclock.h @@ -60,13 +60,13 @@ struct _GstAudioClock { gboolean active; - GST_OBJECT_PADDING + gpointer _gst_reserved[GST_PADDING]; }; struct _GstAudioClockClass { GstSystemClockClass parent_class; - GST_CLASS_PADDING + gpointer _gst_reserved[GST_PADDING]; }; GType gst_audio_clock_get_type (void); diff --git a/gst-libs/gst/audio/gstaudiofilter.c b/gst-libs/gst/audio/gstaudiofilter.c index c097b5d3f..adbb97485 100644 --- a/gst-libs/gst/audio/gstaudiofilter.c +++ b/gst-libs/gst/audio/gstaudiofilter.c @@ -316,7 +316,7 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - NULL, GST_PACKAGE, GST_ORIGIN ) + diff --git a/gst-libs/gst/audio/gstaudiofilterexample.c b/gst-libs/gst/audio/gstaudiofilterexample.c index bfa711c27..15e111af4 100644 --- a/gst-libs/gst/audio/gstaudiofilterexample.c +++ b/gst-libs/gst/audio/gstaudiofilterexample.c @@ -165,7 +165,6 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - NULL, GST_PACKAGE, GST_ORIGIN ) diff --git a/gst-libs/gst/colorbalance/Makefile.am b/gst-libs/gst/colorbalance/Makefile.am index dc8bd0ea6..a86319c24 100644 --- a/gst-libs/gst/colorbalance/Makefile.am +++ b/gst-libs/gst/colorbalance/Makefile.am @@ -9,5 +9,25 @@ noinst_LTLIBRARIES = libgstcolorbalance.la libgstcolorbalance_la_SOURCES = \ colorbalance.c \ - colorbalancechannel.c + colorbalancechannel.c \ + colorbalancemarshal.c libgstcolorbalance_la_CFLAGS = $(GST_CFLAGS) $(GST_OPT_CFLAGS) + +BUILT_SOURCES = \ + colorbalancemarshal.c \ + colorbalancemarshal.h +built_headers = \ + colorbalancemarshal.h + +EXTRA_DIST = colorbalancemarshal.list + +CLEANFILES = $(BUILT_SOURCES) + +colorbalancemarshal.h: colorbalancemarshal.list + glib-genmarshal --header --prefix=gst_color_balance_marshal $^ > colorbalancemarshal.h.tmp + mv colorbalancemarshal.h.tmp colorbalancemarshal.h + +colorbalancemarshal.c: colorbalancemarshal.list + echo "#include \"colorbalancemarshal.h\"" >> colorbalancemarshal.c.tmp + glib-genmarshal --body --prefix=gst_color_balance_marshal $^ >> colorbalancemarshal.c.tmp + mv colorbalancemarshal.c.tmp colorbalancemarshal.c diff --git a/gst-libs/gst/colorbalance/colorbalance.c b/gst-libs/gst/colorbalance/colorbalance.c index 829cf5f63..163111cd6 100644 --- a/gst-libs/gst/colorbalance/colorbalance.c +++ b/gst-libs/gst/colorbalance/colorbalance.c @@ -25,9 +25,17 @@ #endif #include "colorbalance.h" +#include "colorbalancemarshal.h" + +enum { + VALUE_CHANGED, + LAST_SIGNAL +}; static void gst_color_balance_class_init (GstColorBalanceClass *klass); +static guint gst_color_balance_signals[LAST_SIGNAL] = { 0 }; + GType gst_color_balance_get_type (void) { @@ -50,7 +58,7 @@ gst_color_balance_get_type (void) "GstColorBalance", &gst_color_balance_info, 0); g_type_interface_add_prerequisite (gst_color_balance_type, - GST_TYPE_INTERFACE); + GST_TYPE_IMPLEMENTS_INTERFACE); } return gst_color_balance_type; @@ -59,6 +67,21 @@ gst_color_balance_get_type (void) static void gst_color_balance_class_init (GstColorBalanceClass *klass) { + static gboolean initialized = FALSE; + + if (!initialized) { + gst_color_balance_signals[VALUE_CHANGED] = + g_signal_new ("value_changed", + GST_TYPE_COLOR_BALANCE, G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstColorBalanceClass, value_changed), + NULL, NULL, + gst_color_balance_marshal_VOID__OBJECT_INT, + G_TYPE_NONE, 2, + GST_TYPE_COLOR_BALANCE_CHANNEL, G_TYPE_INT); + + initialized = TRUE; + } + /* default virtual functions */ klass->list_channels = NULL; klass->set_value = NULL; @@ -101,3 +124,15 @@ gst_color_balance_get_value (GstColorBalance *balance, return channel->min_value; } + +void +gst_color_balance_value_changed (GstColorBalance *balance, + GstColorBalanceChannel *channel, + gint value) +{ + g_signal_emit (G_OBJECT (balance), + gst_color_balance_signals[VALUE_CHANGED], + 0, channel, value); + + g_signal_emit_by_name (G_OBJECT (channel), "value_changed", value); +} diff --git a/gst-libs/gst/colorbalance/colorbalance.h b/gst-libs/gst/colorbalance/colorbalance.h index 2b9d27d3a..f4a0d78a1 100644 --- a/gst-libs/gst/colorbalance/colorbalance.h +++ b/gst-libs/gst/colorbalance/colorbalance.h @@ -30,13 +30,13 @@ G_BEGIN_DECLS #define GST_TYPE_COLOR_BALANCE \ (gst_color_balance_get_type ()) #define GST_COLOR_BALANCE(obj) \ - (GST_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_COLOR_BALANCE, \ - GstColorBalance)) + (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_COLOR_BALANCE, \ + GstColorBalance)) #define GST_COLOR_BALANCE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_COLOR_BALANCE, \ GstColorBalanceClass)) #define GST_IS_COLOR_BALANCE(obj) \ - (GST_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_COLOR_BALANCE)) + (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_COLOR_BALANCE)) #define GST_IS_COLOR_BALANCE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_COLOR_BALANCE)) #define GST_COLOR_BALANCE_GET_CLASS(inst) \ @@ -55,6 +55,13 @@ typedef struct _GstColorBalanceClass { gint value); gint (* get_value) (GstColorBalance *balance, GstColorBalanceChannel *channel); + + /* signals */ + void (* value_changed) (GstColorBalance *balance, + GstColorBalanceChannel *channel, + gint value); + + gpointer _gst_reserved[GST_PADDING]; } GstColorBalanceClass; GType gst_color_balance_get_type (void); @@ -68,6 +75,11 @@ void gst_color_balance_set_value (GstColorBalance *balance, gint gst_color_balance_get_value (GstColorBalance *balance, GstColorBalanceChannel *channel); +/* trigger signal */ +void gst_color_balance_value_changed (GstColorBalance *balance, + GstColorBalanceChannel *channel, + gint value); + G_END_DECLS #endif /* __GST_COLOR_BALANCE_H__ */ diff --git a/gst-libs/gst/colorbalance/colorbalancechannel.c b/gst-libs/gst/colorbalance/colorbalancechannel.c index 8241bfe70..f87101200 100644 --- a/gst-libs/gst/colorbalance/colorbalancechannel.c +++ b/gst-libs/gst/colorbalance/colorbalancechannel.c @@ -96,8 +96,7 @@ gst_color_balance_channel_dispose (GObject *object) { GstColorBalanceChannel *channel = GST_COLOR_BALANCE_CHANNEL (object); - if (channel->label) - g_free (channel->label); + g_free (channel->label); if (parent_class->dispose) parent_class->dispose (object); diff --git a/gst-libs/gst/colorbalance/colorbalancechannel.h b/gst-libs/gst/colorbalance/colorbalancechannel.h index 5f738ecb8..23f73f8ec 100644 --- a/gst-libs/gst/colorbalance/colorbalancechannel.h +++ b/gst-libs/gst/colorbalance/colorbalancechannel.h @@ -53,6 +53,8 @@ typedef struct _GstColorBalanceChannelClass { /* signals */ void (* value_changed) (GstColorBalanceChannel *channel, gint value); + + gpointer _gst_reserved[GST_PADDING]; } GstColorBalanceChannelClass; GType gst_color_balance_channel_get_type (void); diff --git a/gst-libs/gst/colorbalance/colorbalancemarshal.list b/gst-libs/gst/colorbalance/colorbalancemarshal.list new file mode 100644 index 000000000..b9d0c499a --- /dev/null +++ b/gst-libs/gst/colorbalance/colorbalancemarshal.list @@ -0,0 +1 @@ +VOID:OBJECT,INT diff --git a/gst-libs/gst/idct/idct.c b/gst-libs/gst/idct/idct.c index 4e62a4717..59c6a844d 100644 --- a/gst-libs/gst/idct/idct.c +++ b/gst-libs/gst/idct/idct.c @@ -141,7 +141,6 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, GST_LICENSE, - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN ) diff --git a/gst-libs/gst/media-info/media-info.h b/gst-libs/gst/media-info/media-info.h index 4ff628198..069bfd7c0 100644 --- a/gst-libs/gst/media-info/media-info.h +++ b/gst-libs/gst/media-info/media-info.h @@ -35,7 +35,7 @@ struct _GstMediaInfo GstMediaInfoPriv *priv; - GST_OBJECT_PADDING + gpointer _gst_reserved[GST_PADDING]; }; struct _GstMediaInfoClass @@ -45,7 +45,7 @@ struct _GstMediaInfoClass /* signals */ void (*media_info_signal) (GstMediaInfo *gst_media_info); - GST_CLASS_PADDING + gpointer _gst_reserved[GST_PADDING]; }; /* structure for "physical" stream, diff --git a/gst-libs/gst/mixer/Makefile.am b/gst-libs/gst/mixer/Makefile.am index 193b5a107..ca153dd0a 100644 --- a/gst-libs/gst/mixer/Makefile.am +++ b/gst-libs/gst/mixer/Makefile.am @@ -9,5 +9,25 @@ noinst_LTLIBRARIES = libgstmixer.la libgstmixer_la_SOURCES = \ mixer.c \ - mixertrack.c + mixertrack.c \ + mixermarshal.c libgstmixer_la_CFLAGS = $(GST_CFLAGS) + +BUILT_SOURCES = \ + mixermarshal.c \ + mixermarshal.h +built_headers = \ + mixermarshal.h + +EXTRA_DIST = mixermarshal.list + +CLEANFILES = $(BUILT_SOURCES) + +mixermarshal.h: mixermarshal.list + glib-genmarshal --header --prefix=gst_mixer_marshal $^ > mixermarshal.h.tmp + mv mixermarshal.h.tmp mixermarshal.h + +mixermarshal.c: mixermarshal.list + echo "#include \"mixermarshal.h\"" >> mixermarshal.c.tmp + glib-genmarshal --body --prefix=gst_mixer_marshal $^ >> mixermarshal.c.tmp + mv mixermarshal.c.tmp mixermarshal.c diff --git a/gst-libs/gst/mixer/mixer.c b/gst-libs/gst/mixer/mixer.c index 28d10e6a2..cbdfdad4a 100644 --- a/gst-libs/gst/mixer/mixer.c +++ b/gst-libs/gst/mixer/mixer.c @@ -24,9 +24,19 @@ #endif #include "mixer.h" +#include "mixermarshal.h" + +enum { + MUTE_TOGGLED, + RECORD_TOGGLED, + VOLUME_CHANGED, + LAST_SIGNAL +}; static void gst_mixer_class_init (GstMixerClass *klass); +static guint gst_mixer_signals[LAST_SIGNAL] = { 0 }; + GType gst_mixer_get_type (void) { @@ -49,7 +59,7 @@ gst_mixer_get_type (void) "GstMixer", &gst_mixer_info, 0); g_type_interface_add_prerequisite (gst_mixer_type, - GST_TYPE_INTERFACE); + GST_TYPE_IMPLEMENTS_INTERFACE); } return gst_mixer_type; @@ -58,6 +68,34 @@ gst_mixer_get_type (void) static void gst_mixer_class_init (GstMixerClass *klass) { + static gboolean initialized = FALSE; + + if (!initialized) { + gst_mixer_signals[RECORD_TOGGLED] = + g_signal_new ("record_toggled", + GST_TYPE_MIXER, G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstMixerClass, record_toggled), + NULL, NULL, + gst_mixer_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 1, + GST_TYPE_MIXER_TRACK, G_TYPE_BOOLEAN); + gst_mixer_signals[MUTE_TOGGLED] = + g_signal_new ("mute_toggled", + GST_TYPE_MIXER, G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstMixerClass, mute_toggled), + NULL, NULL, + gst_mixer_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 1, + GST_TYPE_MIXER_TRACK, G_TYPE_BOOLEAN); + gst_mixer_signals[VOLUME_CHANGED] = + g_signal_new ("volume_changed", + GST_TYPE_MIXER, G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstMixerClass, volume_changed), + NULL, NULL, + gst_mixer_marshal_VOID__OBJECT_POINTER, G_TYPE_NONE, 1, + GST_TYPE_MIXER_TRACK, G_TYPE_POINTER); + + initialized = TRUE; + } + /* default virtual functions */ klass->list_tracks = NULL; klass->set_volume = NULL; @@ -131,3 +169,45 @@ gst_mixer_set_record (GstMixer *mixer, klass->set_record (mixer, track, record); } } + +void +gst_mixer_mute_toggled (GstMixer *mixer, + GstMixerTrack *track, + gboolean mute) +{ + g_signal_emit (G_OBJECT (mixer), + gst_mixer_signals[MUTE_TOGGLED], 0, + track, mute); + + g_signal_emit_by_name (G_OBJECT (track), + "mute_toggled", + mute); +} + +void +gst_mixer_record_toggled (GstMixer *mixer, + GstMixerTrack *track, + gboolean record) +{ + g_signal_emit (G_OBJECT (mixer), + gst_mixer_signals[RECORD_TOGGLED], 0, + track, record); + + g_signal_emit_by_name (G_OBJECT (track), + "record_toggled", + record); +} + +void +gst_mixer_volume_changed (GstMixer *mixer, + GstMixerTrack *track, + gint *volumes) +{ + g_signal_emit (G_OBJECT (mixer), + gst_mixer_signals[VOLUME_CHANGED], 0, + track, volumes); + + g_signal_emit_by_name (G_OBJECT (track), + "volume_changed", + volumes); +} diff --git a/gst-libs/gst/mixer/mixer.h b/gst-libs/gst/mixer/mixer.h index 6ee49e3ac..cfc168754 100644 --- a/gst-libs/gst/mixer/mixer.h +++ b/gst-libs/gst/mixer/mixer.h @@ -30,11 +30,11 @@ G_BEGIN_DECLS #define GST_TYPE_MIXER \ (gst_mixer_get_type ()) #define GST_MIXER(obj) \ - (GST_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MIXER, GstMixer)) + (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MIXER, GstMixer)) #define GST_MIXER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MIXER, GstMixerClass)) #define GST_IS_MIXER(obj) \ - (GST_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MIXER)) + (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MIXER)) #define GST_IS_MIXER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MIXER)) #define GST_MIXER_GET_CLASS(inst) \ @@ -62,25 +62,47 @@ typedef struct _GstMixerClass { GstMixerTrack *track, gboolean record); - GST_CLASS_PADDING + /* signals */ + void (* mute_toggled) (GstMixer *mixer, + GstMixerTrack *channel, + gboolean mute); + void (* record_toggled) (GstMixer *mixer, + GstMixerTrack *channel, + gboolean record); + void (* volume_changed) (GstMixer *mixer, + GstMixerTrack *channel, + gint *volumes); + + gpointer _gst_reserved[GST_PADDING]; } GstMixerClass; GType gst_mixer_get_type (void); /* virtual class function wrappers */ -const GList * gst_mixer_list_tracks (GstMixer *mixer); -void gst_mixer_set_volume (GstMixer *mixer, - GstMixerTrack *track, - gint *volumes); -void gst_mixer_get_volume (GstMixer *mixer, - GstMixerTrack *track, - gint *volumes); -void gst_mixer_set_mute (GstMixer *mixer, - GstMixerTrack *track, - gboolean mute); -void gst_mixer_set_record (GstMixer *mixer, - GstMixerTrack *track, - gboolean record); +const GList * gst_mixer_list_tracks (GstMixer *mixer); +void gst_mixer_set_volume (GstMixer *mixer, + GstMixerTrack *track, + gint *volumes); +void gst_mixer_get_volume (GstMixer *mixer, + GstMixerTrack *track, + gint *volumes); +void gst_mixer_set_mute (GstMixer *mixer, + GstMixerTrack *track, + gboolean mute); +void gst_mixer_set_record (GstMixer *mixer, + GstMixerTrack *track, + gboolean record); + +/* trigger signals */ +void gst_mixer_mute_toggled (GstMixer *mixer, + GstMixerTrack *track, + gboolean mute); +void gst_mixer_record_toggled (GstMixer *mixer, + GstMixerTrack *track, + gboolean record); +void gst_mixer_volume_changed (GstMixer *mixer, + GstMixerTrack *track, + gint *volumes); G_END_DECLS diff --git a/gst-libs/gst/mixer/mixermarshal.list b/gst-libs/gst/mixer/mixermarshal.list new file mode 100644 index 000000000..ac2cd6b88 --- /dev/null +++ b/gst-libs/gst/mixer/mixermarshal.list @@ -0,0 +1,2 @@ +VOID:OBJECT,BOOLEAN +VOID:OBJECT,POINTER diff --git a/gst-libs/gst/mixer/mixertrack.h b/gst-libs/gst/mixer/mixertrack.h index cb0108225..7776a3537 100644 --- a/gst-libs/gst/mixer/mixertrack.h +++ b/gst-libs/gst/mixer/mixertrack.h @@ -71,12 +71,15 @@ typedef struct _GstMixerTrack { typedef struct _GstMixerTrackClass { GObjectClass parent; + /* signals */ void (* mute_toggled) (GstMixerTrack *channel, - gboolean on); + gboolean mute); void (* record_toggled) (GstMixerTrack *channel, - gboolean on); + gboolean record); void (* volume_changed) (GstMixerTrack *channel, gint *volumes); + + gpointer _gst_reserved[GST_PADDING]; } GstMixerTrackClass; GType gst_mixer_track_get_type (void); diff --git a/gst-libs/gst/navigation/navigation.h b/gst-libs/gst/navigation/navigation.h index 22a66632d..faa5b809f 100644 --- a/gst-libs/gst/navigation/navigation.h +++ b/gst-libs/gst/navigation/navigation.h @@ -44,7 +44,7 @@ typedef struct _GstNavigationInterface { /* virtual functions */ void (*send_event) (GstNavigation *navigation, GstStructure *structure); - GST_CLASS_PADDING + gpointer _gst_reserved[GST_PADDING]; } GstNavigationInterface; GType gst_navigation_get_type (void); diff --git a/gst-libs/gst/play/Makefile.am b/gst-libs/gst/play/Makefile.am index 360fff49d..db444521f 100644 --- a/gst-libs/gst/play/Makefile.am +++ b/gst-libs/gst/play/Makefile.am @@ -2,13 +2,13 @@ librarydir = $(libdir) library_LTLIBRARIES = libgstplay-@GST_MAJORMINOR@.la -libgstplay_@GST_MAJORMINOR@_la_SOURCES = play.c +libgstplay_@GST_MAJORMINOR@_la_SOURCES = gstplay.c libgstplay_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/play -libgstplay_@GST_MAJORMINOR@include_HEADERS = play.h +libgstplay_@GST_MAJORMINOR@include_HEADERS = gstplay.h libgstplay_@GST_MAJORMINOR@_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_CFLAGS) libgstplay_@GST_MAJORMINOR@_la_LIBADD = $(GST_LIBS) $(GST_PLUGINS_LIBS) $(GST_CONTROL_LIBS) -libgstplay_@GST_MAJORMINOR@_la_LDFLAGS = -version-info @GST_PLUGINS_LIBVERSION@ +libgstplay_@GST_MAJORMINOR@_la_LDFLAGS = \ + -version-info @GST_PLUGINS_LIBVERSION@ -noinst_HEADERS = playpipelines.c diff --git a/gst-libs/gst/play/gstplay.c b/gst-libs/gst/play/gstplay.c new file mode 100644 index 000000000..e4c652a54 --- /dev/null +++ b/gst-libs/gst/play/gstplay.c @@ -0,0 +1,1004 @@ +/* GStreamer + * Copyright (C) 2003 Julien Moutte + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include + +#include "gstplay.h" + +enum +{ + TIME_TICK, + STREAM_LENGTH, + HAVE_VIDEO_SIZE, + LAST_SIGNAL +}; + +struct _GstPlayPrivate { + char *location; + + GHashTable *elements; + + gint64 time_nanos; + gint64 length_nanos; + + gint get_length_attempt; + + guint tick_id; + guint length_id; +}; + +static guint gst_play_signals[LAST_SIGNAL] = { 0 }; + +static GstPipelineClass *parent_class = NULL; + +/* ======================================================= */ +/* */ +/* Private Methods */ +/* */ +/* ======================================================= */ + +static gboolean +gst_play_pipeline_setup (GstPlay *play) +{ + GstElement *work_thread, *video_thread; + GstElement *source, *autoplugger, *video_switch; + GstElement *video_queue, *video_colorspace, *video_scaler, *video_sink; + GstElement *audio_thread, *audio_queue, *audio_volume, *audio_sink; + GstElement *audio_tee, *vis_thread, *vis_queue, *vis_element; + GstPad *audio_tee_pad1, *audio_tee_pad2, *vis_thread_pad, *audio_sink_pad; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + work_thread = gst_element_factory_make ("thread", "work_thread"); + if (!GST_IS_ELEMENT (work_thread)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "work_thread", work_thread); + gst_bin_add (GST_BIN (play), work_thread); + + /* Placeholder for the source and autoplugger { fakesrc ! spider } */ + source = gst_element_factory_make ("fakesrc", "source"); + if (!GST_IS_ELEMENT (source)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "source", source); + + autoplugger = gst_element_factory_make ("spider", "autoplugger"); + if (!GST_IS_ELEMENT (autoplugger)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "autoplugger", autoplugger); + + gst_bin_add_many (GST_BIN (work_thread), source, autoplugger, NULL); + gst_element_link (source, autoplugger); + + /* Creating our video output bin + { queue ! colorspace ! videoscale ! fakesink } */ + video_thread = gst_element_factory_make ("thread", "video_thread"); + if (!GST_IS_ELEMENT (video_thread)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "video_thread", video_thread); + gst_bin_add (GST_BIN (work_thread), video_thread); + + /* Buffer queue for our video thread */ + video_queue = gst_element_factory_make ("queue", "video_queue"); + if (!GST_IS_ELEMENT (video_queue)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "video_queue", video_queue); + + /* Colorspace conversion */ + /* FIXME: Use ffcolorspace and fallback to Hermes on failure ?*/ + video_colorspace = gst_element_factory_make ("colorspace", + "video_colorspace"); + if (!GST_IS_ELEMENT (video_colorspace)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "video_colorspace", + video_colorspace); + + /* Software scaling of video stream */ + video_scaler = gst_element_factory_make ("videoscale", "video_scaler"); + if (!GST_IS_ELEMENT (video_scaler)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "video_scaler", video_scaler); + + /* Placeholder for future video sink bin */ + video_sink = gst_element_factory_make ("fakesink", "video_sink"); + if (!GST_IS_ELEMENT (video_sink)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "video_sink", video_sink); + + /* Linking, Adding, Ghosting */ + gst_element_link_many (video_queue, video_colorspace, + video_scaler, video_sink, NULL); + gst_bin_add_many (GST_BIN (video_thread), video_queue, video_colorspace, + video_scaler, video_sink, NULL); + gst_element_add_ghost_pad (video_thread, + gst_element_get_pad (video_queue, "sink"), + "sink"); + + video_switch = gst_element_factory_make ("switch", + "video_switch"); + if (!GST_IS_ELEMENT (video_switch)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "video_switch", video_switch); + + gst_bin_add (GST_BIN (work_thread), video_switch); + + /* Connecting autoplugger to video switch and video switch to video output + gst_element_link (autoplugger, video_switch); + gst_element_link (video_switch, video_thread);*/ + gst_element_link (autoplugger, video_thread); + + /* Creating our audio output bin + { queue ! volume ! tee ! { queue ! goom } ! fakesink } */ + audio_thread = gst_element_factory_make ("thread", "audio_thread"); + if (!GST_IS_ELEMENT (audio_thread)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "audio_thread", audio_thread); + gst_bin_add (GST_BIN (work_thread), audio_thread); + + /* Buffer queue for our audio thread */ + audio_queue = gst_element_factory_make ("queue", "audio_queue"); + if (!GST_IS_ELEMENT (audio_queue)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "audio_queue", audio_queue); + + /* Volume control */ + audio_volume = gst_element_factory_make ("volume", "audio_volume"); + if (!GST_IS_ELEMENT (audio_volume)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "audio_volume", audio_volume); + + /* Duplicate audio signal to sink and visualization thread */ + audio_tee = gst_element_factory_make ("tee", "audio_tee"); + if (!GST_IS_ELEMENT (audio_tee)) + return FALSE; + + audio_tee_pad1 = gst_element_get_request_pad (audio_tee, "src%d"); + audio_tee_pad2 = gst_element_get_request_pad (audio_tee, "src%d"); + g_hash_table_insert (play->priv->elements, "audio_tee_pad1", + audio_tee_pad1); + g_hash_table_insert (play->priv->elements, "audio_tee_pad2", + audio_tee_pad2); + g_hash_table_insert (play->priv->elements, "audio_tee", audio_tee); + + /* Placeholder for future audio sink bin */ + audio_sink = gst_element_factory_make ("fakesink", "audio_sink"); + if (!GST_IS_ELEMENT (audio_sink)) + return FALSE; + + audio_sink_pad = gst_element_get_pad (audio_sink, "sink"); + g_hash_table_insert (play->priv->elements, "audio_sink_pad", + audio_sink_pad); + g_hash_table_insert (play->priv->elements, "audio_sink", audio_sink); + + /* Visualization thread */ + vis_thread = gst_element_factory_make ("thread", "vis_thread"); + if (!GST_IS_ELEMENT (vis_thread)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "vis_thread", vis_thread); + + /* Buffer queue for our visualization thread */ + vis_queue = gst_element_factory_make ("queue", "vis_queue"); + if (!GST_IS_ELEMENT (vis_queue)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "vis_queue", vis_queue); + + vis_element = gst_element_factory_make ("identity", "vis_element"); + if (!GST_IS_ELEMENT (vis_element)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "vis_element", vis_element); + + /* Adding, Linking, Ghosting in visualization */ + gst_bin_add_many (GST_BIN (vis_thread), vis_queue, vis_element, NULL); + gst_element_link (vis_queue, vis_element); + vis_thread_pad = gst_element_add_ghost_pad (vis_thread, + gst_element_get_pad (vis_queue, "sink"), + "sink"); + g_hash_table_insert (play->priv->elements, "vis_thread_pad", + vis_thread_pad); + + + /* Linking, Adding, Ghosting in audio */ + gst_element_link_many (audio_queue, audio_volume, audio_tee, NULL); + gst_pad_link (audio_tee_pad1, audio_sink_pad); + gst_bin_add_many (GST_BIN (audio_thread), audio_queue, audio_volume, + audio_tee, vis_thread, audio_sink, NULL); + gst_element_add_ghost_pad (audio_thread, + gst_element_get_pad (audio_queue, "sink"), + "sink"); + + /* Connecting audio output to autoplugger */ + gst_element_link (autoplugger, audio_thread); + + return TRUE; +} + +static void +gst_play_have_video_size (GstElement *element, gint width, + gint height, GstPlay *play) +{ + g_return_if_fail (play != NULL); + g_return_if_fail (GST_IS_PLAY (play)); + g_signal_emit (G_OBJECT (play), gst_play_signals[HAVE_VIDEO_SIZE], + 0, width, height); +} + +static gboolean +gst_play_tick_callback (GstPlay *play) +{ + GstClock *clock = NULL; + + g_return_val_if_fail (play != NULL, FALSE); + + if (!GST_IS_PLAY (play)) { + play->priv->tick_id = 0; + return FALSE; + } + + clock = gst_bin_get_clock (GST_BIN (play)); + play->priv->time_nanos = gst_clock_get_time (clock); + + g_signal_emit (G_OBJECT (play), gst_play_signals[TIME_TICK], + 0,play->priv->time_nanos); + + if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) + return TRUE; + else { + play->priv->tick_id = 0; + return FALSE; + } +} + +static gboolean +gst_play_get_length_callback (GstPlay *play) +{ + GstElement *audio_sink_element, *video_sink_element; + GstFormat format = GST_FORMAT_TIME; + gint64 value; + gboolean q = FALSE; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + /* We try to get length from all real sink elements */ + audio_sink_element = g_hash_table_lookup (play->priv->elements, + "audio_sink_element"); + video_sink_element = g_hash_table_lookup (play->priv->elements, + "video_sink_element"); + if (!GST_IS_ELEMENT (audio_sink_element) && + !GST_IS_ELEMENT (video_sink_element)) { + play->priv->length_id = 0; + return FALSE; + } + + /* Audio first and then Video */ + q = gst_element_query (audio_sink_element, GST_QUERY_TOTAL, &format, &value); + if (!q) + q = gst_element_query (video_sink_element, GST_QUERY_TOTAL, &format, + &value); + + if (q) { + play->priv->length_nanos = value; + g_signal_emit (G_OBJECT (play), gst_play_signals[STREAM_LENGTH], + 0,play->priv->length_nanos); + play->priv->length_id = 0; + return FALSE; + } + + play->priv->get_length_attempt++; + + /* We try 16 times */ + if (play->priv->get_length_attempt > 15) { + play->priv->length_id = 0; + return FALSE; + } + else + return TRUE; +} + +static void +gst_play_state_change (GstElement *element, GstElementState old, + GstElementState state) +{ + GstPlay *play; + + g_return_if_fail (element != NULL); + g_return_if_fail (GST_IS_PLAY (element)); + + play = GST_PLAY (element); + + if (state == GST_STATE_PLAYING) { + if (play->priv->tick_id) { + g_source_remove (play->priv->tick_id); + play->priv->tick_id = 0; + } + + play->priv->tick_id = g_timeout_add (200, + (GSourceFunc) gst_play_tick_callback, + play); + + play->priv->get_length_attempt = 0; + + if (play->priv->length_id) { + g_source_remove (play->priv->length_id); + play->priv->length_id = 0; + } + + play->priv->length_id = g_timeout_add (200, + (GSourceFunc) gst_play_get_length_callback, + play); + } + + if (GST_ELEMENT_CLASS (parent_class)->state_change) + GST_ELEMENT_CLASS (parent_class)->state_change (element, old, state); +} + +/* =========================================== */ +/* */ +/* Init & Dispose & Class init */ +/* */ +/* =========================================== */ + +static void +gst_play_dispose (GObject *object) +{ + GstPlay *play; + + g_return_if_fail (object != NULL); + g_return_if_fail (GST_IS_PLAY (object)); + + play = GST_PLAY (object); + + if (play->priv->length_id) { + g_source_remove (play->priv->length_id); + play->priv->length_id = 0; + } + + if (play->priv->tick_id) { + g_source_remove (play->priv->tick_id); + play->priv->tick_id = 0; + } + + if (play->priv->location) { + g_free (play->priv->location); + play->priv->location = NULL; + } + + if (play->priv->elements) { + g_hash_table_destroy (play->priv->elements); + play->priv->elements = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_play_init (GstPlay *play) +{ + play->priv = g_new0 (GstPlayPrivate, 1); + play->priv->location = NULL; + play->priv->length_nanos = 0; + play->priv->time_nanos = 0; + play->priv->elements = g_hash_table_new (g_str_hash, g_str_equal); + + if (!gst_play_pipeline_setup (play)) + g_warning ("libgstplay: failed initializing pipeline"); +} + +static void +gst_play_class_init (GstPlayClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->dispose = gst_play_dispose; + + element_class->state_change = gst_play_state_change; + + gst_play_signals[TIME_TICK] = + g_signal_new ("time_tick", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GstPlayClass, time_tick), NULL, NULL, + gst_marshal_VOID__INT64, G_TYPE_NONE, 1, G_TYPE_INT64); + gst_play_signals[STREAM_LENGTH] = + g_signal_new ("stream_length", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GstPlayClass, stream_length), NULL, NULL, + gst_marshal_VOID__INT64, G_TYPE_NONE, 1, G_TYPE_INT64); + gst_play_signals[HAVE_VIDEO_SIZE] = + g_signal_new ("have_video_size", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GstPlayClass, have_video_size), NULL, NULL, + gst_marshal_VOID__INT_INT, G_TYPE_NONE, 2, + G_TYPE_INT, G_TYPE_INT); +} + +/* ======================================================= */ +/* */ +/* Public Methods */ +/* */ +/* ======================================================= */ + +/** + * gst_play_set_location: + * @play: a #GstPlay. + * @location: a const #char* indicating location to play + * + * Set location of @play to @location. + * + * Returns: TRUE if location was set successfully. + */ +gboolean +gst_play_set_location (GstPlay *play, const char *location) +{ + GstElement *work_thread, *source, *autoplugger, *video_thread, *audio_thread; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + if (play->priv->location) + g_free (play->priv->location); + + play->priv->location = g_strdup (location); + + if (GST_STATE (GST_ELEMENT (play)) != GST_STATE_READY) + gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY); + + work_thread = g_hash_table_lookup (play->priv->elements, "work_thread"); + if (!GST_IS_ELEMENT (work_thread)) + return FALSE; + video_thread = g_hash_table_lookup (play->priv->elements, "video_thread"); + if (!GST_IS_ELEMENT (video_thread)) + return FALSE; + audio_thread = g_hash_table_lookup (play->priv->elements, "audio_thread"); + if (!GST_IS_ELEMENT (audio_thread)) + return FALSE; + source = g_hash_table_lookup (play->priv->elements, "source"); + if (!GST_IS_ELEMENT (source)) + return FALSE; + autoplugger = g_hash_table_lookup (play->priv->elements, "autoplugger"); + if (!GST_IS_ELEMENT (autoplugger)) + return FALSE; + + /* Spider can autoplugg only once. We remove the actual one and put a new + autoplugger */ + gst_element_unlink (source, autoplugger); + gst_element_unlink (autoplugger, video_thread); + gst_element_unlink (autoplugger, audio_thread); + gst_bin_remove (GST_BIN (work_thread), autoplugger); + + autoplugger = gst_element_factory_make ("spider", "autoplugger"); + if (!GST_IS_ELEMENT (autoplugger)) + return FALSE; + + gst_bin_add (GST_BIN (work_thread), autoplugger); + gst_element_link (source, autoplugger); + gst_element_link (autoplugger, video_thread); + gst_element_link (autoplugger, audio_thread); + + g_hash_table_replace (play->priv->elements, "autoplugger", autoplugger); + + /* FIXME: Why don't we have an interface to do that kind of stuff ? */ + g_object_set (G_OBJECT (source), "location", play->priv->location, NULL); + + play->priv->length_nanos = 0LL; + play->priv->time_nanos = 0LL; + + g_signal_emit (G_OBJECT (play), gst_play_signals[STREAM_LENGTH], 0, 0LL); + g_signal_emit (G_OBJECT (play), gst_play_signals[TIME_TICK], 0, 0LL); + + return TRUE; +} + +/** + * gst_play_get_location: + * @play: a #GstPlay. + * + * Get current location of @play. + * + * Returns: a const #char* pointer to current location. + */ +char * +gst_play_get_location (GstPlay *play) +{ + g_return_val_if_fail (play != NULL, NULL); + g_return_val_if_fail (GST_IS_PLAY (play), NULL); + return g_strdup (play->priv->location); +} + +/** + * gst_play_seek_to_time: + * @play: a #GstPlay. + * @time_nanos: a #gint64 indicating a time position. + * + * Performs a seek on @play until @time_nanos. + */ +gboolean +gst_play_seek_to_time (GstPlay * play, gint64 time_nanos) +{ + GstElement *audio_sink_element, *video_sink_element; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + if (time_nanos < 0LL) + time_nanos = 0LL; + + audio_sink_element = g_hash_table_lookup (play->priv->elements, + "audio_sink_element"); + video_sink_element = g_hash_table_lookup (play->priv->elements, + "video_sink_element"); + + if (GST_IS_ELEMENT (audio_sink_element) && + GST_IS_ELEMENT (video_sink_element)) { + gboolean s = FALSE; + + s = gst_element_seek (audio_sink_element, GST_FORMAT_TIME | + GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH, + time_nanos); + if (!s) { + s = gst_element_seek (video_sink_element, GST_FORMAT_TIME | + GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH, + time_nanos); + } + + if (s) { + GstClock *clock = gst_bin_get_clock (GST_BIN (play)); + play->priv->time_nanos = gst_clock_get_time (clock); + g_signal_emit (G_OBJECT (play), gst_play_signals[TIME_TICK], + 0,play->priv->time_nanos); + } + } + + return TRUE; +} + +/** + * gst_play_set_data_src: + * @play: a #GstPlay. + * @data_src: a #GstElement. + * + * Set @data_src as the source element of @play. + * + * Returns: TRUE if call succeeded. + */ +gboolean +gst_play_set_data_src (GstPlay *play, GstElement *data_src) +{ + GstElement *work_thread, *old_data_src, *autoplugger; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + /* We bring back the pipeline to READY */ + if (GST_STATE (GST_ELEMENT (play)) != GST_STATE_READY) + gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY); + + /* Getting needed objects */ + work_thread = g_hash_table_lookup (play->priv->elements, "work_thread"); + if (!GST_IS_ELEMENT (work_thread)) + return FALSE; + old_data_src = g_hash_table_lookup (play->priv->elements, "source"); + if (!GST_IS_ELEMENT (old_data_src)) + return FALSE; + autoplugger = g_hash_table_lookup (play->priv->elements, "autoplugger"); + if (!GST_IS_ELEMENT (autoplugger)) + return FALSE; + + /* Unlinking old source from autoplugger, removing it from pipeline, adding + the new one and connecting it to autoplugger FIXME: we should put a new + autoplugger here as spider can autoplugg only once */ + gst_element_unlink (old_data_src, autoplugger); + gst_bin_remove (GST_BIN (work_thread), old_data_src); + gst_bin_add (GST_BIN (work_thread), data_src); + gst_element_link (data_src, autoplugger); + + g_hash_table_replace (play->priv->elements, "source", data_src); + + return TRUE; +} + +/** + * gst_play_set_video_sink: + * @play: a #GstPlay. + * @video_sink: a #GstElement. + * + * Set @video_sink as the video sink element of @play. + * + * Returns: TRUE if call succeeded. + */ +gboolean +gst_play_set_video_sink (GstPlay *play, GstElement *video_sink) +{ + GstElement *video_thread, *old_video_sink, *video_scaler, *video_sink_element; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + /* We bring back the pipeline to READY */ + if (GST_STATE (GST_ELEMENT (play)) != GST_STATE_READY) + gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY); + + /* Getting needed objects */ + video_thread = g_hash_table_lookup (play->priv->elements, "video_thread"); + if (!GST_IS_ELEMENT (video_thread)) + return FALSE; + old_video_sink = g_hash_table_lookup (play->priv->elements, "video_sink"); + if (!GST_IS_ELEMENT (old_video_sink)) + return FALSE; + video_scaler = g_hash_table_lookup (play->priv->elements, "video_scaler"); + if (!GST_IS_ELEMENT (video_scaler)) + return FALSE; + + /* Unlinking old video sink from video scaler, removing it from pipeline, + adding the new one and linking it */ + gst_element_unlink (video_scaler, old_video_sink); + gst_bin_remove (GST_BIN (video_thread), old_video_sink); + gst_bin_add (GST_BIN (video_thread), video_sink); + gst_element_link (video_scaler, video_sink); + + g_hash_table_replace (play->priv->elements, "video_sink", video_sink); + + video_sink_element = gst_play_get_sink_element (play, video_sink, + GST_PLAY_SINK_TYPE_VIDEO); + if (GST_IS_ELEMENT (video_sink_element)) { + g_hash_table_replace (play->priv->elements, "video_sink_element", + video_sink_element); + g_signal_connect (G_OBJECT (video_sink_element), "have_video_size", + G_CALLBACK (gst_play_have_video_size), play); + } + + gst_element_set_state (video_sink, GST_STATE (GST_ELEMENT(play))); + + return TRUE; +} + +/** + * gst_play_set_audio_sink: + * @play: a #GstPlay. + * @audio_sink: a #GstElement. + * + * Set @audio_sink as the audio sink element of @play. + * + * Returns: TRUE if call succeeded. + */ +gboolean +gst_play_set_audio_sink (GstPlay *play, GstElement *audio_sink) +{ + GstElement *old_audio_sink, *audio_thread, *audio_sink_element; + GstPad *audio_tee_pad1, *audio_sink_pad, *old_audio_sink_pad; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + /* We bring back the pipeline to READY */ + if (GST_STATE (GST_ELEMENT (play)) != GST_STATE_READY) + gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY); + + /* Getting needed objects */ + old_audio_sink = g_hash_table_lookup (play->priv->elements, "audio_sink"); + if (!GST_IS_ELEMENT (old_audio_sink)) + return FALSE; + old_audio_sink_pad = g_hash_table_lookup (play->priv->elements, + "audio_sink_pad"); + if (!GST_IS_PAD (old_audio_sink_pad)) + return FALSE; + audio_thread = g_hash_table_lookup (play->priv->elements, "audio_thread"); + if (!GST_IS_ELEMENT (audio_thread)) + return FALSE; + audio_tee_pad1 = g_hash_table_lookup (play->priv->elements, + "audio_tee_pad1"); + if (!GST_IS_PAD (audio_tee_pad1)) + return FALSE; + audio_sink_pad = gst_element_get_pad (audio_sink, "sink"); + if (!GST_IS_PAD (audio_sink_pad)) + return FALSE; + + /* Unlinking old audiosink, removing it from pipeline, putting the new one + and linking it */ + gst_pad_unlink (audio_tee_pad1, old_audio_sink_pad); + gst_bin_remove (GST_BIN (audio_thread), old_audio_sink); + gst_bin_add (GST_BIN (audio_thread), audio_sink); + gst_pad_link (audio_tee_pad1, audio_sink_pad); + + g_hash_table_replace (play->priv->elements, "audio_sink", audio_sink); + g_hash_table_replace (play->priv->elements, "audio_sink_pad", + audio_sink_pad); + + audio_sink_element = gst_play_get_sink_element (play, audio_sink, + GST_PLAY_SINK_TYPE_AUDIO); + if (GST_IS_ELEMENT (audio_sink_element)) { + g_hash_table_replace (play->priv->elements, "audio_sink_element", + audio_sink_element); + } + + gst_element_set_state (audio_sink, GST_STATE (GST_ELEMENT(play))); + + return TRUE; +} + +/** + * gst_play_set_visualization: + * @play: a #GstPlay. + * @element: a #GstElement. + * + * Set @video_sink as the video sink element of @play. + * + * Returns: TRUE if call succeeded. + */ +gboolean +gst_play_set_visualization (GstPlay *play, GstElement *vis_element) +{ + GstElement *old_vis_element, *vis_thread, *vis_queue/*, *video_switch*/; + gboolean was_playing = FALSE; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + /* We bring back the pipeline to READY */ + if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) { + gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED); + was_playing = TRUE; + } + + /* Getting needed objects */ + vis_thread = g_hash_table_lookup (play->priv->elements, "vis_thread"); + if (!GST_IS_ELEMENT (vis_thread)) + return FALSE; + old_vis_element = g_hash_table_lookup (play->priv->elements, + "vis_element"); + if (!GST_IS_ELEMENT (old_vis_element)) + return FALSE; + vis_queue = g_hash_table_lookup (play->priv->elements, "vis_queue"); + if (!GST_IS_ELEMENT (vis_queue)) + return FALSE; + /*video_switch = g_hash_table_lookup (play->priv->elements, "video_switch"); + if (!GST_IS_ELEMENT (video_switch)) + return FALSE;*/ + + /* Unlinking, removing the old element then adding and linking the new one */ + gst_element_unlink (vis_queue, old_vis_element); + /*gst_element_unlink (old_vis_element, video_switch);*/ + gst_bin_remove (GST_BIN (vis_thread), old_vis_element); + gst_bin_add (GST_BIN (vis_thread), vis_element); + gst_element_link (vis_queue, vis_element); + /*gst_element_link (vis_element, video_switch);*/ + + if (was_playing) + gst_element_set_state (GST_ELEMENT (play), GST_STATE_PLAYING); + + return TRUE; +} + +/** + * gst_play_connect_visualization: + * @play: a #GstPlay. + * @connect: a #gboolean indicating wether or not + * visualization should be connected. + * + * Connect or disconnect visualization bin in @play. + * + * Returns: TRUE if call succeeded. + */ +gboolean +gst_play_connect_visualization (GstPlay * play, gboolean connect) +{ + GstPad *audio_tee_pad2, *vis_thread_pad; + gboolean connected = FALSE, was_playing = FALSE; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + vis_thread_pad = g_hash_table_lookup (play->priv->elements, + "vis_thread_pad"); + if (!GST_IS_PAD (vis_thread_pad)) + return FALSE; + audio_tee_pad2 = g_hash_table_lookup (play->priv->elements, + "audio_tee_pad2"); + if (!GST_IS_PAD (audio_tee_pad2)) + return FALSE; + + if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) { + gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED); + was_playing = TRUE; + } + + if (gst_pad_get_peer (vis_thread_pad) != NULL) + connected = TRUE; + else + connected = FALSE; + + if ((connect) && (!connected)) + gst_pad_link (audio_tee_pad2, vis_thread_pad); + else if ((!connect) && (connected)) + gst_pad_unlink (audio_tee_pad2, vis_thread_pad); + + if (was_playing) + gst_element_set_state (GST_ELEMENT (play), GST_STATE_PLAYING); + + return TRUE; +} + +/** + * gst_play_get_sink_element: + * @play: a #GstPlay. + * @element: a #GstElement. + * @sink_type: a #GstPlaySinkType. + * + * Searches recursively for a sink #GstElement with + * type @sink_type in @element which is supposed to be a #GstBin. + * + * Returns: the sink #GstElement of @element. + */ +GstElement * +gst_play_get_sink_element (GstPlay *play, + GstElement *element, GstPlaySinkType sink_type) +{ + GList *elements = NULL; + const GList *pads = NULL; + gboolean has_src, has_correct_type; + + g_return_val_if_fail (play != NULL, NULL); + g_return_val_if_fail (element != NULL, NULL); + g_return_val_if_fail (GST_IS_PLAY (play), NULL); + g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); + + if (!GST_IS_BIN (element)) { + /* since its not a bin, we'll presume this + * element is a sink element */ + return element; + } + + elements = (GList *) gst_bin_get_list (GST_BIN (element)); + + /* traverse all elements looking for a src pad */ + + while (elements) { + element = GST_ELEMENT (elements->data); + + /* Recursivity :) */ + + if (GST_IS_BIN (element)) { + element = gst_play_get_sink_element (play, element, sink_type); + if (GST_IS_ELEMENT (element)) + return element; + } + else { + pads = gst_element_get_pad_list (element); + has_src = FALSE; + has_correct_type = FALSE; + while (pads) { + /* check for src pad */ + if (GST_PAD_DIRECTION (GST_PAD (pads->data)) == GST_PAD_SRC) { + has_src = TRUE; + break; + } + else { + /* If not a src pad checking caps */ + const GstCaps2 *caps; + GstStructure *structure; + gboolean has_video_cap = FALSE; + gboolean has_audio_cap = FALSE; + + caps = gst_pad_get_caps (GST_PAD (pads->data)); + structure = gst_caps2_get_nth_cap (caps, 0); + + if (strcmp (gst_structure_get_name (structure), + "audio/x-raw-int") == 0) { + has_audio_cap = TRUE; + } + + if (strcmp (gst_structure_get_name (structure), + "video/x-raw-yuv") == 0 || + strcmp (gst_structure_get_name (structure), + "video/x-raw-rgb") == 0) { + has_video_cap = TRUE; + } + + switch (sink_type) { + case GST_PLAY_SINK_TYPE_AUDIO: + if (has_audio_cap) + has_correct_type = TRUE; + break;; + case GST_PLAY_SINK_TYPE_VIDEO: + if (has_video_cap) + has_correct_type = TRUE; + break;; + case GST_PLAY_SINK_TYPE_ANY: + if ((has_video_cap) || (has_audio_cap)) + has_correct_type = TRUE; + break;; + default: + has_correct_type = FALSE; + } + } + + pads = g_list_next (pads); + + } + + if ((!has_src) && (has_correct_type)) + return element; + } + + elements = g_list_next (elements); + } + + /* we didn't find a sink element */ + + return NULL; +} + +GstPlay * +gst_play_new (void) +{ + GstPlay *play = g_object_new (GST_TYPE_PLAY, NULL); + + return play; +} + +/* =========================================== */ +/* */ +/* Object typing & Creation */ +/* */ +/* =========================================== */ + +GType +gst_play_get_type (void) +{ + static GType play_type = 0; + + if (!play_type) { + static const GTypeInfo play_info = { + sizeof (GstPlayClass), + NULL, + NULL, + (GClassInitFunc) gst_play_class_init, + NULL, + NULL, + sizeof (GstPlay), + 0, + (GInstanceInitFunc) gst_play_init, + NULL + }; + + play_type = g_type_register_static (GST_TYPE_PIPELINE, "GstPlay", + &play_info, 0); + } + + return play_type; +} diff --git a/gst-libs/gst/play/gstplay.h b/gst-libs/gst/play/gstplay.h new file mode 100644 index 000000000..0c45d9431 --- /dev/null +++ b/gst-libs/gst/play/gstplay.h @@ -0,0 +1,89 @@ +/* GStreamer + * Copyright (C) 2003 Julien Moutte + * + * 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_PLAY_H__ +#define __GST_PLAY_H__ + +#include + +#define GST_TYPE_PLAY (gst_play_get_type()) +#define GST_PLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PLAY, GstPlay)) +#define GST_PLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PLAY, GstPlayClass)) +#define GST_IS_PLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PLAY)) +#define GST_IS_PLAY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PLAY)) +#define GST_PLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PLAY, GstPlayClass)) + +typedef enum +{ + GST_PLAY_SINK_TYPE_AUDIO, + GST_PLAY_SINK_TYPE_VIDEO, + GST_PLAY_SINK_TYPE_ANY, +} GstPlaySinkType; + +typedef struct _GstPlay GstPlay; +typedef struct _GstPlayClass GstPlayClass; +typedef struct _GstPlayPrivate GstPlayPrivate; + +struct _GstPlay +{ + GstPipeline pipeline; + + GstPlayPrivate *priv; + + gpointer _gst_reserved[GST_PADDING]; +}; + +struct _GstPlayClass +{ + GstPipelineClass parent_class; + + void (*time_tick) (GstPlay *play, gint64 time_nanos); + void (*stream_length) (GstPlay *play, gint64 length_nanos); + void (*have_video_size) (GstPlay *play, gint width, gint height); + + gpointer _gst_reserved[GST_PADDING]; +}; + +GType gst_play_get_type (void); +GstPlay * gst_play_new (void); + +gboolean gst_play_set_data_src (GstPlay *play, + GstElement *data_src); +gboolean gst_play_set_video_sink (GstPlay *play, + GstElement *video_sink); +gboolean gst_play_set_audio_sink (GstPlay *play, + GstElement *audio_sink); + +gboolean gst_play_set_visualization (GstPlay *play, + GstElement *element); +gboolean gst_play_connect_visualization (GstPlay *play, + gboolean connect); + +gboolean gst_play_set_location (GstPlay *play, + const char *location); +char * gst_play_get_location (GstPlay *play); + +gboolean gst_play_seek_to_time (GstPlay *play, + gint64 time_nanos); + +GstElement * gst_play_get_sink_element (GstPlay *play, + GstElement *element, + GstPlaySinkType sink_type); + +#endif /* __GST_PLAY_H__ */ diff --git a/gst-libs/gst/play/play.c b/gst-libs/gst/play/play.c new file mode 100644 index 000000000..e4c652a54 --- /dev/null +++ b/gst-libs/gst/play/play.c @@ -0,0 +1,1004 @@ +/* GStreamer + * Copyright (C) 2003 Julien Moutte + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include + +#include "gstplay.h" + +enum +{ + TIME_TICK, + STREAM_LENGTH, + HAVE_VIDEO_SIZE, + LAST_SIGNAL +}; + +struct _GstPlayPrivate { + char *location; + + GHashTable *elements; + + gint64 time_nanos; + gint64 length_nanos; + + gint get_length_attempt; + + guint tick_id; + guint length_id; +}; + +static guint gst_play_signals[LAST_SIGNAL] = { 0 }; + +static GstPipelineClass *parent_class = NULL; + +/* ======================================================= */ +/* */ +/* Private Methods */ +/* */ +/* ======================================================= */ + +static gboolean +gst_play_pipeline_setup (GstPlay *play) +{ + GstElement *work_thread, *video_thread; + GstElement *source, *autoplugger, *video_switch; + GstElement *video_queue, *video_colorspace, *video_scaler, *video_sink; + GstElement *audio_thread, *audio_queue, *audio_volume, *audio_sink; + GstElement *audio_tee, *vis_thread, *vis_queue, *vis_element; + GstPad *audio_tee_pad1, *audio_tee_pad2, *vis_thread_pad, *audio_sink_pad; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + work_thread = gst_element_factory_make ("thread", "work_thread"); + if (!GST_IS_ELEMENT (work_thread)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "work_thread", work_thread); + gst_bin_add (GST_BIN (play), work_thread); + + /* Placeholder for the source and autoplugger { fakesrc ! spider } */ + source = gst_element_factory_make ("fakesrc", "source"); + if (!GST_IS_ELEMENT (source)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "source", source); + + autoplugger = gst_element_factory_make ("spider", "autoplugger"); + if (!GST_IS_ELEMENT (autoplugger)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "autoplugger", autoplugger); + + gst_bin_add_many (GST_BIN (work_thread), source, autoplugger, NULL); + gst_element_link (source, autoplugger); + + /* Creating our video output bin + { queue ! colorspace ! videoscale ! fakesink } */ + video_thread = gst_element_factory_make ("thread", "video_thread"); + if (!GST_IS_ELEMENT (video_thread)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "video_thread", video_thread); + gst_bin_add (GST_BIN (work_thread), video_thread); + + /* Buffer queue for our video thread */ + video_queue = gst_element_factory_make ("queue", "video_queue"); + if (!GST_IS_ELEMENT (video_queue)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "video_queue", video_queue); + + /* Colorspace conversion */ + /* FIXME: Use ffcolorspace and fallback to Hermes on failure ?*/ + video_colorspace = gst_element_factory_make ("colorspace", + "video_colorspace"); + if (!GST_IS_ELEMENT (video_colorspace)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "video_colorspace", + video_colorspace); + + /* Software scaling of video stream */ + video_scaler = gst_element_factory_make ("videoscale", "video_scaler"); + if (!GST_IS_ELEMENT (video_scaler)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "video_scaler", video_scaler); + + /* Placeholder for future video sink bin */ + video_sink = gst_element_factory_make ("fakesink", "video_sink"); + if (!GST_IS_ELEMENT (video_sink)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "video_sink", video_sink); + + /* Linking, Adding, Ghosting */ + gst_element_link_many (video_queue, video_colorspace, + video_scaler, video_sink, NULL); + gst_bin_add_many (GST_BIN (video_thread), video_queue, video_colorspace, + video_scaler, video_sink, NULL); + gst_element_add_ghost_pad (video_thread, + gst_element_get_pad (video_queue, "sink"), + "sink"); + + video_switch = gst_element_factory_make ("switch", + "video_switch"); + if (!GST_IS_ELEMENT (video_switch)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "video_switch", video_switch); + + gst_bin_add (GST_BIN (work_thread), video_switch); + + /* Connecting autoplugger to video switch and video switch to video output + gst_element_link (autoplugger, video_switch); + gst_element_link (video_switch, video_thread);*/ + gst_element_link (autoplugger, video_thread); + + /* Creating our audio output bin + { queue ! volume ! tee ! { queue ! goom } ! fakesink } */ + audio_thread = gst_element_factory_make ("thread", "audio_thread"); + if (!GST_IS_ELEMENT (audio_thread)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "audio_thread", audio_thread); + gst_bin_add (GST_BIN (work_thread), audio_thread); + + /* Buffer queue for our audio thread */ + audio_queue = gst_element_factory_make ("queue", "audio_queue"); + if (!GST_IS_ELEMENT (audio_queue)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "audio_queue", audio_queue); + + /* Volume control */ + audio_volume = gst_element_factory_make ("volume", "audio_volume"); + if (!GST_IS_ELEMENT (audio_volume)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "audio_volume", audio_volume); + + /* Duplicate audio signal to sink and visualization thread */ + audio_tee = gst_element_factory_make ("tee", "audio_tee"); + if (!GST_IS_ELEMENT (audio_tee)) + return FALSE; + + audio_tee_pad1 = gst_element_get_request_pad (audio_tee, "src%d"); + audio_tee_pad2 = gst_element_get_request_pad (audio_tee, "src%d"); + g_hash_table_insert (play->priv->elements, "audio_tee_pad1", + audio_tee_pad1); + g_hash_table_insert (play->priv->elements, "audio_tee_pad2", + audio_tee_pad2); + g_hash_table_insert (play->priv->elements, "audio_tee", audio_tee); + + /* Placeholder for future audio sink bin */ + audio_sink = gst_element_factory_make ("fakesink", "audio_sink"); + if (!GST_IS_ELEMENT (audio_sink)) + return FALSE; + + audio_sink_pad = gst_element_get_pad (audio_sink, "sink"); + g_hash_table_insert (play->priv->elements, "audio_sink_pad", + audio_sink_pad); + g_hash_table_insert (play->priv->elements, "audio_sink", audio_sink); + + /* Visualization thread */ + vis_thread = gst_element_factory_make ("thread", "vis_thread"); + if (!GST_IS_ELEMENT (vis_thread)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "vis_thread", vis_thread); + + /* Buffer queue for our visualization thread */ + vis_queue = gst_element_factory_make ("queue", "vis_queue"); + if (!GST_IS_ELEMENT (vis_queue)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "vis_queue", vis_queue); + + vis_element = gst_element_factory_make ("identity", "vis_element"); + if (!GST_IS_ELEMENT (vis_element)) + return FALSE; + + g_hash_table_insert (play->priv->elements, "vis_element", vis_element); + + /* Adding, Linking, Ghosting in visualization */ + gst_bin_add_many (GST_BIN (vis_thread), vis_queue, vis_element, NULL); + gst_element_link (vis_queue, vis_element); + vis_thread_pad = gst_element_add_ghost_pad (vis_thread, + gst_element_get_pad (vis_queue, "sink"), + "sink"); + g_hash_table_insert (play->priv->elements, "vis_thread_pad", + vis_thread_pad); + + + /* Linking, Adding, Ghosting in audio */ + gst_element_link_many (audio_queue, audio_volume, audio_tee, NULL); + gst_pad_link (audio_tee_pad1, audio_sink_pad); + gst_bin_add_many (GST_BIN (audio_thread), audio_queue, audio_volume, + audio_tee, vis_thread, audio_sink, NULL); + gst_element_add_ghost_pad (audio_thread, + gst_element_get_pad (audio_queue, "sink"), + "sink"); + + /* Connecting audio output to autoplugger */ + gst_element_link (autoplugger, audio_thread); + + return TRUE; +} + +static void +gst_play_have_video_size (GstElement *element, gint width, + gint height, GstPlay *play) +{ + g_return_if_fail (play != NULL); + g_return_if_fail (GST_IS_PLAY (play)); + g_signal_emit (G_OBJECT (play), gst_play_signals[HAVE_VIDEO_SIZE], + 0, width, height); +} + +static gboolean +gst_play_tick_callback (GstPlay *play) +{ + GstClock *clock = NULL; + + g_return_val_if_fail (play != NULL, FALSE); + + if (!GST_IS_PLAY (play)) { + play->priv->tick_id = 0; + return FALSE; + } + + clock = gst_bin_get_clock (GST_BIN (play)); + play->priv->time_nanos = gst_clock_get_time (clock); + + g_signal_emit (G_OBJECT (play), gst_play_signals[TIME_TICK], + 0,play->priv->time_nanos); + + if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) + return TRUE; + else { + play->priv->tick_id = 0; + return FALSE; + } +} + +static gboolean +gst_play_get_length_callback (GstPlay *play) +{ + GstElement *audio_sink_element, *video_sink_element; + GstFormat format = GST_FORMAT_TIME; + gint64 value; + gboolean q = FALSE; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + /* We try to get length from all real sink elements */ + audio_sink_element = g_hash_table_lookup (play->priv->elements, + "audio_sink_element"); + video_sink_element = g_hash_table_lookup (play->priv->elements, + "video_sink_element"); + if (!GST_IS_ELEMENT (audio_sink_element) && + !GST_IS_ELEMENT (video_sink_element)) { + play->priv->length_id = 0; + return FALSE; + } + + /* Audio first and then Video */ + q = gst_element_query (audio_sink_element, GST_QUERY_TOTAL, &format, &value); + if (!q) + q = gst_element_query (video_sink_element, GST_QUERY_TOTAL, &format, + &value); + + if (q) { + play->priv->length_nanos = value; + g_signal_emit (G_OBJECT (play), gst_play_signals[STREAM_LENGTH], + 0,play->priv->length_nanos); + play->priv->length_id = 0; + return FALSE; + } + + play->priv->get_length_attempt++; + + /* We try 16 times */ + if (play->priv->get_length_attempt > 15) { + play->priv->length_id = 0; + return FALSE; + } + else + return TRUE; +} + +static void +gst_play_state_change (GstElement *element, GstElementState old, + GstElementState state) +{ + GstPlay *play; + + g_return_if_fail (element != NULL); + g_return_if_fail (GST_IS_PLAY (element)); + + play = GST_PLAY (element); + + if (state == GST_STATE_PLAYING) { + if (play->priv->tick_id) { + g_source_remove (play->priv->tick_id); + play->priv->tick_id = 0; + } + + play->priv->tick_id = g_timeout_add (200, + (GSourceFunc) gst_play_tick_callback, + play); + + play->priv->get_length_attempt = 0; + + if (play->priv->length_id) { + g_source_remove (play->priv->length_id); + play->priv->length_id = 0; + } + + play->priv->length_id = g_timeout_add (200, + (GSourceFunc) gst_play_get_length_callback, + play); + } + + if (GST_ELEMENT_CLASS (parent_class)->state_change) + GST_ELEMENT_CLASS (parent_class)->state_change (element, old, state); +} + +/* =========================================== */ +/* */ +/* Init & Dispose & Class init */ +/* */ +/* =========================================== */ + +static void +gst_play_dispose (GObject *object) +{ + GstPlay *play; + + g_return_if_fail (object != NULL); + g_return_if_fail (GST_IS_PLAY (object)); + + play = GST_PLAY (object); + + if (play->priv->length_id) { + g_source_remove (play->priv->length_id); + play->priv->length_id = 0; + } + + if (play->priv->tick_id) { + g_source_remove (play->priv->tick_id); + play->priv->tick_id = 0; + } + + if (play->priv->location) { + g_free (play->priv->location); + play->priv->location = NULL; + } + + if (play->priv->elements) { + g_hash_table_destroy (play->priv->elements); + play->priv->elements = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_play_init (GstPlay *play) +{ + play->priv = g_new0 (GstPlayPrivate, 1); + play->priv->location = NULL; + play->priv->length_nanos = 0; + play->priv->time_nanos = 0; + play->priv->elements = g_hash_table_new (g_str_hash, g_str_equal); + + if (!gst_play_pipeline_setup (play)) + g_warning ("libgstplay: failed initializing pipeline"); +} + +static void +gst_play_class_init (GstPlayClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->dispose = gst_play_dispose; + + element_class->state_change = gst_play_state_change; + + gst_play_signals[TIME_TICK] = + g_signal_new ("time_tick", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GstPlayClass, time_tick), NULL, NULL, + gst_marshal_VOID__INT64, G_TYPE_NONE, 1, G_TYPE_INT64); + gst_play_signals[STREAM_LENGTH] = + g_signal_new ("stream_length", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GstPlayClass, stream_length), NULL, NULL, + gst_marshal_VOID__INT64, G_TYPE_NONE, 1, G_TYPE_INT64); + gst_play_signals[HAVE_VIDEO_SIZE] = + g_signal_new ("have_video_size", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GstPlayClass, have_video_size), NULL, NULL, + gst_marshal_VOID__INT_INT, G_TYPE_NONE, 2, + G_TYPE_INT, G_TYPE_INT); +} + +/* ======================================================= */ +/* */ +/* Public Methods */ +/* */ +/* ======================================================= */ + +/** + * gst_play_set_location: + * @play: a #GstPlay. + * @location: a const #char* indicating location to play + * + * Set location of @play to @location. + * + * Returns: TRUE if location was set successfully. + */ +gboolean +gst_play_set_location (GstPlay *play, const char *location) +{ + GstElement *work_thread, *source, *autoplugger, *video_thread, *audio_thread; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + if (play->priv->location) + g_free (play->priv->location); + + play->priv->location = g_strdup (location); + + if (GST_STATE (GST_ELEMENT (play)) != GST_STATE_READY) + gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY); + + work_thread = g_hash_table_lookup (play->priv->elements, "work_thread"); + if (!GST_IS_ELEMENT (work_thread)) + return FALSE; + video_thread = g_hash_table_lookup (play->priv->elements, "video_thread"); + if (!GST_IS_ELEMENT (video_thread)) + return FALSE; + audio_thread = g_hash_table_lookup (play->priv->elements, "audio_thread"); + if (!GST_IS_ELEMENT (audio_thread)) + return FALSE; + source = g_hash_table_lookup (play->priv->elements, "source"); + if (!GST_IS_ELEMENT (source)) + return FALSE; + autoplugger = g_hash_table_lookup (play->priv->elements, "autoplugger"); + if (!GST_IS_ELEMENT (autoplugger)) + return FALSE; + + /* Spider can autoplugg only once. We remove the actual one and put a new + autoplugger */ + gst_element_unlink (source, autoplugger); + gst_element_unlink (autoplugger, video_thread); + gst_element_unlink (autoplugger, audio_thread); + gst_bin_remove (GST_BIN (work_thread), autoplugger); + + autoplugger = gst_element_factory_make ("spider", "autoplugger"); + if (!GST_IS_ELEMENT (autoplugger)) + return FALSE; + + gst_bin_add (GST_BIN (work_thread), autoplugger); + gst_element_link (source, autoplugger); + gst_element_link (autoplugger, video_thread); + gst_element_link (autoplugger, audio_thread); + + g_hash_table_replace (play->priv->elements, "autoplugger", autoplugger); + + /* FIXME: Why don't we have an interface to do that kind of stuff ? */ + g_object_set (G_OBJECT (source), "location", play->priv->location, NULL); + + play->priv->length_nanos = 0LL; + play->priv->time_nanos = 0LL; + + g_signal_emit (G_OBJECT (play), gst_play_signals[STREAM_LENGTH], 0, 0LL); + g_signal_emit (G_OBJECT (play), gst_play_signals[TIME_TICK], 0, 0LL); + + return TRUE; +} + +/** + * gst_play_get_location: + * @play: a #GstPlay. + * + * Get current location of @play. + * + * Returns: a const #char* pointer to current location. + */ +char * +gst_play_get_location (GstPlay *play) +{ + g_return_val_if_fail (play != NULL, NULL); + g_return_val_if_fail (GST_IS_PLAY (play), NULL); + return g_strdup (play->priv->location); +} + +/** + * gst_play_seek_to_time: + * @play: a #GstPlay. + * @time_nanos: a #gint64 indicating a time position. + * + * Performs a seek on @play until @time_nanos. + */ +gboolean +gst_play_seek_to_time (GstPlay * play, gint64 time_nanos) +{ + GstElement *audio_sink_element, *video_sink_element; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + if (time_nanos < 0LL) + time_nanos = 0LL; + + audio_sink_element = g_hash_table_lookup (play->priv->elements, + "audio_sink_element"); + video_sink_element = g_hash_table_lookup (play->priv->elements, + "video_sink_element"); + + if (GST_IS_ELEMENT (audio_sink_element) && + GST_IS_ELEMENT (video_sink_element)) { + gboolean s = FALSE; + + s = gst_element_seek (audio_sink_element, GST_FORMAT_TIME | + GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH, + time_nanos); + if (!s) { + s = gst_element_seek (video_sink_element, GST_FORMAT_TIME | + GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH, + time_nanos); + } + + if (s) { + GstClock *clock = gst_bin_get_clock (GST_BIN (play)); + play->priv->time_nanos = gst_clock_get_time (clock); + g_signal_emit (G_OBJECT (play), gst_play_signals[TIME_TICK], + 0,play->priv->time_nanos); + } + } + + return TRUE; +} + +/** + * gst_play_set_data_src: + * @play: a #GstPlay. + * @data_src: a #GstElement. + * + * Set @data_src as the source element of @play. + * + * Returns: TRUE if call succeeded. + */ +gboolean +gst_play_set_data_src (GstPlay *play, GstElement *data_src) +{ + GstElement *work_thread, *old_data_src, *autoplugger; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + /* We bring back the pipeline to READY */ + if (GST_STATE (GST_ELEMENT (play)) != GST_STATE_READY) + gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY); + + /* Getting needed objects */ + work_thread = g_hash_table_lookup (play->priv->elements, "work_thread"); + if (!GST_IS_ELEMENT (work_thread)) + return FALSE; + old_data_src = g_hash_table_lookup (play->priv->elements, "source"); + if (!GST_IS_ELEMENT (old_data_src)) + return FALSE; + autoplugger = g_hash_table_lookup (play->priv->elements, "autoplugger"); + if (!GST_IS_ELEMENT (autoplugger)) + return FALSE; + + /* Unlinking old source from autoplugger, removing it from pipeline, adding + the new one and connecting it to autoplugger FIXME: we should put a new + autoplugger here as spider can autoplugg only once */ + gst_element_unlink (old_data_src, autoplugger); + gst_bin_remove (GST_BIN (work_thread), old_data_src); + gst_bin_add (GST_BIN (work_thread), data_src); + gst_element_link (data_src, autoplugger); + + g_hash_table_replace (play->priv->elements, "source", data_src); + + return TRUE; +} + +/** + * gst_play_set_video_sink: + * @play: a #GstPlay. + * @video_sink: a #GstElement. + * + * Set @video_sink as the video sink element of @play. + * + * Returns: TRUE if call succeeded. + */ +gboolean +gst_play_set_video_sink (GstPlay *play, GstElement *video_sink) +{ + GstElement *video_thread, *old_video_sink, *video_scaler, *video_sink_element; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + /* We bring back the pipeline to READY */ + if (GST_STATE (GST_ELEMENT (play)) != GST_STATE_READY) + gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY); + + /* Getting needed objects */ + video_thread = g_hash_table_lookup (play->priv->elements, "video_thread"); + if (!GST_IS_ELEMENT (video_thread)) + return FALSE; + old_video_sink = g_hash_table_lookup (play->priv->elements, "video_sink"); + if (!GST_IS_ELEMENT (old_video_sink)) + return FALSE; + video_scaler = g_hash_table_lookup (play->priv->elements, "video_scaler"); + if (!GST_IS_ELEMENT (video_scaler)) + return FALSE; + + /* Unlinking old video sink from video scaler, removing it from pipeline, + adding the new one and linking it */ + gst_element_unlink (video_scaler, old_video_sink); + gst_bin_remove (GST_BIN (video_thread), old_video_sink); + gst_bin_add (GST_BIN (video_thread), video_sink); + gst_element_link (video_scaler, video_sink); + + g_hash_table_replace (play->priv->elements, "video_sink", video_sink); + + video_sink_element = gst_play_get_sink_element (play, video_sink, + GST_PLAY_SINK_TYPE_VIDEO); + if (GST_IS_ELEMENT (video_sink_element)) { + g_hash_table_replace (play->priv->elements, "video_sink_element", + video_sink_element); + g_signal_connect (G_OBJECT (video_sink_element), "have_video_size", + G_CALLBACK (gst_play_have_video_size), play); + } + + gst_element_set_state (video_sink, GST_STATE (GST_ELEMENT(play))); + + return TRUE; +} + +/** + * gst_play_set_audio_sink: + * @play: a #GstPlay. + * @audio_sink: a #GstElement. + * + * Set @audio_sink as the audio sink element of @play. + * + * Returns: TRUE if call succeeded. + */ +gboolean +gst_play_set_audio_sink (GstPlay *play, GstElement *audio_sink) +{ + GstElement *old_audio_sink, *audio_thread, *audio_sink_element; + GstPad *audio_tee_pad1, *audio_sink_pad, *old_audio_sink_pad; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + /* We bring back the pipeline to READY */ + if (GST_STATE (GST_ELEMENT (play)) != GST_STATE_READY) + gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY); + + /* Getting needed objects */ + old_audio_sink = g_hash_table_lookup (play->priv->elements, "audio_sink"); + if (!GST_IS_ELEMENT (old_audio_sink)) + return FALSE; + old_audio_sink_pad = g_hash_table_lookup (play->priv->elements, + "audio_sink_pad"); + if (!GST_IS_PAD (old_audio_sink_pad)) + return FALSE; + audio_thread = g_hash_table_lookup (play->priv->elements, "audio_thread"); + if (!GST_IS_ELEMENT (audio_thread)) + return FALSE; + audio_tee_pad1 = g_hash_table_lookup (play->priv->elements, + "audio_tee_pad1"); + if (!GST_IS_PAD (audio_tee_pad1)) + return FALSE; + audio_sink_pad = gst_element_get_pad (audio_sink, "sink"); + if (!GST_IS_PAD (audio_sink_pad)) + return FALSE; + + /* Unlinking old audiosink, removing it from pipeline, putting the new one + and linking it */ + gst_pad_unlink (audio_tee_pad1, old_audio_sink_pad); + gst_bin_remove (GST_BIN (audio_thread), old_audio_sink); + gst_bin_add (GST_BIN (audio_thread), audio_sink); + gst_pad_link (audio_tee_pad1, audio_sink_pad); + + g_hash_table_replace (play->priv->elements, "audio_sink", audio_sink); + g_hash_table_replace (play->priv->elements, "audio_sink_pad", + audio_sink_pad); + + audio_sink_element = gst_play_get_sink_element (play, audio_sink, + GST_PLAY_SINK_TYPE_AUDIO); + if (GST_IS_ELEMENT (audio_sink_element)) { + g_hash_table_replace (play->priv->elements, "audio_sink_element", + audio_sink_element); + } + + gst_element_set_state (audio_sink, GST_STATE (GST_ELEMENT(play))); + + return TRUE; +} + +/** + * gst_play_set_visualization: + * @play: a #GstPlay. + * @element: a #GstElement. + * + * Set @video_sink as the video sink element of @play. + * + * Returns: TRUE if call succeeded. + */ +gboolean +gst_play_set_visualization (GstPlay *play, GstElement *vis_element) +{ + GstElement *old_vis_element, *vis_thread, *vis_queue/*, *video_switch*/; + gboolean was_playing = FALSE; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + /* We bring back the pipeline to READY */ + if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) { + gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED); + was_playing = TRUE; + } + + /* Getting needed objects */ + vis_thread = g_hash_table_lookup (play->priv->elements, "vis_thread"); + if (!GST_IS_ELEMENT (vis_thread)) + return FALSE; + old_vis_element = g_hash_table_lookup (play->priv->elements, + "vis_element"); + if (!GST_IS_ELEMENT (old_vis_element)) + return FALSE; + vis_queue = g_hash_table_lookup (play->priv->elements, "vis_queue"); + if (!GST_IS_ELEMENT (vis_queue)) + return FALSE; + /*video_switch = g_hash_table_lookup (play->priv->elements, "video_switch"); + if (!GST_IS_ELEMENT (video_switch)) + return FALSE;*/ + + /* Unlinking, removing the old element then adding and linking the new one */ + gst_element_unlink (vis_queue, old_vis_element); + /*gst_element_unlink (old_vis_element, video_switch);*/ + gst_bin_remove (GST_BIN (vis_thread), old_vis_element); + gst_bin_add (GST_BIN (vis_thread), vis_element); + gst_element_link (vis_queue, vis_element); + /*gst_element_link (vis_element, video_switch);*/ + + if (was_playing) + gst_element_set_state (GST_ELEMENT (play), GST_STATE_PLAYING); + + return TRUE; +} + +/** + * gst_play_connect_visualization: + * @play: a #GstPlay. + * @connect: a #gboolean indicating wether or not + * visualization should be connected. + * + * Connect or disconnect visualization bin in @play. + * + * Returns: TRUE if call succeeded. + */ +gboolean +gst_play_connect_visualization (GstPlay * play, gboolean connect) +{ + GstPad *audio_tee_pad2, *vis_thread_pad; + gboolean connected = FALSE, was_playing = FALSE; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY (play), FALSE); + + vis_thread_pad = g_hash_table_lookup (play->priv->elements, + "vis_thread_pad"); + if (!GST_IS_PAD (vis_thread_pad)) + return FALSE; + audio_tee_pad2 = g_hash_table_lookup (play->priv->elements, + "audio_tee_pad2"); + if (!GST_IS_PAD (audio_tee_pad2)) + return FALSE; + + if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) { + gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED); + was_playing = TRUE; + } + + if (gst_pad_get_peer (vis_thread_pad) != NULL) + connected = TRUE; + else + connected = FALSE; + + if ((connect) && (!connected)) + gst_pad_link (audio_tee_pad2, vis_thread_pad); + else if ((!connect) && (connected)) + gst_pad_unlink (audio_tee_pad2, vis_thread_pad); + + if (was_playing) + gst_element_set_state (GST_ELEMENT (play), GST_STATE_PLAYING); + + return TRUE; +} + +/** + * gst_play_get_sink_element: + * @play: a #GstPlay. + * @element: a #GstElement. + * @sink_type: a #GstPlaySinkType. + * + * Searches recursively for a sink #GstElement with + * type @sink_type in @element which is supposed to be a #GstBin. + * + * Returns: the sink #GstElement of @element. + */ +GstElement * +gst_play_get_sink_element (GstPlay *play, + GstElement *element, GstPlaySinkType sink_type) +{ + GList *elements = NULL; + const GList *pads = NULL; + gboolean has_src, has_correct_type; + + g_return_val_if_fail (play != NULL, NULL); + g_return_val_if_fail (element != NULL, NULL); + g_return_val_if_fail (GST_IS_PLAY (play), NULL); + g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); + + if (!GST_IS_BIN (element)) { + /* since its not a bin, we'll presume this + * element is a sink element */ + return element; + } + + elements = (GList *) gst_bin_get_list (GST_BIN (element)); + + /* traverse all elements looking for a src pad */ + + while (elements) { + element = GST_ELEMENT (elements->data); + + /* Recursivity :) */ + + if (GST_IS_BIN (element)) { + element = gst_play_get_sink_element (play, element, sink_type); + if (GST_IS_ELEMENT (element)) + return element; + } + else { + pads = gst_element_get_pad_list (element); + has_src = FALSE; + has_correct_type = FALSE; + while (pads) { + /* check for src pad */ + if (GST_PAD_DIRECTION (GST_PAD (pads->data)) == GST_PAD_SRC) { + has_src = TRUE; + break; + } + else { + /* If not a src pad checking caps */ + const GstCaps2 *caps; + GstStructure *structure; + gboolean has_video_cap = FALSE; + gboolean has_audio_cap = FALSE; + + caps = gst_pad_get_caps (GST_PAD (pads->data)); + structure = gst_caps2_get_nth_cap (caps, 0); + + if (strcmp (gst_structure_get_name (structure), + "audio/x-raw-int") == 0) { + has_audio_cap = TRUE; + } + + if (strcmp (gst_structure_get_name (structure), + "video/x-raw-yuv") == 0 || + strcmp (gst_structure_get_name (structure), + "video/x-raw-rgb") == 0) { + has_video_cap = TRUE; + } + + switch (sink_type) { + case GST_PLAY_SINK_TYPE_AUDIO: + if (has_audio_cap) + has_correct_type = TRUE; + break;; + case GST_PLAY_SINK_TYPE_VIDEO: + if (has_video_cap) + has_correct_type = TRUE; + break;; + case GST_PLAY_SINK_TYPE_ANY: + if ((has_video_cap) || (has_audio_cap)) + has_correct_type = TRUE; + break;; + default: + has_correct_type = FALSE; + } + } + + pads = g_list_next (pads); + + } + + if ((!has_src) && (has_correct_type)) + return element; + } + + elements = g_list_next (elements); + } + + /* we didn't find a sink element */ + + return NULL; +} + +GstPlay * +gst_play_new (void) +{ + GstPlay *play = g_object_new (GST_TYPE_PLAY, NULL); + + return play; +} + +/* =========================================== */ +/* */ +/* Object typing & Creation */ +/* */ +/* =========================================== */ + +GType +gst_play_get_type (void) +{ + static GType play_type = 0; + + if (!play_type) { + static const GTypeInfo play_info = { + sizeof (GstPlayClass), + NULL, + NULL, + (GClassInitFunc) gst_play_class_init, + NULL, + NULL, + sizeof (GstPlay), + 0, + (GInstanceInitFunc) gst_play_init, + NULL + }; + + play_type = g_type_register_static (GST_TYPE_PIPELINE, "GstPlay", + &play_info, 0); + } + + return play_type; +} diff --git a/gst-libs/gst/play/play.h b/gst-libs/gst/play/play.h new file mode 100644 index 000000000..0c45d9431 --- /dev/null +++ b/gst-libs/gst/play/play.h @@ -0,0 +1,89 @@ +/* GStreamer + * Copyright (C) 2003 Julien Moutte + * + * 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_PLAY_H__ +#define __GST_PLAY_H__ + +#include + +#define GST_TYPE_PLAY (gst_play_get_type()) +#define GST_PLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PLAY, GstPlay)) +#define GST_PLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PLAY, GstPlayClass)) +#define GST_IS_PLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PLAY)) +#define GST_IS_PLAY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PLAY)) +#define GST_PLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PLAY, GstPlayClass)) + +typedef enum +{ + GST_PLAY_SINK_TYPE_AUDIO, + GST_PLAY_SINK_TYPE_VIDEO, + GST_PLAY_SINK_TYPE_ANY, +} GstPlaySinkType; + +typedef struct _GstPlay GstPlay; +typedef struct _GstPlayClass GstPlayClass; +typedef struct _GstPlayPrivate GstPlayPrivate; + +struct _GstPlay +{ + GstPipeline pipeline; + + GstPlayPrivate *priv; + + gpointer _gst_reserved[GST_PADDING]; +}; + +struct _GstPlayClass +{ + GstPipelineClass parent_class; + + void (*time_tick) (GstPlay *play, gint64 time_nanos); + void (*stream_length) (GstPlay *play, gint64 length_nanos); + void (*have_video_size) (GstPlay *play, gint width, gint height); + + gpointer _gst_reserved[GST_PADDING]; +}; + +GType gst_play_get_type (void); +GstPlay * gst_play_new (void); + +gboolean gst_play_set_data_src (GstPlay *play, + GstElement *data_src); +gboolean gst_play_set_video_sink (GstPlay *play, + GstElement *video_sink); +gboolean gst_play_set_audio_sink (GstPlay *play, + GstElement *audio_sink); + +gboolean gst_play_set_visualization (GstPlay *play, + GstElement *element); +gboolean gst_play_connect_visualization (GstPlay *play, + gboolean connect); + +gboolean gst_play_set_location (GstPlay *play, + const char *location); +char * gst_play_get_location (GstPlay *play); + +gboolean gst_play_seek_to_time (GstPlay *play, + gint64 time_nanos); + +GstElement * gst_play_get_sink_element (GstPlay *play, + GstElement *element, + GstPlaySinkType sink_type); + +#endif /* __GST_PLAY_H__ */ diff --git a/gst-libs/gst/play/play.old.h b/gst-libs/gst/play/play.old.h index fec75173b..956923e73 100644 --- a/gst-libs/gst/play/play.old.h +++ b/gst-libs/gst/play/play.old.h @@ -133,7 +133,7 @@ struct _GstPlay GstPlayTimeoutAdd timeout_add_func; GstPlayIdleAdd idle_add_func; - GST_OBJECT_PADDING + gpointer _gst_reserved[GST_PADDING]; }; struct _GstPlayClass @@ -155,7 +155,7 @@ struct _GstPlayClass void (*have_video_size) (GstPlay * play, gint width, gint height); void (*have_vis_size) (GstPlay * play, gint width, gint height); - GST_CLASS_PADDING + gpointer _gst_reserved[GST_PADDING]; }; struct _GstPlayIdleData diff --git a/gst-libs/gst/propertyprobe/propertyprobe.h b/gst-libs/gst/propertyprobe/propertyprobe.h index 3fe08f0bc..695aa4daf 100644 --- a/gst-libs/gst/propertyprobe/propertyprobe.h +++ b/gst-libs/gst/propertyprobe/propertyprobe.h @@ -56,7 +56,7 @@ typedef struct _GstPropertyProbeInterface { guint prop_id, const GParamSpec *pspec); - GST_CLASS_PADDING + gpointer _gst_reserved[GST_PADDING]; } GstPropertyProbeInterface; GType gst_property_probe_get_type (void); diff --git a/gst-libs/gst/resample/resample.c b/gst-libs/gst/resample/resample.c index 52a80e61a..575922dc3 100644 --- a/gst-libs/gst/resample/resample.c +++ b/gst-libs/gst/resample/resample.c @@ -886,7 +886,6 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, GST_LICENSE, - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN ); diff --git a/gst-libs/gst/riff/Makefile.am b/gst-libs/gst/riff/Makefile.am index 8795515f1..03cd8d545 100644 --- a/gst-libs/gst/riff/Makefile.am +++ b/gst-libs/gst/riff/Makefile.am @@ -1,10 +1,15 @@ - plugin_LTLIBRARIES = libgstriff.la -libgstriff_la_SOURCES = riffparse.c riffencode.c riffutil.c riff.c +libgstriff_la_SOURCES = \ + riff.c \ + riff-media.c \ + riff-read.c libgstriffincludedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/riff -libgstriffinclude_HEADERS = riff.h +libgstriffinclude_HEADERS = \ + riff-ids.h \ + riff-media.h \ + riff-read.h libgstriff_la_LIBADD = libgstriff_la_CFLAGS = $(GST_CFLAGS) diff --git a/gst-libs/gst/riff/riff-ids.h b/gst-libs/gst/riff/riff-ids.h new file mode 100644 index 000000000..da465c2df --- /dev/null +++ b/gst-libs/gst/riff/riff-ids.h @@ -0,0 +1,319 @@ +/* GStreamer RIFF I/O + * Copyright (C) 2003 Ronald Bultje + * + * riff-ids.h: RIFF IDs and structs + * + * 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_RIFF_IDS_H__ +#define __GST_RIFF_IDS_H__ + +#include + +/* RIFF types */ +#define GST_RIFF_RIFF_WAVE GST_MAKE_FOURCC ('W','A','V','E') +#define GST_RIFF_RIFF_AVI GST_MAKE_FOURCC ('A','V','I',' ') + +/* tags */ +#define GST_RIFF_TAG_RIFF GST_MAKE_FOURCC ('R','I','F','F') +#define GST_RIFF_TAG_RIFX GST_MAKE_FOURCC ('R','I','F','X') +#define GST_RIFF_TAG_LIST GST_MAKE_FOURCC ('L','I','S','T') +#define GST_RIFF_TAG_avih GST_MAKE_FOURCC ('a','v','i','h') +#define GST_RIFF_TAG_strd GST_MAKE_FOURCC ('s','t','r','d') +#define GST_RIFF_TAG_strn GST_MAKE_FOURCC ('s','t','r','n') +#define GST_RIFF_TAG_strh GST_MAKE_FOURCC ('s','t','r','h') +#define GST_RIFF_TAG_strf GST_MAKE_FOURCC ('s','t','r','f') +#define GST_RIFF_TAG_vedt GST_MAKE_FOURCC ('v','e','d','t') +#define GST_RIFF_TAG_JUNK GST_MAKE_FOURCC ('J','U','N','K') +#define GST_RIFF_TAG_idx1 GST_MAKE_FOURCC ('i','d','x','1') +#define GST_RIFF_TAG_dmlh GST_MAKE_FOURCC ('d','m','l','h') +/* WAV stuff */ +#define GST_RIFF_TAG_fmt GST_MAKE_FOURCC ('f','m','t',' ') +#define GST_RIFF_TAG_data GST_MAKE_FOURCC ('d','a','t','a') + +/* LIST types */ +#define GST_RIFF_LIST_movi GST_MAKE_FOURCC ('m','o','v','i') +#define GST_RIFF_LIST_hdrl GST_MAKE_FOURCC ('h','d','r','l') +#define GST_RIFF_LIST_odml GST_MAKE_FOURCC ('o','d','m','l') +#define GST_RIFF_LIST_strl GST_MAKE_FOURCC ('s','t','r','l') +#define GST_RIFF_LIST_INFO GST_MAKE_FOURCC ('I','N','F','O') +#define GST_RIFF_LIST_AVIX GST_MAKE_FOURCC ('A','V','I','X') + +/* fcc types */ +#define GST_RIFF_FCC_vids GST_MAKE_FOURCC ('v','i','d','s') +#define GST_RIFF_FCC_auds GST_MAKE_FOURCC ('a','u','d','s') +#define GST_RIFF_FCC_pads GST_MAKE_FOURCC ('p','a','d','s') +#define GST_RIFF_FCC_txts GST_MAKE_FOURCC ('t','x','t','s') +#define GST_RIFF_FCC_vidc GST_MAKE_FOURCC ('v','i','d','c') +#define GST_RIFF_FCC_iavs GST_MAKE_FOURCC ('i','a','v','s') +/* fcc handlers */ +#define GST_RIFF_FCCH_RLE GST_MAKE_FOURCC ('R','L','E',' ') +#define GST_RIFF_FCCH_msvc GST_MAKE_FOURCC ('m','s','v','c') +#define GST_RIFF_FCCH_MSVC GST_MAKE_FOURCC ('M','S','V','C') + +/* INFO types - see http://www.saettler.com/RIFFMCI/riffmci.html */ +#define GST_RIFF_INFO_IARL GST_MAKE_FOURCC ('I','A','R','L') /* location */ +#define GST_RIFF_INFO_IART GST_MAKE_FOURCC ('I','A','R','T') /* artist */ +#define GST_RIFF_INFO_ICMS GST_MAKE_FOURCC ('I','C','M','S') /* commissioned */ +#define GST_RIFF_INFO_ICMT GST_MAKE_FOURCC ('I','C','M','T') /* comment */ +#define GST_RIFF_INFO_ICOP GST_MAKE_FOURCC ('I','C','O','P') /* copyright */ +#define GST_RIFF_INFO_ICRD GST_MAKE_FOURCC ('I','C','R','D') /* creation date */ +#define GST_RIFF_INFO_ICRP GST_MAKE_FOURCC ('I','C','R','P') /* cropped */ +#define GST_RIFF_INFO_IDIM GST_MAKE_FOURCC ('I','D','I','M') /* dimensions */ +#define GST_RIFF_INFO_IDPI GST_MAKE_FOURCC ('I','D','P','I') /* dots-per-inch */ +#define GST_RIFF_INFO_IENG GST_MAKE_FOURCC ('I','E','N','G') /* engineer(s) */ +#define GST_RIFF_INFO_IGNR GST_MAKE_FOURCC ('I','G','N','R') /* genre */ +#define GST_RIFF_INFO_IKEY GST_MAKE_FOURCC ('I','K','E','Y') /* keywords */ +#define GST_RIFF_INFO_ILGT GST_MAKE_FOURCC ('I','L','G','T') /* lightness */ +#define GST_RIFF_INFO_IMED GST_MAKE_FOURCC ('I','M','E','D') /* medium */ +#define GST_RIFF_INFO_INAM GST_MAKE_FOURCC ('I','N','A','M') /* name */ +#define GST_RIFF_INFO_IPLT GST_MAKE_FOURCC ('I','P','L','T') /* palette setting */ +#define GST_RIFF_INFO_IPRD GST_MAKE_FOURCC ('I','P','R','D') /* product */ +#define GST_RIFF_INFO_ISBJ GST_MAKE_FOURCC ('I','S','B','J') /* subject */ +#define GST_RIFF_INFO_ISFT GST_MAKE_FOURCC ('I','S','F','T') /* software */ +#define GST_RIFF_INFO_ISHP GST_MAKE_FOURCC ('I','S','H','P') /* sharpness */ +#define GST_RIFF_INFO_ISRC GST_MAKE_FOURCC ('I','S','R','C') /* source */ +#define GST_RIFF_INFO_ISRF GST_MAKE_FOURCC ('I','S','R','F') /* source form */ +#define GST_RIFF_INFO_ITCH GST_MAKE_FOURCC ('I','T','C','H') /* technician(s) */ + +/*********Chunk Names***************/ +#define GST_RIFF_FF00 GST_MAKE_FOURCC (0xFF,0xFF,0x00,0x00) +#define GST_RIFF_00 GST_MAKE_FOURCC ('0', '0',0x00,0x00) +#define GST_RIFF_01 GST_MAKE_FOURCC ('0', '1',0x00,0x00) +#define GST_RIFF_02 GST_MAKE_FOURCC ('0', '2',0x00,0x00) +#define GST_RIFF_03 GST_MAKE_FOURCC ('0', '3',0x00,0x00) +#define GST_RIFF_04 GST_MAKE_FOURCC ('0', '4',0x00,0x00) +#define GST_RIFF_05 GST_MAKE_FOURCC ('0', '5',0x00,0x00) +#define GST_RIFF_06 GST_MAKE_FOURCC ('0', '6',0x00,0x00) +#define GST_RIFF_07 GST_MAKE_FOURCC ('0', '7',0x00,0x00) +#define GST_RIFF_00pc GST_MAKE_FOURCC ('0', '0', 'p', 'c') +#define GST_RIFF_01pc GST_MAKE_FOURCC ('0', '1', 'p', 'c') +#define GST_RIFF_00dc GST_MAKE_FOURCC ('0', '0', 'd', 'c') +#define GST_RIFF_00dx GST_MAKE_FOURCC ('0', '0', 'd', 'x') +#define GST_RIFF_00db GST_MAKE_FOURCC ('0', '0', 'd', 'b') +#define GST_RIFF_00xx GST_MAKE_FOURCC ('0', '0', 'x', 'x') +#define GST_RIFF_00id GST_MAKE_FOURCC ('0', '0', 'i', 'd') +#define GST_RIFF_00rt GST_MAKE_FOURCC ('0', '0', 'r', 't') +#define GST_RIFF_0021 GST_MAKE_FOURCC ('0', '0', '2', '1') +#define GST_RIFF_00iv GST_MAKE_FOURCC ('0', '0', 'i', 'v') +#define GST_RIFF_0031 GST_MAKE_FOURCC ('0', '0', '3', '1') +#define GST_RIFF_0032 GST_MAKE_FOURCC ('0', '0', '3', '2') +#define GST_RIFF_00vc GST_MAKE_FOURCC ('0', '0', 'v', 'c') +#define GST_RIFF_00xm GST_MAKE_FOURCC ('0', '0', 'x', 'm') +#define GST_RIFF_01wb GST_MAKE_FOURCC ('0', '1', 'w', 'b') +#define GST_RIFF_01dc GST_MAKE_FOURCC ('0', '1', 'd', 'c') +#define GST_RIFF_00__ GST_MAKE_FOURCC ('0', '0', '_', '_') + +/*********VIDEO CODECS**************/ +#define GST_RIFF_cram GST_MAKE_FOURCC ('c', 'r', 'a', 'm') +#define GST_RIFF_CRAM GST_MAKE_FOURCC ('C', 'R', 'A', 'M') +#define GST_RIFF_wham GST_MAKE_FOURCC ('w', 'h', 'a', 'm') +#define GST_RIFF_WHAM GST_MAKE_FOURCC ('W', 'H', 'A', 'M') +#define GST_RIFF_rgb GST_MAKE_FOURCC (0x00,0x00,0x00,0x00) +#define GST_RIFF_RGB GST_MAKE_FOURCC ('R', 'G', 'B', ' ') +#define GST_RIFF_rle8 GST_MAKE_FOURCC (0x01,0x00,0x00,0x00) +#define GST_RIFF_RLE8 GST_MAKE_FOURCC ('R', 'L', 'E', '8') +#define GST_RIFF_rle4 GST_MAKE_FOURCC (0x02,0x00,0x00,0x00) +#define GST_RIFF_RLE4 GST_MAKE_FOURCC ('R', 'L', 'E', '4') +#define GST_RIFF_none GST_MAKE_FOURCC (0x00,0x00,0xFF,0xFF) +#define GST_RIFF_NONE GST_MAKE_FOURCC ('N', 'O', 'N', 'E') +#define GST_RIFF_pack GST_MAKE_FOURCC (0x01,0x00,0xFF,0xFF) +#define GST_RIFF_PACK GST_MAKE_FOURCC ('P', 'A', 'C', 'K') +#define GST_RIFF_tran GST_MAKE_FOURCC (0x02,0x00,0xFF,0xFF) +#define GST_RIFF_TRAN GST_MAKE_FOURCC ('T', 'R', 'A', 'N') +#define GST_RIFF_ccc GST_MAKE_FOURCC (0x03,0x00,0xFF,0xFF) +#define GST_RIFF_CCC GST_MAKE_FOURCC ('C', 'C', 'C', ' ') +#define GST_RIFF_cyuv GST_MAKE_FOURCC ('c', 'y', 'u', 'v') +#define GST_RIFF_CYUV GST_MAKE_FOURCC ('C', 'Y', 'U', 'V') +#define GST_RIFF_jpeg GST_MAKE_FOURCC (0x04,0x00,0xFF,0xFF) +#define GST_RIFF_JPEG GST_MAKE_FOURCC ('J', 'P', 'E', 'G') +#define GST_RIFF_MJPG GST_MAKE_FOURCC ('M', 'J', 'P', 'G') +#define GST_RIFF_mJPG GST_MAKE_FOURCC ('m', 'J', 'P', 'G') +#define GST_RIFF_IJPG GST_MAKE_FOURCC ('I', 'J', 'P', 'G') +#define GST_RIFF_rt21 GST_MAKE_FOURCC ('r', 't', '2', '1') +#define GST_RIFF_RT21 GST_MAKE_FOURCC ('R', 'T', '2', '1') +#define GST_RIFF_iv31 GST_MAKE_FOURCC ('i', 'v', '3', '1') +#define GST_RIFF_IV31 GST_MAKE_FOURCC ('I', 'V', '3', '1') +#define GST_RIFF_iv32 GST_MAKE_FOURCC ('i', 'v', '3', '2') +#define GST_RIFF_IV32 GST_MAKE_FOURCC ('I', 'V', '3', '2') +#define GST_RIFF_iv41 GST_MAKE_FOURCC ('i', 'v', '4', '1') +#define GST_RIFF_IV41 GST_MAKE_FOURCC ('I', 'V', '4', '1') +#define GST_RIFF_iv50 GST_MAKE_FOURCC ('i', 'v', '5', '0') +#define GST_RIFF_IV50 GST_MAKE_FOURCC ('I', 'V', '5', '0') +#define GST_RIFF_cvid GST_MAKE_FOURCC ('c', 'v', 'i', 'd') +#define GST_RIFF_CVID GST_MAKE_FOURCC ('C', 'V', 'I', 'D') +#define GST_RIFF_ULTI GST_MAKE_FOURCC ('U', 'L', 'T', 'I') +#define GST_RIFF_ulti GST_MAKE_FOURCC ('u', 'l', 't', 'i') +#define GST_RIFF_YUV9 GST_MAKE_FOURCC ('Y', 'V', 'U', '9') +#define GST_RIFF_YVU9 GST_MAKE_FOURCC ('Y', 'U', 'V', '9') +#define GST_RIFF_XMPG GST_MAKE_FOURCC ('X', 'M', 'P', 'G') +#define GST_RIFF_xmpg GST_MAKE_FOURCC ('x', 'm', 'p', 'g') +#define GST_RIFF_VDOW GST_MAKE_FOURCC ('V', 'D', 'O', 'W') +#define GST_RIFF_MVI1 GST_MAKE_FOURCC ('M', 'V', 'I', '1') +#define GST_RIFF_v422 GST_MAKE_FOURCC ('v', '4', '2', '2') +#define GST_RIFF_V422 GST_MAKE_FOURCC ('V', '4', '2', '2') +#define GST_RIFF_mvi1 GST_MAKE_FOURCC ('m', 'v', 'i', '1') +#define GST_RIFF_MPIX GST_MAKE_FOURCC (0x04,0x00, 'i', '1') /* MotionPixels munged their id */ +#define GST_RIFF_AURA GST_MAKE_FOURCC ('A', 'U', 'R', 'A') +#define GST_RIFF_DMB1 GST_MAKE_FOURCC ('D', 'M', 'B', '1') +#define GST_RIFF_dmb1 GST_MAKE_FOURCC ('d', 'm', 'b', '1') + +#define GST_RIFF_BW10 GST_MAKE_FOURCC ('B', 'W', '1', '0') +#define GST_RIFF_bw10 GST_MAKE_FOURCC ('b', 'w', '1', '0') + +#define GST_RIFF_yuy2 GST_MAKE_FOURCC ('y', 'u', 'y', '2') +#define GST_RIFF_YUY2 GST_MAKE_FOURCC ('Y', 'U', 'Y', '2') +#define GST_RIFF_YUV8 GST_MAKE_FOURCC ('Y', 'U', 'V', '8') +#define GST_RIFF_WINX GST_MAKE_FOURCC ('W', 'I', 'N', 'X') +#define GST_RIFF_WPY2 GST_MAKE_FOURCC ('W', 'P', 'Y', '2') +#define GST_RIFF_m263 GST_MAKE_FOURCC ('m', '2', '6', '3') +#define GST_RIFF_M263 GST_MAKE_FOURCC ('M', '2', '6', '3') + +#define GST_RIFF_Q1_0 GST_MAKE_FOURCC ('Q', '1',0x2e, '0') +#define GST_RIFF_SFMC GST_MAKE_FOURCC ('S', 'F', 'M', 'C') + +#define GST_RIFF_y41p GST_MAKE_FOURCC ('y', '4', '1', 'p') +#define GST_RIFF_Y41P GST_MAKE_FOURCC ('Y', '4', '1', 'P') +#define GST_RIFF_yv12 GST_MAKE_FOURCC ('y', 'v', '1', '2') +#define GST_RIFF_YV12 GST_MAKE_FOURCC ('Y', 'V', '1', '2') +#define GST_RIFF_vixl GST_MAKE_FOURCC ('v', 'i', 'x', 'l') +#define GST_RIFF_VIXL GST_MAKE_FOURCC ('V', 'I', 'X', 'L') +#define GST_RIFF_iyuv GST_MAKE_FOURCC ('i', 'y', 'u', 'v') +#define GST_RIFF_IYUV GST_MAKE_FOURCC ('I', 'Y', 'U', 'V') +#define GST_RIFF_i420 GST_MAKE_FOURCC ('i', '4', '2', '0') +#define GST_RIFF_I420 GST_MAKE_FOURCC ('I', '4', '2', '0') +#define GST_RIFF_vyuy GST_MAKE_FOURCC ('v', 'y', 'u', 'y') +#define GST_RIFF_VYUY GST_MAKE_FOURCC ('V', 'Y', 'U', 'Y') + +#define GST_RIFF_DIV3 GST_MAKE_FOURCC ('D', 'I', 'V', '3') + +#define GST_RIFF_rpza GST_MAKE_FOURCC ('r', 'p', 'z', 'a') +/* And this here's the mistakes that need to be supported */ +#define GST_RIFF_azpr GST_MAKE_FOURCC ('a', 'z', 'p', 'r') /* recognize Apple's rpza mangled? */ + +/*********** FND in MJPG **********/ +#define GST_RIFF_ISFT GST_MAKE_FOURCC ('I', 'S', 'F', 'T') +#define GST_RIFF_IDIT GST_MAKE_FOURCC ('I', 'D', 'I', 'T') + +#define GST_RIFF_00AM GST_MAKE_FOURCC ('0', '0', 'A', 'M') +#define GST_RIFF_DISP GST_MAKE_FOURCC ('D', 'I', 'S', 'P') +#define GST_RIFF_ISBJ GST_MAKE_FOURCC ('I', 'S', 'B', 'J') + +#define GST_RIFF_rec GST_MAKE_FOURCC ('r', 'e', 'c', ' ') + +/* common data structures */ +typedef struct _gst_riff_strh { + guint32 type; /* stream type */ + guint32 fcc_handler; /* fcc_handler */ + guint32 flags; +/* flags values */ +#define GST_RIFF_STRH_DISABLED 0x000000001 +#define GST_RIFF_STRH_VIDEOPALCHANGES 0x000010000 + guint32 priority; + guint32 init_frames; /* initial frames (???) */ + guint32 scale; + guint32 rate; + guint32 start; + guint32 length; + guint32 bufsize; /* suggested buffer size */ + guint32 quality; + guint32 samplesize; + /* XXX 16 bytes ? */ +} gst_riff_strh; + +typedef struct _gst_riff_strf_vids { /* == BitMapInfoHeader */ + guint32 size; + guint32 width; + guint32 height; + guint16 planes; + guint16 bit_cnt; + guint32 compression; + guint32 image_size; + guint32 xpels_meter; + guint32 ypels_meter; + guint32 num_colors; /* used colors */ + guint32 imp_colors; /* important colors */ + /* may be more for some codecs */ +} gst_riff_strf_vids; + + +typedef struct _gst_riff_strf_auds { /* == WaveHeader (?) */ + guint16 format; +/**** from public Microsoft RIFF docs ******/ +#define GST_RIFF_WAVE_FORMAT_UNKNOWN (0x0000) +#define GST_RIFF_WAVE_FORMAT_PCM (0x0001) +#define GST_RIFF_WAVE_FORMAT_ADPCM (0x0002) +#define GST_RIFF_WAVE_FORMAT_IBM_CVSD (0x0005) +#define GST_RIFF_WAVE_FORMAT_ALAW (0x0006) +#define GST_RIFF_WAVE_FORMAT_MULAW (0x0007) +#define GST_RIFF_WAVE_FORMAT_OKI_ADPCM (0x0010) +#define GST_RIFF_WAVE_FORMAT_DVI_ADPCM (0x0011) +#define GST_RIFF_WAVE_FORMAT_DIGISTD (0x0015) +#define GST_RIFF_WAVE_FORMAT_DIGIFIX (0x0016) +#define GST_RIFF_WAVE_FORMAT_YAMAHA_ADPCM (0x0020) +#define GST_RIFF_WAVE_FORMAT_DSP_TRUESPEECH (0x0022) +#define GST_RIFF_WAVE_FORMAT_GSM610 (0x0031) +#define GST_RIFF_WAVE_FORMAT_MSN (0x0032) +#define GST_RIFF_WAVE_FORMAT_MPEGL12 (0x0050) +#define GST_RIFF_WAVE_FORMAT_MPEGL3 (0x0055) +#define GST_RIFF_IBM_FORMAT_MULAW (0x0101) +#define GST_RIFF_IBM_FORMAT_ALAW (0x0102) +#define GST_RIFF_IBM_FORMAT_ADPCM (0x0103) +#define GST_RIFF_WAVE_FORMAT_DIVX_WMAV1 (0x0160) +#define GST_RIFF_WAVE_FORMAT_DIVX_WMAV2 (0x0161) +#define GST_RIFF_WAVE_FORMAT_WMAV9 (0x0162) +#define GST_RIFF_WAVE_FORMAT_A52 (0x2000) +#define GST_RIFF_WAVE_FORMAT_VORBIS1 (0x674f) +#define GST_RIFF_WAVE_FORMAT_VORBIS2 (0x6750) +#define GST_RIFF_WAVE_FORMAT_VORBIS3 (0x6751) +#define GST_RIFF_WAVE_FORMAT_VORBIS1PLUS (0x676f) +#define GST_RIFF_WAVE_FORMAT_VORBIS2PLUS (0x6770) +#define GST_RIFF_WAVE_FORMAT_VORBIS3PLUS (0x6771) + guint16 channels; + guint32 rate; + guint32 av_bps; + guint16 blockalign; + guint16 size; +} gst_riff_strf_auds; + +typedef struct _gst_riff_strf_iavs { + guint32 DVAAuxSrc; + guint32 DVAAuxCtl; + guint32 DVAAuxSrc1; + guint32 DVAAuxCtl1; + guint32 DVVAuxSrc; + guint32 DVVAuxCtl; + guint32 DVReserved1; + guint32 DVReserved2; +} gst_riff_strf_iavs; + +typedef struct _gst_riff_index_entry { + guint32 id; + guint32 flags; +#define GST_RIFF_IF_LIST (0x00000001L) +#define GST_RIFF_IF_KEYFRAME (0x00000010L) +#define GST_RIFF_IF_NO_TIME (0x00000100L) +#define GST_RIFF_IF_COMPUSE (0x0FFF0000L) + guint32 offset; + guint32 size; +} gst_riff_index_entry; + +typedef struct _gst_riff_dmlh { + guint32 totalframes; +} gst_riff_dmlh; + +#endif /* __GST_RIFF_IDS_H__ */ diff --git a/gst-libs/gst/riff/riff-media.c b/gst-libs/gst/riff/riff-media.c new file mode 100644 index 000000000..79db94202 --- /dev/null +++ b/gst-libs/gst/riff/riff-media.c @@ -0,0 +1,369 @@ +/* GStreamer RIFF I/O + * Copyright (C) 2003 Ronald Bultje + * + * riff-media.h: RIFF-id to/from caps routines + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "riff-ids.h" +#include "riff-media.h" + +GstCaps2 * +gst_riff_create_video_caps (guint32 codec_fcc, + gst_riff_strh *strh, + gst_riff_strf_vids *strf) +{ + GstCaps2 *caps = NULL; + + switch (codec_fcc) { + case GST_MAKE_FOURCC('I','4','2','0'): + case GST_MAKE_FOURCC('Y','U','Y','2'): + caps = gst_caps2_new_simple ("video/x-raw-yuv", + "format", GST_TYPE_FOURCC, codec_fcc, + NULL); + break; + + case GST_MAKE_FOURCC('M','J','P','G'): /* YUY2 MJPEG */ + case GST_MAKE_FOURCC('J','P','E','G'): /* generic (mostly RGB) MJPEG */ + case GST_MAKE_FOURCC('P','I','X','L'): /* Miro/Pinnacle fourccs */ + case GST_MAKE_FOURCC('V','I','X','L'): /* Miro/Pinnacle fourccs */ + caps = gst_caps2_new_simple ("video/x-jpeg", NULL); + break; + + case GST_MAKE_FOURCC('H','F','Y','U'): + caps = gst_caps2_new_simple ( "video/x-huffyuv", NULL); + break; + + case GST_MAKE_FOURCC('M','P','E','G'): + case GST_MAKE_FOURCC('M','P','G','I'): + caps = gst_caps2_new_simple ("video/mpeg", + "systemstream", G_TYPE_BOOLEAN, FALSE, + "mpegversion", G_TYPE_BOOLEAN, 1, + NULL); + break; + + case GST_MAKE_FOURCC('H','2','6','3'): + case GST_MAKE_FOURCC('i','2','6','3'): + case GST_MAKE_FOURCC('L','2','6','3'): + case GST_MAKE_FOURCC('M','2','6','3'): + case GST_MAKE_FOURCC('V','D','O','W'): + case GST_MAKE_FOURCC('V','I','V','O'): + case GST_MAKE_FOURCC('x','2','6','3'): + caps = gst_caps2_new_simple ("video/x-h263", NULL); + break; + + case GST_MAKE_FOURCC('D','I','V','3'): + case GST_MAKE_FOURCC('D','I','V','4'): + case GST_MAKE_FOURCC('D','I','V','5'): + caps = gst_caps2_new_simple ("video/x-divx", + "divxversion", G_TYPE_INT, 3, + NULL); + break; + + case GST_MAKE_FOURCC('d','i','v','x'): + case GST_MAKE_FOURCC('D','I','V','X'): + case GST_MAKE_FOURCC('D','X','5','0'): + caps = gst_caps2_new_simple ("video/x-divx", + "divxversion", G_TYPE_INT, 5, + NULL); + break; + + case GST_MAKE_FOURCC('X','V','I','D'): + case GST_MAKE_FOURCC('x','v','i','d'): + caps = gst_caps2_new_simple ("video/x-xvid", NULL); + break; + + case GST_MAKE_FOURCC('M','P','G','4'): + caps = gst_caps2_new_simple ("video/x-msmpeg", + "msmpegversion", G_TYPE_INT, 41, + NULL); + break; + + case GST_MAKE_FOURCC('M','P','4','2'): + caps = gst_caps2_new_simple ("video/x-msmpeg", + "msmpegversion", G_TYPE_INT, 42, + NULL); + break; + + case GST_MAKE_FOURCC('M','P','4','3'): + caps = gst_caps2_new_simple ("video/x-msmpeg", + "msmpegversion", G_TYPE_INT, 43, + NULL); + break; + + case GST_MAKE_FOURCC('3','I','V','1'): + case GST_MAKE_FOURCC('3','I','V','2'): + caps = gst_caps2_new_simple ( "video/x-3ivx", NULL); + break; + + case GST_MAKE_FOURCC('D','V','S','D'): + case GST_MAKE_FOURCC('d','v','s','d'): + caps = gst_caps2_new_simple ("video/x-dv", + "systemstream", G_TYPE_BOOLEAN, FALSE, + NULL); + break; + + case GST_MAKE_FOURCC('W','M','V','1'): + caps = gst_caps2_new_simple ("video/x-wmv", + "wmvversion", G_TYPE_INT, 1, + NULL); + break; + + case GST_MAKE_FOURCC('W','M','V','2'): + caps = gst_caps2_new_simple ("video/x-wmv", + "wmvversion", G_TYPE_INT, 2, + NULL); + break; + + default: + GST_WARNING ("Unkown video fourcc " GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (codec_fcc)); + return NULL; + } + + if (strh != NULL) { + gfloat fps = 1. * strh->rate / strh->scale; + + gst_caps2_set_simple (caps, "framerate", G_TYPE_DOUBLE, fps, NULL); + } else { + gst_caps2_set_simple (caps, + "framerate", GST_TYPE_DOUBLE_RANGE, 0., G_MAXDOUBLE, + NULL); + } + + if (strf != NULL) { + gst_caps2_set_simple (caps, + "width", G_TYPE_INT, strf->width, + "height", G_TYPE_INT, strf->height, + NULL); + } else { + gst_caps2_set_simple (caps, + "width", GST_TYPE_INT_RANGE, 16, 4096, + "height", GST_TYPE_INT_RANGE, 16, 4096, + NULL); + } + + return caps; +} + +GstCaps2 * +gst_riff_create_audio_caps (guint16 codec_id, + gst_riff_strh *strh, + gst_riff_strf_auds *strf) +{ + GstCaps2 *caps = NULL; + + switch (codec_id) { + case GST_RIFF_WAVE_FORMAT_MPEGL3: /* mp3 */ + caps = gst_caps2_new_simple ("audio/mpeg", + "mpegversion", G_TYPE_INT, 1, + "layer", G_TYPE_INT, 3, + NULL); + break; + + case GST_RIFF_WAVE_FORMAT_MPEGL12: /* mp1 or mp2 */ + caps = gst_caps2_new_simple ("audio/mpeg", + "layer", G_TYPE_INT, 2, + NULL); + break; + + case GST_RIFF_WAVE_FORMAT_PCM: /* PCM/wav */ + if (strf != NULL) { + gint ba = GUINT16_FROM_LE (strf->blockalign); + gint ch = GUINT16_FROM_LE (strf->channels); + gint ws = GUINT16_FROM_LE (strf->size); + + caps = gst_caps2_new_simple ("audio/x-raw-int", + "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, + "width", G_TYPE_INT, (int)(ba * 8 / ch), + "depth", G_TYPE_INT, ws, + "signed", G_TYPE_BOOLEAN, ws != 8, + NULL); + } else { + caps = gst_caps2_from_string ("audio/x-raw-int, " + "endianness = (int) LITTLE_ENDIAN, " + "signed = (boolean) { true, false }, " + "width = (int) { 8, 16 }, " + "height = (int) { 8, 16 }"); + } + break; + + case GST_RIFF_WAVE_FORMAT_MULAW: + if (strf != NULL && strf->size != 8) { + GST_WARNING ("invalid depth (%d) of mulaw audio, overwriting.", + strf->size); + } + caps = gst_caps2_new_simple ("audio/x-mulaw", NULL); + break; + + case GST_RIFF_WAVE_FORMAT_ALAW: + if (strf != NULL && strf->size != 8) { + GST_WARNING ("invalid depth (%d) of alaw audio, overwriting.", + strf->size); + } + caps = gst_caps2_new_simple ("audio/x-alaw", NULL); + break; + + case GST_RIFF_WAVE_FORMAT_VORBIS1: /* ogg/vorbis mode 1 */ + case GST_RIFF_WAVE_FORMAT_VORBIS2: /* ogg/vorbis mode 2 */ + case GST_RIFF_WAVE_FORMAT_VORBIS3: /* ogg/vorbis mode 3 */ + case GST_RIFF_WAVE_FORMAT_VORBIS1PLUS: /* ogg/vorbis mode 1+ */ + case GST_RIFF_WAVE_FORMAT_VORBIS2PLUS: /* ogg/vorbis mode 2+ */ + case GST_RIFF_WAVE_FORMAT_VORBIS3PLUS: /* ogg/vorbis mode 3+ */ + caps = gst_caps2_new_simple ("audio/x-vorbis", NULL); + break; + + case GST_RIFF_WAVE_FORMAT_A52: + caps = gst_caps2_new_simple ("audio/x-ac3", NULL); + break; + + default: + GST_WARNING ("Unkown audio tag 0x%04x", + codec_id); + break; + } + + if (strf != NULL) { + gst_caps2_set_simple (caps, + "rate", G_TYPE_INT, strf->rate, + "channels", G_TYPE_INT, strf->channels, + NULL); + } else { + gst_caps2_set_simple (caps, + "rate", GST_TYPE_INT_RANGE, 8000, 96000, + "channels", GST_TYPE_INT_RANGE, 1, 2, + NULL); + } + + return caps; +} + +GstCaps2 * +gst_riff_create_iavs_caps (guint32 codec_fcc, + gst_riff_strh *strh, + gst_riff_strf_iavs *strf) +{ + GstCaps2 *caps = NULL; + + switch (codec_fcc) { + /* is this correct? */ + case GST_MAKE_FOURCC ('D','V','S','D'): + case GST_MAKE_FOURCC ('d','v','s','d'): + caps = gst_caps2_new_simple ("video/x-dv", + "systemstream", G_TYPE_BOOLEAN, TRUE, NULL); + + default: + GST_WARNING ("Unkown IAVS fourcc " GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (codec_fcc)); + return NULL; + } + + return caps; +} + +/* + * Functions below are for template caps. All is variable. + */ + +GstCaps2 * +gst_riff_create_video_template_caps (void) +{ + guint32 tags[] = { + GST_MAKE_FOURCC ('I','4','2','0'), + GST_MAKE_FOURCC ('Y','U','Y','2'), + GST_MAKE_FOURCC ('M','J','P','G'), + GST_MAKE_FOURCC ('D','V','S','D'), + GST_MAKE_FOURCC ('W','M','V','1'), + GST_MAKE_FOURCC ('W','M','V','2'), + GST_MAKE_FOURCC ('M','P','G','4'), + GST_MAKE_FOURCC ('M','P','4','2'), + GST_MAKE_FOURCC ('M','P','4','3'), + GST_MAKE_FOURCC ('H','F','Y','U'), + GST_MAKE_FOURCC ('D','I','V','3'), + GST_MAKE_FOURCC ('M','P','E','G'), + GST_MAKE_FOURCC ('H','2','6','3'), + GST_MAKE_FOURCC ('D','I','V','X'), + GST_MAKE_FOURCC ('X','V','I','D'), + GST_MAKE_FOURCC ('3','I','V','1'), + /* FILL ME */ + 0 + }; + guint i; + GstCaps2 *caps, *one; + + caps = gst_caps2_new_empty (); + for (i = 0; tags[i] != 0; i++) { + one = gst_riff_create_video_caps (tags[i], NULL, NULL); + if (one) + gst_caps2_append (caps, one); + } + + return caps; +} + +GstCaps2 * +gst_riff_create_audio_template_caps (void) +{ + guint16 tags[] = { + GST_RIFF_WAVE_FORMAT_MPEGL3, + GST_RIFF_WAVE_FORMAT_MPEGL12, + GST_RIFF_WAVE_FORMAT_PCM, + GST_RIFF_WAVE_FORMAT_VORBIS1, + GST_RIFF_WAVE_FORMAT_A52, + GST_RIFF_WAVE_FORMAT_ALAW, + GST_RIFF_WAVE_FORMAT_MULAW, + /* FILL ME */ + 0 + }; + guint i; + GstCaps2 *caps, *one; + + caps = gst_caps2_new_empty (); + for (i = 0; tags[i] != 0; i++) { + one = gst_riff_create_audio_caps (tags[i], NULL, NULL); + if (one) + gst_caps2_append (caps, one); + } + + return caps; +} + +GstCaps2 * +gst_riff_create_iavs_template_caps (void) +{ + guint32 tags[] = { + GST_MAKE_FOURCC ('D','V','S','D'), + /* FILL ME */ + 0 + }; + guint i; + GstCaps2 *caps, *one; + + caps = gst_caps2_new_empty (); + for (i = 0; tags[i] != 0; i++) { + one = gst_riff_create_iavs_caps (tags[i], NULL, NULL); + if (one) + gst_caps2_append (caps, one); + } + + return caps; +} + diff --git a/gst-libs/gst/riff/riff-media.h b/gst-libs/gst/riff/riff-media.h new file mode 100644 index 000000000..1607fc3a3 --- /dev/null +++ b/gst-libs/gst/riff/riff-media.h @@ -0,0 +1,55 @@ +/* GStreamer RIFF I/O + * Copyright (C) 2003 Ronald Bultje + * + * riff-media.h: RIFF-id to/from caps routines + * + * 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_RIFF_MEDIA_H__ +#define __GST_RIFF_MEDIA_H__ + +#include +#include +#include "riff-ids.h" + +G_BEGIN_DECLS + +/* + * Create one caps. strh/strf can be NULL (for non-fixed caps). + */ + +GstCaps2 *gst_riff_create_video_caps (guint32 codec_fcc, + gst_riff_strh *strh, + gst_riff_strf_vids *strf); +GstCaps2 *gst_riff_create_audio_caps (guint16 codec_id, + gst_riff_strh *strh, + gst_riff_strf_auds *strf); +GstCaps2 *gst_riff_create_iavs_caps (guint32 codec_fcc, + gst_riff_strh *strh, + gst_riff_strf_iavs *strf); + +/* + * Create template caps (includes all known types). + */ + +GstCaps2 *gst_riff_create_video_template_caps (void); +GstCaps2 *gst_riff_create_audio_template_caps (void); +GstCaps2 *gst_riff_create_iavs_template_caps (void); + +G_END_DECLS + +#endif /* __GST_RIFF_READ_H__ */ diff --git a/gst-libs/gst/riff/riff-read.c b/gst-libs/gst/riff/riff-read.c new file mode 100644 index 000000000..17daf0241 --- /dev/null +++ b/gst-libs/gst/riff/riff-read.c @@ -0,0 +1,868 @@ +/* GStreamer RIFF I/O + * Copyright (C) 2003 Ronald Bultje + * + * riff-read.c: RIFF input file parsing + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "riff-ids.h" +#include "riff-read.h" + +enum { + ARG_0, + ARG_METADATA + /* FILL ME */ +}; + +static void gst_riff_read_class_init (GstRiffReadClass *klass); +static void gst_riff_read_init (GstRiffRead *riff); +static void gst_riff_read_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static GstElementStateReturn + gst_riff_read_change_state (GstElement *element); + +static GstElementClass *parent_class = NULL; + +GType +gst_riff_read_get_type (void) +{ + static GType gst_riff_read_type = 0; + + if (!gst_riff_read_type) { + static const GTypeInfo gst_riff_read_info = { + sizeof (GstRiffReadClass), + NULL, + NULL, + (GClassInitFunc) gst_riff_read_class_init, + NULL, + NULL, + sizeof (GstRiffRead), + 0, + (GInstanceInitFunc) gst_riff_read_init, + }; + + gst_riff_read_type = + g_type_register_static (GST_TYPE_ELEMENT, "GstRiffRead", + &gst_riff_read_info, 0); + } + + return gst_riff_read_type; +} + +static void +gst_riff_read_class_init (GstRiffReadClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + + g_object_class_install_property (gobject_class, ARG_METADATA, + g_param_spec_boxed ("metadata", "Metadata", "Metadata", + GST_TYPE_CAPS2, G_PARAM_READABLE)); + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + gobject_class->get_property = gst_riff_read_get_property; + + gstelement_class->change_state = gst_riff_read_change_state; +} + +static void +gst_riff_read_init (GstRiffRead *riff) +{ + riff->sinkpad = NULL; + riff->bs = NULL; + riff->level = NULL; + riff->metadata = NULL; +} + +static void +gst_riff_read_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GstRiffRead *riff = GST_RIFF_READ (object); + + switch (prop_id) { + case ARG_METADATA: + g_value_set_boxed (value, riff->metadata); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstElementStateReturn +gst_riff_read_change_state (GstElement *element) +{ + GstRiffRead *riff = GST_RIFF_READ (element); + + switch (GST_STATE_TRANSITION (element)) { + case GST_STATE_READY_TO_PAUSED: + if (!riff->sinkpad) + return GST_STATE_FAILURE; + riff->bs = gst_bytestream_new (riff->sinkpad); + break; + case GST_STATE_PAUSED_TO_READY: + gst_caps2_replace (&riff->metadata, NULL); + gst_bytestream_destroy (riff->bs); + while (riff->level) { + GstRiffLevel *level = riff->level->data; + + riff->level = g_list_remove (riff->level, level); + g_free (level); + } + break; + default: + break; + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + + return GST_STATE_SUCCESS; +} + +/* + * Return: the amount of levels in the hierarchy that the + * current element lies higher than the previous one. + * The opposite isn't done - that's auto-done using list + * element reading. + */ + +static guint +gst_riff_read_element_level_up (GstRiffRead *riff) +{ + guint num = 0; + guint64 pos = gst_bytestream_tell (riff->bs); + + while (riff->level != NULL) { + GList *last = g_list_last (riff->level); + GstRiffLevel *level = last->data; + + if (pos >= level->start + level->length) { + riff->level = g_list_remove (riff->level, level); + g_free (level); + num++; + } else + break; + } + + return num; +} + +/* + * Read the next tag plus length (may be NULL). Return + * TRUE on success or FALSE on failure. + */ + +static gboolean +gst_riff_peek_head (GstRiffRead *riff, + guint32 *tag, + guint32 *length, + guint *level_up) +{ + guint8 *data; + + /* read */ + if (gst_bytestream_peek_bytes (riff->bs, &data, 8) != 8) { + GstEvent *event = NULL; + guint32 remaining; + + /* Here, we might encounter EOS */ + gst_bytestream_get_status (riff->bs, &remaining, &event); + if (event && GST_EVENT_TYPE (event) == GST_EVENT_EOS) { + gst_pad_event_default (riff->sinkpad, event); + } else { + gst_event_unref (event); + gst_element_error (GST_ELEMENT (riff), "Read error"); + } + return FALSE; + } + + /* parse tag + length (if wanted) */ + *tag = GUINT32_FROM_LE (((guint32 *) data)[0]); + if (length) + *length = GUINT32_FROM_LE (((guint32 *) data)[1]); + + /* level */ + if (level_up) + *level_up = gst_riff_read_element_level_up (riff); + + return TRUE; +} + +/* + * Read: the actual data (plus alignment and flush). + * Return: the data, as a GstBuffer. + */ + +static GstBuffer * +gst_riff_read_element_data (GstRiffRead *riff, + guint length) +{ + GstBuffer *buf = NULL; + + if (gst_bytestream_peek (riff->bs, &buf, length) != length) { + gst_element_error (GST_ELEMENT (riff), "Read error"); + if (buf) + gst_buffer_unref (buf); + return NULL; + } + + /* we need 16-bit alignment */ + if (length & 1) + length++; + + gst_bytestream_flush (riff->bs, length); + + return buf; +} + +/* + * Seek. + */ + +GstEvent * +gst_riff_read_seek (GstRiffRead *riff, + guint64 offset) +{ + guint64 length = gst_bytestream_length (riff->bs); + guint32 remaining; + GstEvent *event; + guchar *data; + + /* hack for AVI files with broken idx1 size chunk markers */ + if (offset > length) + offset = length; + + /* first, flush remaining buffers */ + gst_bytestream_get_status (riff->bs, &remaining, &event); + if (event) { + g_warning ("Unexpected event before seek"); + gst_event_unref (event); + } + if (remaining) + gst_bytestream_flush_fast (riff->bs, remaining); + + /* now seek */ + if (!gst_bytestream_seek (riff->bs, offset, GST_SEEK_METHOD_SET)) { + gst_element_error (GST_ELEMENT (riff), "Seek failed"); + return NULL; + } + + /* and now, peek a new byte. This will fail because there's a + * pending event. Then, take the event and return it. */ + if (gst_bytestream_peek_bytes (riff->bs, &data, 1)) + g_warning ("Unexpected data after seek"); + + /* get the discont event and return */ + gst_bytestream_get_status (riff->bs, &remaining, &event); + if (!event || GST_EVENT_TYPE (event) != GST_EVENT_DISCONTINUOUS) { + gst_element_error (GST_ELEMENT (riff), + "No discontinuity event after seek"); + if (event) + gst_event_unref (event); + return NULL; + } + + return event; +} + +/* + * Gives the tag of the next RIFF element. + */ + +guint32 +gst_riff_peek_tag (GstRiffRead *riff, + guint *level_up) +{ + guint32 tag; + + if (!gst_riff_peek_head (riff, &tag, NULL, level_up)) + return 0; + + return tag; +} + +/* + * Gives the tag of the next LIST/RIFF element. + */ + +guint32 +gst_riff_peek_list (GstRiffRead *riff) +{ + guint32 lst; + guint8 *data; + + if (!gst_riff_peek_head (riff, &lst, NULL, NULL)) + return FALSE; + if (lst != GST_RIFF_TAG_LIST) { + g_warning ("Not a LIST object"); + return 0; + } + + if (gst_bytestream_peek_bytes (riff->bs, &data, 12) != 12) { + gst_element_error (GST_ELEMENT (riff), "Read error"); + return 0; + } + + return GUINT32_FROM_LE (((guint32 *) data)[2]); +} + +/* + * Don't read data. + */ + +gboolean +gst_riff_read_skip (GstRiffRead *riff) +{ + guint32 tag, length; + GstEvent *event; + guint32 remaining; + + if (!gst_riff_peek_head (riff, &tag, &length, NULL)) + return FALSE; + + /* 16-bit alignment */ + if (length & 1) + length++; + + /* header itself */ + length += 8; + + /* see if we have that much data available */ + gst_bytestream_get_status (riff->bs, &remaining, &event); + if (event) { + g_warning ("Unexpected event in skip"); + gst_event_unref (event); + } + + /* yes */ + if (remaining >= length) { + gst_bytestream_flush_fast (riff->bs, length); + return TRUE; + } + + /* no */ + if (!(event = gst_riff_read_seek (riff, + gst_bytestream_tell (riff->bs) + length))) + return FALSE; + + gst_event_unref (event); + + return TRUE; +} + +/* + * Read any type of data. + */ + +gboolean +gst_riff_read_data (GstRiffRead *riff, + guint32 *tag, + GstBuffer **buf) +{ + guint32 length; + + if (!gst_riff_peek_head (riff, tag, &length, NULL)) + return FALSE; + gst_bytestream_flush_fast (riff->bs, 8); + + return ((*buf = gst_riff_read_element_data (riff, length)) != NULL); +} + +/* + * Read a string. + */ + +gboolean +gst_riff_read_ascii (GstRiffRead *riff, + guint32 *tag, + gchar **str) +{ + GstBuffer *buf; + + if (!gst_riff_read_data (riff, tag, &buf)) + return FALSE; + + *str = g_malloc (GST_BUFFER_SIZE (buf) + 1); + memcpy (*str, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); + (*str)[GST_BUFFER_SIZE (buf)] = '\0'; + + gst_buffer_unref (buf); + + return TRUE; +} + +/* + * Read media structs. + */ + +gboolean +gst_riff_read_strh (GstRiffRead *riff, + gst_riff_strh **header) +{ + guint32 tag; + GstBuffer *buf; + gst_riff_strh *strh; + + if (!gst_riff_read_data (riff, &tag, &buf)) + return FALSE; + + if (tag != GST_RIFF_TAG_strh) { + g_warning ("Not a strh chunk"); + gst_buffer_unref (buf); + return FALSE; + } + if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_strh)) { + g_warning ("Too small strh (%d available, %d needed)", + GST_BUFFER_SIZE (buf), sizeof (gst_riff_strh)); + gst_buffer_unref (buf); + return FALSE; + } + + strh = g_memdup (GST_BUFFER_DATA (buf), + GST_BUFFER_SIZE (buf)); + gst_buffer_unref (buf); + +#if (G_BYTE_ORDER == G_BIG_ENDIAN) + strh->type = GUINT32_FROM_LE (strh->type); + strh->fcc_handler = GUINT32_FROM_LE (strh->fcc_handler); + strh->flags = GUINT32_FROM_LE (strh->flags); + strh->priority = GUINT32_FROM_LE (strh->priority); + strh->init_frames = GUINT32_FROM_LE (strh->init_frames); + strh->scale = GUINT32_FROM_LE (strh->scale); + strh->rate = GUINT32_FROM_LE (strh->rate); + strh->start = GUINT32_FROM_LE (strh->start); + strh->length = GUINT32_FROM_LE (strh->length); + strh->bufsize = GUINT32_FROM_LE (strh->bufsize); + strh->quality = GUINT32_FROM_LE (strh->quality); + strh->samplesize = GUINT32_FROM_LE (strh->samplesize); +#endif + + /* avoid divisions by zero */ + if (!strh->scale) + strh->scale = 1; + if (!strh->rate) + strh->rate = 1; + + /* debug */ + GST_INFO ("strh tag found"); + GST_INFO (" type " GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (strh->type)); + GST_INFO (" fcc_handler " GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (strh->fcc_handler)); + GST_INFO (" flags 0x%08x", strh->flags); + GST_INFO (" priority %d", strh->priority); + GST_INFO (" init_frames %d", strh->init_frames); + GST_INFO (" scale %d", strh->scale); + GST_INFO (" rate %d", strh->rate); + GST_INFO (" start %d", strh->start); + GST_INFO (" length %d", strh->length); + GST_INFO (" bufsize %d", strh->bufsize); + GST_INFO (" quality %d", strh->quality); + GST_INFO (" samplesize %d", strh->samplesize); + + *header = strh; + + return TRUE; +} + +gboolean +gst_riff_read_strf_vids (GstRiffRead *riff, + gst_riff_strf_vids **header) +{ + guint32 tag; + GstBuffer *buf; + gst_riff_strf_vids *strf; + + if (!gst_riff_read_data (riff, &tag, &buf)) + return FALSE; + + if (tag != GST_RIFF_TAG_strf) { + g_warning ("Not a strf chunk"); + gst_buffer_unref (buf); + return FALSE; + } + if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_strf_vids)) { + g_warning ("Too small strf_vids (%d available, %d needed)", + GST_BUFFER_SIZE (buf), sizeof (gst_riff_strf_vids)); + gst_buffer_unref (buf); + return FALSE; + } + + strf = g_memdup (GST_BUFFER_DATA (buf), + GST_BUFFER_SIZE (buf)); + +#if (G_BYTE_ORDER == G_BIG_ENDIAN) + strf->size = GUINT32_FROM_LE (strf->size); + strf->width = GUINT32_FROM_LE (strf->width); + strf->height = GUINT32_FROM_LE (strf->height); + strf->planes = GUINT16_FROM_LE (strf->planes); + strf->bit_cnt = GUINT16_FROM_LE (strf->bit_cnt); + strf->compression = GUINT32_FROM_LE (strf->compression); + strf->image_size = GUINT32_FROM_LE (strf->image_size); + strf->xpels_meter = GUINT32_FROM_LE (strf->xpels_meter); + strf->ypels_meter = GUINT32_FROM_LE (strf->ypels_meter); + strf->num_colors = GUINT32_FROM_LE (strf->num_colors); + strf->imp_colors = GUINT32_FROM_LE (strf->imp_colors); +#endif + + /* size checking */ + if (strf->size > GST_BUFFER_SIZE (buf)) { + g_warning ("strf_vids header gave %d bytes data, only %d available", + strf->size, GST_BUFFER_SIZE (buf)); + strf->size = GST_BUFFER_SIZE (buf); + } + + /* debug */ + GST_INFO ("strf tag found in context vids:"); + GST_INFO (" size %d", strf->size); + GST_INFO (" width %d", strf->width); + GST_INFO (" height %d", strf->height); + GST_INFO (" planes %d", strf->planes); + GST_INFO (" bit_cnt %d", strf->bit_cnt); + GST_INFO (" compression " GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (strf->compression)); + GST_INFO (" image_size %d", strf->image_size); + GST_INFO (" xpels_meter %d", strf->xpels_meter); + GST_INFO (" ypels_meter %d", strf->ypels_meter); + GST_INFO (" num_colors %d", strf->num_colors); + GST_INFO (" imp_colors %d", strf->imp_colors); + + gst_buffer_unref (buf); + + *header = strf; + + return TRUE; +} + +gboolean +gst_riff_read_strf_auds (GstRiffRead *riff, + gst_riff_strf_auds **header) +{ + guint32 tag; + GstBuffer *buf; + gst_riff_strf_auds *strf; + + if (!gst_riff_read_data (riff, &tag, &buf)) + return FALSE; + + if (tag != GST_RIFF_TAG_strf) { + g_warning ("Not a strf chunk"); + gst_buffer_unref (buf); + return FALSE; + } + if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_strf_auds)) { + g_warning ("Too small strf_auds (%d available, %d needed)", + GST_BUFFER_SIZE (buf), sizeof (gst_riff_strf_auds)); + gst_buffer_unref (buf); + return FALSE; + } + + strf = g_memdup (GST_BUFFER_DATA (buf), + GST_BUFFER_SIZE (buf)); + +#if (G_BYTE_ORDER == G_BIG_ENDIAN) + strf->format = GUINT16_FROM_LE (strf->format); + strf->channels = GUINT16_FROM_LE (strf->channels); + strf->rate = GUINT32_FROM_LE (strf->rate); + strf->av_bps = GUINT32_FROM_LE (strf->av_bps); + strf->blockalign = GUINT16_FROM_LE (strf->blockalign); + strf->size = GUINT16_FROM_LE (strf->size); +#endif + + /* debug */ + GST_INFO ("strf tag found in context auds:"); + GST_INFO (" format %d", strf->format); + GST_INFO (" channels %d", strf->channels); + GST_INFO (" rate %d", strf->rate); + GST_INFO (" av_bps %d", strf->av_bps); + GST_INFO (" blockalign %d", strf->blockalign); + GST_INFO (" size %d", strf->size); /* wordsize, not extrasize! */ + + gst_buffer_unref (buf); + + *header = strf; + + return TRUE; +} + +gboolean +gst_riff_read_strf_iavs (GstRiffRead *riff, + gst_riff_strf_iavs **header) +{ + guint32 tag; + GstBuffer *buf; + gst_riff_strf_iavs *strf; + + if (!gst_riff_read_data (riff, &tag, &buf)) + return FALSE; + + if (tag != GST_RIFF_TAG_strf) { + g_warning ("Not a strf chunk"); + gst_buffer_unref (buf); + return FALSE; + } + if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_strf_iavs)) { + g_warning ("Too small strf_iavs (%d available, %d needed)", + GST_BUFFER_SIZE (buf), sizeof (gst_riff_strf_iavs)); + gst_buffer_unref (buf); + return FALSE; + } + + strf = g_memdup (GST_BUFFER_DATA (buf), + GST_BUFFER_SIZE (buf)); + gst_buffer_unref (buf); + +#if (G_BYTE_ORDER == G_BIG_ENDIAN) + strf->DVAAuxSrc = GUINT32_FROM_LE (strf->DVAAuxSrc); + strf->DVAAuxCtl = GUINT32_FROM_LE (strf->DVAAuxCtl); + strf->DVAAuxSrc1 = GUINT32_FROM_LE (strf->DVAAuxSrc1); + strf->DVAAuxCtl1 = GUINT32_FROM_LE (strf->DVAAuxCtl1); + strf->DVVAuxSrc = GUINT32_FROM_LE (strf->DVVAuxSrc); + strf->DVVAuxCtl = GUINT32_FROM_LE (strf->DVVAuxCtl); + strf->DVReserved1 = GUINT32_FROM_LE (strf->DVReserved1); + strf->DVReserved2 = GUINT32_FROM_LE (strf->DVReserved2); +#endif + + /* debug */ + GST_INFO ("strf tag found in context iavs"); + GST_INFO (" DVAAuxSrc %08x", strf->DVAAuxSrc); + GST_INFO (" DVAAuxCtl %08x", strf->DVAAuxCtl); + GST_INFO (" DVAAuxSrc1 %08x", strf->DVAAuxSrc1); + GST_INFO (" DVAAuxCtl1 %08x", strf->DVAAuxCtl1); + GST_INFO (" DVVAuxSrc %08x", strf->DVVAuxSrc); + GST_INFO (" DVVAuxCtl %08x", strf->DVVAuxCtl); + GST_INFO (" DVReserved1 %08x", strf->DVReserved1); + GST_INFO (" DVReserved2 %08x", strf->DVReserved2); + + *header = strf; + + return TRUE; +} + +/* + * Read a list. + */ + +gboolean +gst_riff_read_list (GstRiffRead *riff, + guint32 *tag) +{ + guint32 length, lst; + GstRiffLevel *level; + guint8 *data; + + if (!gst_riff_peek_head (riff, &lst, &length, NULL)) + return FALSE; + if (lst != GST_RIFF_TAG_LIST) { + g_warning ("Not a LIST object"); + return FALSE; + } + gst_bytestream_flush_fast (riff->bs, 8); + if (gst_bytestream_peek_bytes (riff->bs, &data, 4) != 4) { + gst_element_error (GST_ELEMENT (riff), "Read error"); + return FALSE; + } + gst_bytestream_flush_fast (riff->bs, 4); + *tag = GUINT32_FROM_LE (* (guint32 *) data); + + /* remember level */ + level = g_new (GstRiffLevel, 1); + level->start = gst_bytestream_tell (riff->bs); + level->length = length - 4; + riff->level = g_list_append (riff->level, level); + + return TRUE; +} + +/* + * Utility function for reading metadata in a RIFF file. + */ + +gboolean +gst_riff_read_info (GstRiffRead *riff) +{ + guint32 tag; + guint64 end; + GstRiffLevel *level; + GList *last; + gchar *name, *type; + GstCaps2 *caps; + + /* What we're doing here is ugly (oh no!); we look + * at our LIST tag size and assure that we do not + * cross boundaries. This is to maintain the level + * counter for the client app. */ + last = g_list_last (riff->level); + level = last->data; + riff->level = g_list_remove (riff->level, level); + end = level->start + level->length; + g_free (level); + + caps = gst_caps2_new_simple ("application/x-gst-metadata", NULL); + + while (gst_bytestream_tell (riff->bs) < end) { + if (!gst_riff_peek_head (riff, &tag, NULL, NULL)) { + return FALSE; + } + + /* find out the type of metadata */ + switch (tag) { + case GST_RIFF_INFO_IARL: + type = "Location"; + break; + case GST_RIFF_INFO_IART: + type = "Artist"; + break; + case GST_RIFF_INFO_ICMS: + type = "Commissioner"; + break; + case GST_RIFF_INFO_ICMT: + type = "Comment"; + break; + case GST_RIFF_INFO_ICOP: + type = "Copyright"; + break; + case GST_RIFF_INFO_ICRD: + type = "Creation Date"; + break; + case GST_RIFF_INFO_ICRP: + type = "Cropped"; + break; + case GST_RIFF_INFO_IDIM: + type = "Dimensions"; + break; + case GST_RIFF_INFO_IDPI: + type = "Dots per Inch"; + break; + case GST_RIFF_INFO_IENG: + type = "Engineer"; + break; + case GST_RIFF_INFO_IGNR: + type = "Genre"; + break; + case GST_RIFF_INFO_IKEY: + type = "Keywords"; + break; + case GST_RIFF_INFO_ILGT: + type = "Lightness"; + break; + case GST_RIFF_INFO_IMED: + type = "Medium"; + break; + case GST_RIFF_INFO_INAM: + type = "Title"; /* "Name" */ + break; + case GST_RIFF_INFO_IPLT: + type = "Palette"; + break; + case GST_RIFF_INFO_IPRD: + type = "Product"; + break; + case GST_RIFF_INFO_ISBJ: + type = "Subject"; + break; + case GST_RIFF_INFO_ISFT: + type = "Encoder"; /* "Software" */ + break; + case GST_RIFF_INFO_ISHP: + type = "Sharpness"; + break; + case GST_RIFF_INFO_ISRC: + type = "Source"; + break; + case GST_RIFF_INFO_ISRF: + type = "Source Form"; + break; + case GST_RIFF_INFO_ITCH: + type = "Technician"; + break; + default: + type = NULL; + GST_WARNING ("Unknown INFO (metadata) tag entry " GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (tag)); + break; + } + + if (type) { + if (!gst_riff_read_ascii (riff, &tag, &name)) { + return FALSE; + } + + gst_caps2_set_simple (caps, type, G_TYPE_STRING, name, NULL); + } else { + gst_riff_read_skip (riff); + } + } + + /* let the world know about this wonderful thing */ + gst_caps2_replace (&riff->metadata, caps); + g_object_notify (G_OBJECT (riff), "metadata"); + + return TRUE; +} + +/* + * Read RIFF header and document type. + */ + +gboolean +gst_riff_read_header (GstRiffRead *riff, + guint32 *doctype) +{ + GstRiffLevel *level; + guint32 tag, length; + guint8 *data; + + /* We ignore size for openDML-2.0 support */ + if (!gst_riff_peek_head (riff, &tag, &length, NULL)) + return FALSE; + if (tag != GST_RIFF_TAG_RIFF) { + GST_WARNING ("Not a RIFF file"); + return FALSE; + } + gst_bytestream_flush_fast (riff->bs, 8); + + /* doctype */ + if (gst_bytestream_peek_bytes (riff->bs, &data, 4) != 4) { + gst_element_error (GST_ELEMENT (riff), "Read error"); + return FALSE; + } + gst_bytestream_flush_fast (riff->bs, 4); + *doctype = GUINT32_FROM_LE (* (guint32 *) data); + + /* remember level */ + level = g_new (GstRiffLevel, 1); + level->start = gst_bytestream_tell (riff->bs); + level->length = length - 4; + riff->level = g_list_append (riff->level, level); + + return TRUE; +} diff --git a/gst-libs/gst/riff/riff-read.h b/gst-libs/gst/riff/riff-read.h new file mode 100644 index 000000000..cf8c379bc --- /dev/null +++ b/gst-libs/gst/riff/riff-read.h @@ -0,0 +1,100 @@ +/* GStreamer RIFF I/O + * Copyright (C) 2003 Ronald Bultje + * + * riff-read.h: function declarations for parsing a RIFF file + * + * 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_RIFF_READ_H__ +#define __GST_RIFF_READ_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_RIFF_READ \ + (gst_riff_read_get_type ()) +#define GST_RIFF_READ(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RIFF_READ, GstRiffRead)) +#define GST_RIFF_READ_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RIFF_READ, GstRiffReadClass)) +#define GST_IS_RIFF_READ(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RIFF_READ)) +#define GST_IS_RIFF_READ_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RIFF_READ)) +#define GST_RIFF_READ_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RIFF_READ, GstRiffReadClass)) + +typedef struct _GstRiffLevel { + guint64 start, + length; +} GstRiffLevel; + +typedef struct _GstRiffRead { + GstElement parent; + + GstPad *sinkpad; + GstByteStream *bs; + + GList *level; + + /* metadata */ + GstCaps2 *metadata; +} GstRiffRead; + +typedef struct _GstRiffReadClass { + GstElementClass parent; +} GstRiffReadClass; + +GType gst_riff_read_get_type (void); + +guint32 gst_riff_peek_tag (GstRiffRead *riff, + guint *level_up); +guint32 gst_riff_peek_list (GstRiffRead *riff); + +GstEvent *gst_riff_read_seek (GstRiffRead *riff, + guint64 offset); +gboolean gst_riff_read_skip (GstRiffRead *riff); +gboolean gst_riff_read_data (GstRiffRead *riff, + guint32 *tag, + GstBuffer **buf); +gboolean gst_riff_read_ascii (GstRiffRead *riff, + guint32 *tag, + gchar **str); +gboolean gst_riff_read_list (GstRiffRead *riff, + guint32 *tag); +gboolean gst_riff_read_header (GstRiffRead *read, + guint32 *doctype); + +/* + * Utility functions (including byteswapping). + */ +gboolean gst_riff_read_strh (GstRiffRead *riff, + gst_riff_strh **header); +gboolean gst_riff_read_strf_vids (GstRiffRead *riff, + gst_riff_strf_vids **header); +gboolean gst_riff_read_strf_auds (GstRiffRead *riff, + gst_riff_strf_auds **header); +gboolean gst_riff_read_strf_iavs (GstRiffRead *riff, + gst_riff_strf_iavs **header); +gboolean gst_riff_read_info (GstRiffRead *riff); + +G_END_DECLS + +#endif /* __GST_RIFF_READ_H__ */ diff --git a/gst-libs/gst/riff/riff.c b/gst-libs/gst/riff/riff.c index bb29150c0..9c0ce2aec 100644 --- a/gst-libs/gst/riff/riff.c +++ b/gst-libs/gst/riff/riff.c @@ -1,5 +1,7 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen +/* GStreamer RIFF I/O + * Copyright (C) 2003 Ronald Bultje + * + * riff.c: plugin registering * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -18,26 +20,25 @@ */ #ifdef HAVE_CONFIG_H -# include "config.h" +#include "config.h" #endif -#include +#include static gboolean plugin_init (GstPlugin *plugin) { - return TRUE; + return gst_library_load ("gstbytestream"); } GST_PLUGIN_DEFINE ( GST_VERSION_MAJOR, GST_VERSION_MINOR, - "gstriff", - "RIFF convenience routines", + "riff", + "RIFF I/O functions", plugin_init, VERSION, GST_LICENSE, - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN ) diff --git a/gst-libs/gst/riff/riff.h b/gst-libs/gst/riff/riff.h deleted file mode 100644 index d8f57735b..000000000 --- a/gst-libs/gst/riff/riff.h +++ /dev/null @@ -1,448 +0,0 @@ -/* 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_RIFF_H__ -#define __GST_RIFF_H__ - - -#include - -typedef enum { - GST_RIFF_OK = 0, - GST_RIFF_ENOTRIFF = -1, - GST_RIFF_EINVAL = -2, - GST_RIFF_ENOMEM = -3 -} GstRiffReturn; - -/* states */ -typedef enum { - GST_RIFF_STATE_INITIAL = 0, - GST_RIFF_STATE_HASAVIH = 1, - GST_RIFF_STATE_HASSTRH = 2, - GST_RIFF_STATE_HASSTRF = 3, - GST_RIFF_STATE_MOVI = 4 -} GstRiffParserState; - -#define MAKE_FOUR_CC(a,b,c,d) GST_MAKE_FOURCC(a,b,c,d) - -/* RIFF types */ -#define GST_RIFF_RIFF_WAVE MAKE_FOUR_CC('W','A','V','E') -#define GST_RIFF_RIFF_AVI MAKE_FOUR_CC('A','V','I',' ') - -/* tags */ -#define GST_RIFF_TAG_RIFF MAKE_FOUR_CC('R','I','F','F') -#define GST_RIFF_TAG_RIFX MAKE_FOUR_CC('R','I','F','X') -#define GST_RIFF_TAG_LIST MAKE_FOUR_CC('L','I','S','T') -#define GST_RIFF_TAG_avih MAKE_FOUR_CC('a','v','i','h') -#define GST_RIFF_TAG_strd MAKE_FOUR_CC('s','t','r','d') -#define GST_RIFF_TAG_strn MAKE_FOUR_CC('s','t','r','n') -#define GST_RIFF_TAG_strh MAKE_FOUR_CC('s','t','r','h') -#define GST_RIFF_TAG_strf MAKE_FOUR_CC('s','t','r','f') -#define GST_RIFF_TAG_vedt MAKE_FOUR_CC('v','e','d','t') -#define GST_RIFF_TAG_JUNK MAKE_FOUR_CC('J','U','N','K') -#define GST_RIFF_TAG_idx1 MAKE_FOUR_CC('i','d','x','1') -#define GST_RIFF_TAG_dmlh MAKE_FOUR_CC('d','m','l','h') -/* WAV stuff */ -#define GST_RIFF_TAG_fmt MAKE_FOUR_CC('f','m','t',' ') -#define GST_RIFF_TAG_data MAKE_FOUR_CC('d','a','t','a') - -/* LIST types */ -#define GST_RIFF_LIST_movi MAKE_FOUR_CC('m','o','v','i') -#define GST_RIFF_LIST_hdrl MAKE_FOUR_CC('h','d','r','l') -#define GST_RIFF_LIST_strl MAKE_FOUR_CC('s','t','r','l') -#define GST_RIFF_LIST_INFO MAKE_FOUR_CC('I','N','F','O') - -/* fcc types */ -#define GST_RIFF_FCC_vids MAKE_FOUR_CC('v','i','d','s') -#define GST_RIFF_FCC_auds MAKE_FOUR_CC('a','u','d','s') -#define GST_RIFF_FCC_pads MAKE_FOUR_CC('p','a','d','s') -#define GST_RIFF_FCC_txts MAKE_FOUR_CC('t','x','t','s') -#define GST_RIFF_FCC_vidc MAKE_FOUR_CC('v','i','d','c') -#define GST_RIFF_FCC_iavs MAKE_FOUR_CC('i','a','v','s') -/* fcc handlers */ -#define GST_RIFF_FCCH_RLE MAKE_FOUR_CC('R','L','E',' ') -#define GST_RIFF_FCCH_msvc MAKE_FOUR_CC('m','s','v','c') -#define GST_RIFF_FCCH_MSVC MAKE_FOUR_CC('M','S','V','C') - -/* INFO types - see http://www.saettler.com/RIFFMCI/riffmci.html */ -#define GST_RIFF_INFO_IARL MAKE_FOUR_CC('I','A','R','L') /* location */ -#define GST_RIFF_INFO_IART MAKE_FOUR_CC('I','A','R','T') /* artist */ -#define GST_RIFF_INFO_ICMS MAKE_FOUR_CC('I','C','M','S') /* commissioned */ -#define GST_RIFF_INFO_ICMT MAKE_FOUR_CC('I','C','M','T') /* comment */ -#define GST_RIFF_INFO_ICOP MAKE_FOUR_CC('I','C','O','P') /* copyright */ -#define GST_RIFF_INFO_ICRD MAKE_FOUR_CC('I','C','R','D') /* creation date */ -#define GST_RIFF_INFO_ICRP MAKE_FOUR_CC('I','C','R','P') /* cropped */ -#define GST_RIFF_INFO_IDIM MAKE_FOUR_CC('I','D','I','M') /* dimensions */ -#define GST_RIFF_INFO_IDPI MAKE_FOUR_CC('I','D','P','I') /* dots-per-inch */ -#define GST_RIFF_INFO_IENG MAKE_FOUR_CC('I','E','N','G') /* engineer(s) */ -#define GST_RIFF_INFO_IGNR MAKE_FOUR_CC('I','G','N','R') /* genre */ -#define GST_RIFF_INFO_IKEY MAKE_FOUR_CC('I','K','E','Y') /* keywords */ -#define GST_RIFF_INFO_ILGT MAKE_FOUR_CC('I','L','G','T') /* lightness */ -#define GST_RIFF_INFO_IMED MAKE_FOUR_CC('I','M','E','D') /* medium */ -#define GST_RIFF_INFO_INAM MAKE_FOUR_CC('I','N','A','M') /* name */ -#define GST_RIFF_INFO_IPLT MAKE_FOUR_CC('I','P','L','T') /* palette setting */ -#define GST_RIFF_INFO_IPRD MAKE_FOUR_CC('I','P','R','D') /* product */ -#define GST_RIFF_INFO_ISBJ MAKE_FOUR_CC('I','S','B','J') /* subject */ -#define GST_RIFF_INFO_ISFT MAKE_FOUR_CC('I','S','F','T') /* software */ -#define GST_RIFF_INFO_ISHP MAKE_FOUR_CC('I','S','H','P') /* sharpness */ -#define GST_RIFF_INFO_ISRC MAKE_FOUR_CC('I','S','R','C') /* source */ -#define GST_RIFF_INFO_ISRF MAKE_FOUR_CC('I','S','R','F') /* source form */ -#define GST_RIFF_INFO_ITCH MAKE_FOUR_CC('I','T','C','H') /* technician(s) */ - -/*********Chunk Names***************/ -#define GST_RIFF_FF00 MAKE_FOUR_CC(0xFF,0xFF,0x00,0x00) -#define GST_RIFF_00 MAKE_FOUR_CC( '0', '0',0x00,0x00) -#define GST_RIFF_01 MAKE_FOUR_CC( '0', '1',0x00,0x00) -#define GST_RIFF_02 MAKE_FOUR_CC( '0', '2',0x00,0x00) -#define GST_RIFF_03 MAKE_FOUR_CC( '0', '3',0x00,0x00) -#define GST_RIFF_04 MAKE_FOUR_CC( '0', '4',0x00,0x00) -#define GST_RIFF_05 MAKE_FOUR_CC( '0', '5',0x00,0x00) -#define GST_RIFF_06 MAKE_FOUR_CC( '0', '6',0x00,0x00) -#define GST_RIFF_07 MAKE_FOUR_CC( '0', '7',0x00,0x00) -#define GST_RIFF_00pc MAKE_FOUR_CC( '0', '0', 'p', 'c') -#define GST_RIFF_01pc MAKE_FOUR_CC( '0', '1', 'p', 'c') -#define GST_RIFF_00dc MAKE_FOUR_CC( '0', '0', 'd', 'c') -#define GST_RIFF_00dx MAKE_FOUR_CC( '0', '0', 'd', 'x') -#define GST_RIFF_00db MAKE_FOUR_CC( '0', '0', 'd', 'b') -#define GST_RIFF_00xx MAKE_FOUR_CC( '0', '0', 'x', 'x') -#define GST_RIFF_00id MAKE_FOUR_CC( '0', '0', 'i', 'd') -#define GST_RIFF_00rt MAKE_FOUR_CC( '0', '0', 'r', 't') -#define GST_RIFF_0021 MAKE_FOUR_CC( '0', '0', '2', '1') -#define GST_RIFF_00iv MAKE_FOUR_CC( '0', '0', 'i', 'v') -#define GST_RIFF_0031 MAKE_FOUR_CC( '0', '0', '3', '1') -#define GST_RIFF_0032 MAKE_FOUR_CC( '0', '0', '3', '2') -#define GST_RIFF_00vc MAKE_FOUR_CC( '0', '0', 'v', 'c') -#define GST_RIFF_00xm MAKE_FOUR_CC( '0', '0', 'x', 'm') -#define GST_RIFF_01wb MAKE_FOUR_CC( '0', '1', 'w', 'b') -#define GST_RIFF_01dc MAKE_FOUR_CC( '0', '1', 'd', 'c') -#define GST_RIFF_00__ MAKE_FOUR_CC( '0', '0', '_', '_') - -/*********VIDEO CODECS**************/ -#define GST_RIFF_cram MAKE_FOUR_CC( 'c', 'r', 'a', 'm') -#define GST_RIFF_CRAM MAKE_FOUR_CC( 'C', 'R', 'A', 'M') -#define GST_RIFF_wham MAKE_FOUR_CC( 'w', 'h', 'a', 'm') -#define GST_RIFF_WHAM MAKE_FOUR_CC( 'W', 'H', 'A', 'M') -#define GST_RIFF_rgb MAKE_FOUR_CC(0x00,0x00,0x00,0x00) -#define GST_RIFF_RGB MAKE_FOUR_CC( 'R', 'G', 'B', ' ') -#define GST_RIFF_rle8 MAKE_FOUR_CC(0x01,0x00,0x00,0x00) -#define GST_RIFF_RLE8 MAKE_FOUR_CC( 'R', 'L', 'E', '8') -#define GST_RIFF_rle4 MAKE_FOUR_CC(0x02,0x00,0x00,0x00) -#define GST_RIFF_RLE4 MAKE_FOUR_CC( 'R', 'L', 'E', '4') -#define GST_RIFF_none MAKE_FOUR_CC(0x00,0x00,0xFF,0xFF) -#define GST_RIFF_NONE MAKE_FOUR_CC( 'N', 'O', 'N', 'E') -#define GST_RIFF_pack MAKE_FOUR_CC(0x01,0x00,0xFF,0xFF) -#define GST_RIFF_PACK MAKE_FOUR_CC( 'P', 'A', 'C', 'K') -#define GST_RIFF_tran MAKE_FOUR_CC(0x02,0x00,0xFF,0xFF) -#define GST_RIFF_TRAN MAKE_FOUR_CC( 'T', 'R', 'A', 'N') -#define GST_RIFF_ccc MAKE_FOUR_CC(0x03,0x00,0xFF,0xFF) -#define GST_RIFF_CCC MAKE_FOUR_CC( 'C', 'C', 'C', ' ') -#define GST_RIFF_cyuv MAKE_FOUR_CC( 'c', 'y', 'u', 'v') -#define GST_RIFF_CYUV MAKE_FOUR_CC( 'C', 'Y', 'U', 'V') -#define GST_RIFF_jpeg MAKE_FOUR_CC(0x04,0x00,0xFF,0xFF) -#define GST_RIFF_JPEG MAKE_FOUR_CC( 'J', 'P', 'E', 'G') -#define GST_RIFF_MJPG MAKE_FOUR_CC( 'M', 'J', 'P', 'G') -#define GST_RIFF_mJPG MAKE_FOUR_CC( 'm', 'J', 'P', 'G') -#define GST_RIFF_IJPG MAKE_FOUR_CC( 'I', 'J', 'P', 'G') -#define GST_RIFF_rt21 MAKE_FOUR_CC( 'r', 't', '2', '1') -#define GST_RIFF_RT21 MAKE_FOUR_CC( 'R', 'T', '2', '1') -#define GST_RIFF_iv31 MAKE_FOUR_CC( 'i', 'v', '3', '1') -#define GST_RIFF_IV31 MAKE_FOUR_CC( 'I', 'V', '3', '1') -#define GST_RIFF_iv32 MAKE_FOUR_CC( 'i', 'v', '3', '2') -#define GST_RIFF_IV32 MAKE_FOUR_CC( 'I', 'V', '3', '2') -#define GST_RIFF_iv41 MAKE_FOUR_CC( 'i', 'v', '4', '1') -#define GST_RIFF_IV41 MAKE_FOUR_CC( 'I', 'V', '4', '1') -#define GST_RIFF_iv50 MAKE_FOUR_CC( 'i', 'v', '5', '0') -#define GST_RIFF_IV50 MAKE_FOUR_CC( 'I', 'V', '5', '0') -#define GST_RIFF_cvid MAKE_FOUR_CC( 'c', 'v', 'i', 'd') -#define GST_RIFF_CVID MAKE_FOUR_CC( 'C', 'V', 'I', 'D') -#define GST_RIFF_ULTI MAKE_FOUR_CC( 'U', 'L', 'T', 'I') -#define GST_RIFF_ulti MAKE_FOUR_CC( 'u', 'l', 't', 'i') -#define GST_RIFF_YUV9 MAKE_FOUR_CC( 'Y', 'V', 'U', '9') -#define GST_RIFF_YVU9 MAKE_FOUR_CC( 'Y', 'U', 'V', '9') -#define GST_RIFF_XMPG MAKE_FOUR_CC( 'X', 'M', 'P', 'G') -#define GST_RIFF_xmpg MAKE_FOUR_CC( 'x', 'm', 'p', 'g') -#define GST_RIFF_VDOW MAKE_FOUR_CC( 'V', 'D', 'O', 'W') -#define GST_RIFF_MVI1 MAKE_FOUR_CC( 'M', 'V', 'I', '1') -#define GST_RIFF_v422 MAKE_FOUR_CC( 'v', '4', '2', '2') -#define GST_RIFF_V422 MAKE_FOUR_CC( 'V', '4', '2', '2') -#define GST_RIFF_mvi1 MAKE_FOUR_CC( 'm', 'v', 'i', '1') -#define GST_RIFF_MPIX MAKE_FOUR_CC(0x04,0x00, 'i', '1') /* MotionPixels munged their id */ -#define GST_RIFF_AURA MAKE_FOUR_CC( 'A', 'U', 'R', 'A') -#define GST_RIFF_DMB1 MAKE_FOUR_CC( 'D', 'M', 'B', '1') -#define GST_RIFF_dmb1 MAKE_FOUR_CC( 'd', 'm', 'b', '1') - -#define GST_RIFF_BW10 MAKE_FOUR_CC( 'B', 'W', '1', '0') -#define GST_RIFF_bw10 MAKE_FOUR_CC( 'b', 'w', '1', '0') - -#define GST_RIFF_yuy2 MAKE_FOUR_CC( 'y', 'u', 'y', '2') -#define GST_RIFF_YUY2 MAKE_FOUR_CC( 'Y', 'U', 'Y', '2') -#define GST_RIFF_YUV8 MAKE_FOUR_CC( 'Y', 'U', 'V', '8') -#define GST_RIFF_WINX MAKE_FOUR_CC( 'W', 'I', 'N', 'X') -#define GST_RIFF_WPY2 MAKE_FOUR_CC( 'W', 'P', 'Y', '2') -#define GST_RIFF_m263 MAKE_FOUR_CC( 'm', '2', '6', '3') -#define GST_RIFF_M263 MAKE_FOUR_CC( 'M', '2', '6', '3') - -#define GST_RIFF_Q1_0 MAKE_FOUR_CC( 'Q', '1',0x2e, '0') -#define GST_RIFF_SFMC MAKE_FOUR_CC( 'S', 'F', 'M', 'C') - -#define GST_RIFF_y41p MAKE_FOUR_CC( 'y', '4', '1', 'p') -#define GST_RIFF_Y41P MAKE_FOUR_CC( 'Y', '4', '1', 'P') -#define GST_RIFF_yv12 MAKE_FOUR_CC( 'y', 'v', '1', '2') -#define GST_RIFF_YV12 MAKE_FOUR_CC( 'Y', 'V', '1', '2') -#define GST_RIFF_vixl MAKE_FOUR_CC( 'v', 'i', 'x', 'l') -#define GST_RIFF_VIXL MAKE_FOUR_CC( 'V', 'I', 'X', 'L') -#define GST_RIFF_iyuv MAKE_FOUR_CC( 'i', 'y', 'u', 'v') -#define GST_RIFF_IYUV MAKE_FOUR_CC( 'I', 'Y', 'U', 'V') -#define GST_RIFF_i420 MAKE_FOUR_CC( 'i', '4', '2', '0') -#define GST_RIFF_I420 MAKE_FOUR_CC( 'I', '4', '2', '0') -#define GST_RIFF_vyuy MAKE_FOUR_CC( 'v', 'y', 'u', 'y') -#define GST_RIFF_VYUY MAKE_FOUR_CC( 'V', 'Y', 'U', 'Y') - -#define GST_RIFF_DIV3 MAKE_FOUR_CC( 'D', 'I', 'V', '3') - -#define GST_RIFF_rpza MAKE_FOUR_CC( 'r', 'p', 'z', 'a') -/* And this here's the mistakes that need to be supported */ -#define GST_RIFF_azpr MAKE_FOUR_CC( 'a', 'z', 'p', 'r') /* recognize Apple's rpza mangled? */ - -/*********** FND in MJPG **********/ -#define GST_RIFF_ISFT MAKE_FOUR_CC( 'I', 'S', 'F', 'T') -#define GST_RIFF_IDIT MAKE_FOUR_CC( 'I', 'D', 'I', 'T') - -#define GST_RIFF_00AM MAKE_FOUR_CC( '0', '0', 'A', 'M') -#define GST_RIFF_DISP MAKE_FOUR_CC( 'D', 'I', 'S', 'P') -#define GST_RIFF_ISBJ MAKE_FOUR_CC( 'I', 'S', 'B', 'J') - -#define GST_RIFF_rec MAKE_FOUR_CC( 'r', 'e', 'c', ' ') - -/* common data structures */ -struct _gst_riff_avih { - guint32 us_frame; /* microsec per frame */ - guint32 max_bps; /* byte/s overall */ - guint32 pad_gran; /* pad_gran (???) */ - guint32 flags; -/* flags values */ -#define GST_RIFF_AVIH_HASINDEX 0x00000010 /* has idx1 chunk */ -#define GST_RIFF_AVIH_MUSTUSEINDEX 0x00000020 /* must use idx1 chunk to determine order */ -#define GST_RIFF_AVIH_ISINTERLEAVED 0x00000100 /* AVI file is interleaved */ -#define GST_RIFF_AVIH_WASCAPTUREFILE 0x00010000 /* specially allocated used for capturing real time video */ -#define GST_RIFF_AVIH_COPYRIGHTED 0x00020000 /* contains copyrighted data */ - guint32 tot_frames; /* # of frames (all) */ - guint32 init_frames; /* initial frames (???) */ - guint32 streams; - guint32 bufsize; /* suggested buffer size */ - guint32 width; - guint32 height; - guint32 scale; - guint32 rate; - guint32 start; - guint32 length; -}; - -struct _gst_riff_strh { - guint32 type; /* stream type */ - guint32 fcc_handler; /* fcc_handler */ - guint32 flags; -/* flags values */ -#define GST_RIFF_STRH_DISABLED 0x000000001 -#define GST_RIFF_STRH_VIDEOPALCHANGES 0x000010000 - guint32 priority; - guint32 init_frames; /* initial frames (???) */ - guint32 scale; - guint32 rate; - guint32 start; - guint32 length; - guint32 bufsize; /* suggested buffer size */ - guint32 quality; - guint32 samplesize; - /* XXX 16 bytes ? */ -}; - -struct _gst_riff_strf_vids { /* == BitMapInfoHeader */ - guint32 size; - guint32 width; - guint32 height; - guint16 planes; - guint16 bit_cnt; - guint32 compression; - guint32 image_size; - guint32 xpels_meter; - guint32 ypels_meter; - guint32 num_colors; /* used colors */ - guint32 imp_colors; /* important colors */ - /* may be more for some codecs */ -}; - - -struct _gst_riff_strf_auds { /* == WaveHeader (?) */ - guint16 format; -/**** from public Microsoft RIFF docs ******/ -#define GST_RIFF_WAVE_FORMAT_UNKNOWN (0x0000) -#define GST_RIFF_WAVE_FORMAT_PCM (0x0001) -#define GST_RIFF_WAVE_FORMAT_ADPCM (0x0002) -#define GST_RIFF_WAVE_FORMAT_IBM_CVSD (0x0005) -#define GST_RIFF_WAVE_FORMAT_ALAW (0x0006) -#define GST_RIFF_WAVE_FORMAT_MULAW (0x0007) -#define GST_RIFF_WAVE_FORMAT_OKI_ADPCM (0x0010) -#define GST_RIFF_WAVE_FORMAT_DVI_ADPCM (0x0011) -#define GST_RIFF_WAVE_FORMAT_DIGISTD (0x0015) -#define GST_RIFF_WAVE_FORMAT_DIGIFIX (0x0016) -#define GST_RIFF_WAVE_FORMAT_YAMAHA_ADPCM (0x0020) -#define GST_RIFF_WAVE_FORMAT_DSP_TRUESPEECH (0x0022) -#define GST_RIFF_WAVE_FORMAT_GSM610 (0x0031) -#define GST_RIFF_WAVE_FORMAT_MSN (0x0032) -#define GST_RIFF_WAVE_FORMAT_MPEGL12 (0x0050) -#define GST_RIFF_WAVE_FORMAT_MPEGL3 (0x0055) -#define GST_RIFF_IBM_FORMAT_MULAW (0x0101) -#define GST_RIFF_IBM_FORMAT_ALAW (0x0102) -#define GST_RIFF_IBM_FORMAT_ADPCM (0x0103) -#define GST_RIFF_WAVE_FORMAT_DIVX_WMAV1 (0x0160) -#define GST_RIFF_WAVE_FORMAT_DIVX_WMAV2 (0x0161) -#define GST_RIFF_WAVE_FORMAT_WMAV9 (0x0162) -#define GST_RIFF_WAVE_FORMAT_A52 (0x2000) -#define GST_RIFF_WAVE_FORMAT_VORBIS1 (0x674f) -#define GST_RIFF_WAVE_FORMAT_VORBIS2 (0x6750) -#define GST_RIFF_WAVE_FORMAT_VORBIS3 (0x6751) -#define GST_RIFF_WAVE_FORMAT_VORBIS1PLUS (0x676f) -#define GST_RIFF_WAVE_FORMAT_VORBIS2PLUS (0x6770) -#define GST_RIFF_WAVE_FORMAT_VORBIS3PLUS (0x6771) - guint16 channels; - guint32 rate; - guint32 av_bps; - guint16 blockalign; - guint16 size; -}; - -struct _gst_riff_strf_iavs { - guint32 DVAAuxSrc; - guint32 DVAAuxCtl; - guint32 DVAAuxSrc1; - guint32 DVAAuxCtl1; - guint32 DVVAuxSrc; - guint32 DVVAuxCtl; - guint32 DVReserved1; - guint32 DVReserved2; -}; - -struct _gst_riff_riff { - guint32 id; - guint32 size; - guint32 type; -}; - -struct _gst_riff_list { - guint32 id; - guint32 size; - guint32 type; -}; - -struct _gst_riff_chunk { - guint32 id; - guint32 size; -}; - -struct _gst_riff_index_entry { - guint32 id; - guint32 flags; -#define GST_RIFF_IF_LIST (0x00000001L) -#define GST_RIFF_IF_KEYFRAME (0x00000010L) -#define GST_RIFF_IF_NO_TIME (0x00000100L) -#define GST_RIFF_IF_COMPUSE (0x0FFF0000L) - guint32 offset; - guint32 size; -}; - -struct _gst_riff_dmlh { - guint32 totalframes; -}; - -typedef struct _gst_riff_riff gst_riff_riff; -typedef struct _gst_riff_list gst_riff_list; -typedef struct _gst_riff_chunk gst_riff_chunk; -typedef struct _gst_riff_index_entry gst_riff_index_entry; - -typedef struct _gst_riff_avih gst_riff_avih; -typedef struct _gst_riff_strh gst_riff_strh; -typedef struct _gst_riff_strf_vids gst_riff_strf_vids; -typedef struct _gst_riff_strf_auds gst_riff_strf_auds; -typedef struct _gst_riff_strf_iavs gst_riff_strf_iavs; -typedef struct _gst_riff_dmlh gst_riff_dmlh; -typedef struct _GstRiff GstRiff; -typedef struct _GstRiffChunk GstRiffChunk; - -typedef void (*GstRiffCallback) (GstRiffChunk *chunk, gpointer data); - -struct _GstRiff { - guint32 form; - - /* list of chunks, most recent at the head */ - GList *chunks; - - /* incomplete chunks are assembled here */ - GstRiffChunk *incomplete_chunk; - guint32 incomplete_chunk_size; - /* parse state */ - GstRiffParserState state; - guint32 curoffset; - guint32 nextlikely; - /* leftover data */ - guchar *dataleft; - guint32 dataleft_size; - - /* callback function and data pointer */ - GstRiffCallback new_tag_found; - gpointer callback_data; -}; - -struct _GstRiffChunk { - gulong offset; - - guint32 id; - guint32 size; - guint32 form; /* for list chunks */ - - gchar *data; -}; - - -/* from gstriffparse.c */ -GstRiff* gst_riff_parser_new (GstRiffCallback function, gpointer data); -GstRiffReturn gst_riff_parser_next_buffer (GstRiff *riff, GstBuffer *buf, gulong off); -void gst_riff_parser_resync (GstRiff *riff, gulong offset); -GstRiffChunk* gst_riff_parser_get_chunk (GstRiff *riff, guint32 fourcc); -guint32 gst_riff_parser_get_nextlikely (GstRiff *riff); - -/* from gstriffencode.c */ -GstRiff* gst_riff_encoder_new (guint32 type); -GstRiffReturn gst_riff_encoder_avih (GstRiff *riff, gst_riff_avih *head, gulong size); -GstRiffReturn gst_riff_encoder_strh (GstRiff *riff, guint32 fcc_type, - gst_riff_strh *head, gulong size); -GstRiffReturn gst_riff_encoder_strf (GstRiff *riff, void *format, gulong size); -GstRiffReturn gst_riff_encoder_chunk (GstRiff *riff, guint32 chunk_type, - void *chunk, gulong size); - -GstBuffer* gst_riff_encoder_get_buffer (GstRiff *riff); -GstBuffer* gst_riff_encoder_get_and_reset_buffer (GstRiff *riff); - -/* from gstriffutil.c */ -gulong gst_riff_fourcc_to_id (gchar *fourcc); -gchar* gst_riff_id_to_fourcc (gulong id); - - -#endif /* __GST_RIFF_H__ */ diff --git a/gst-libs/gst/riff/riffencode.c b/gst-libs/gst/riff/riffencode.c deleted file mode 100644 index 630725d56..000000000 --- a/gst-libs/gst/riff/riffencode.c +++ /dev/null @@ -1,181 +0,0 @@ -/* 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -/*#define DEBUG_ENABLED */ -#include "riff.h" - -#define GST_RIFF_ENCODER_BUF_SIZE 1024 - -#define ADD_CHUNK(riffenc, chunkid, chunksize) \ -{ \ - gst_riff_chunk *chunk;\ - chunk = (gst_riff_chunk *)(riffenc->dataleft + riffenc->nextlikely);\ - chunk->id = chunkid; \ - chunk->size = chunksize; \ - riffenc->nextlikely += sizeof(gst_riff_chunk); \ -} - -#define ADD_LIST(riffenc, listsize, listtype) \ -{ \ - gst_riff_list *list;\ - list = (gst_riff_list *)(riffenc->dataleft + riffenc->nextlikely); \ - list->id = GST_RIFF_TAG_LIST; \ - list->size = listsize; \ - list->type = listtype; \ - riffenc->nextlikely += sizeof(gst_riff_list); \ -} - - -GstRiff *gst_riff_encoder_new(guint32 type) { - GstRiff *riff; - gst_riff_list *list; - - GST_DEBUG ("gst_riff_encoder: making %4.4s encoder", (char *)&type); - riff = (GstRiff *)g_malloc(sizeof(GstRiff)); - g_return_val_if_fail(riff != NULL, NULL); - - riff->form = 0; - riff->chunks = NULL; - riff->state = GST_RIFF_STATE_INITIAL; - riff->curoffset = 0; - riff->incomplete_chunk = NULL; - riff->dataleft = g_malloc(GST_RIFF_ENCODER_BUF_SIZE); - riff->dataleft_size = GST_RIFF_ENCODER_BUF_SIZE; - riff->nextlikely = 0; - - list = (gst_riff_list *)riff->dataleft; - list->id = GST_RIFF_TAG_RIFF; - list->size = 0x00FFFFFF; - list->type = GST_RIFF_RIFF_AVI; - - riff->nextlikely += sizeof(gst_riff_list); - - return riff; -} - -gint gst_riff_encoder_avih(GstRiff *riff, gst_riff_avih *head, gulong size) { - gst_riff_chunk *chunk; - - g_return_val_if_fail(riff->state == GST_RIFF_STATE_INITIAL, GST_RIFF_EINVAL); - - GST_DEBUG ("gst_riff_encoder: add avih"); - - ADD_LIST(riff, 0xB8, GST_RIFF_LIST_hdrl); - - ADD_CHUNK(riff, GST_RIFF_TAG_avih, size); - - chunk = (gst_riff_chunk *)(riff->dataleft + riff->nextlikely); - memcpy(chunk, head, size); - riff->nextlikely += size; - - riff->state = GST_RIFF_STATE_HASAVIH; - return GST_RIFF_OK; -} - -gint gst_riff_encoder_strh(GstRiff *riff, guint32 fcc_type, gst_riff_strh *head, gulong size) { - gst_riff_chunk *chunk; - - g_return_val_if_fail(riff->state == GST_RIFF_STATE_HASAVIH || - riff->state == GST_RIFF_STATE_HASSTRF, GST_RIFF_EINVAL); - - GST_DEBUG ("gst_riff_encoder: add strh type %08x (%4.4s)", fcc_type, (char *)&fcc_type); - - ADD_LIST(riff, 108, GST_RIFF_LIST_strl); - - ADD_CHUNK(riff, GST_RIFF_TAG_strh, size); - - chunk = (gst_riff_chunk *)(riff->dataleft + riff->nextlikely); - head->type = fcc_type; - memcpy(chunk, head, size); - - riff->nextlikely += size; - - riff->state = GST_RIFF_STATE_HASSTRH; - return GST_RIFF_OK; -} - -gint gst_riff_encoder_strf(GstRiff *riff, void *format, gulong size) { - gst_riff_chunk *chunk; - - g_return_val_if_fail(riff->state == GST_RIFF_STATE_HASSTRH, GST_RIFF_EINVAL); - - GST_DEBUG ("gst_riff_encoder: add strf"); - - ADD_CHUNK(riff, GST_RIFF_TAG_strf, size); - - chunk = (gst_riff_chunk *)(riff->dataleft + riff->nextlikely); - memcpy(chunk, format, size); - riff->nextlikely += size; - - riff->state = GST_RIFF_STATE_HASSTRF; - return GST_RIFF_OK; -} - -gint gst_riff_encoder_chunk(GstRiff *riff, guint32 chunk_type, void *chunkdata, gulong size) { - gst_riff_chunk *chunk; - - g_return_val_if_fail(riff->state == GST_RIFF_STATE_HASSTRF || - riff->state == GST_RIFF_STATE_MOVI, GST_RIFF_EINVAL); - - if (riff->state != GST_RIFF_STATE_MOVI) { - ADD_LIST(riff, 0x00FFFFFF, GST_RIFF_LIST_movi); - riff->state = GST_RIFF_STATE_MOVI; - } - - GST_DEBUG ("gst_riff_encoder: add chunk type %08x (%4.4s)", chunk_type, (char *)&chunk_type); - - ADD_CHUNK(riff, chunk_type, size); - - if (chunkdata != NULL) { - chunk = (gst_riff_chunk *)(riff->dataleft + riff->nextlikely); - memcpy(chunk, chunkdata, size); - riff->nextlikely += size + (size&1); - } - - return GST_RIFF_OK; -} - -GstBuffer *gst_riff_encoder_get_buffer(GstRiff *riff) { - GstBuffer *newbuf; - - newbuf = gst_buffer_new(); - GST_BUFFER_DATA(newbuf) = riff->dataleft; - GST_BUFFER_SIZE(newbuf) = riff->nextlikely; - - return newbuf; -} - -GstBuffer *gst_riff_encoder_get_and_reset_buffer(GstRiff *riff) { - GstBuffer *newbuf; - - newbuf = gst_riff_encoder_get_buffer(riff); - - riff->dataleft = g_malloc(GST_RIFF_ENCODER_BUF_SIZE); - riff->dataleft_size = GST_RIFF_ENCODER_BUF_SIZE; - riff->nextlikely = 0; - - return newbuf; -} - diff --git a/gst-libs/gst/riff/riffparse.c b/gst-libs/gst/riff/riffparse.c deleted file mode 100644 index 72c9e4bb9..000000000 --- a/gst-libs/gst/riff/riffparse.c +++ /dev/null @@ -1,250 +0,0 @@ -/* 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -/*#define DEBUG_ENABLED */ -#include - -GstRiff* -gst_riff_parser_new (GstRiffCallback function, gpointer data) -{ - GstRiff *riff; - - riff = (GstRiff *)g_malloc(sizeof(GstRiff)); - g_return_val_if_fail(riff != NULL, NULL); - - riff->form = 0; - riff->chunks = NULL; - riff->state = 0; - riff->curoffset = 0; - riff->nextlikely = 0; - riff->new_tag_found = function; - riff->callback_data = data; - riff->incomplete_chunk = NULL; - riff->dataleft = NULL; - - return riff; -} - -gint -gst_riff_parser_next_buffer (GstRiff *riff, GstBuffer *buf, gulong off) -{ - gulong last, size; - GstRiffChunk *chunk; - - g_return_val_if_fail(riff != NULL, GST_RIFF_EINVAL); - g_return_val_if_fail(buf != NULL, GST_RIFF_EINVAL); - g_return_val_if_fail(GST_BUFFER_DATA(buf) != NULL, GST_RIFF_EINVAL); - - size = GST_BUFFER_SIZE(buf); - last = off + size; - - GST_DEBUG ("gst_riff_parser: offset new buffer 0x%08lx size 0x%08x", off, GST_BUFFER_SIZE(buf)); - - if (riff->dataleft) { - gulong newsize; - - GST_DEBUG ("gst_riff_parser: recovering left data"); - newsize = riff->dataleft_size + size; - riff->dataleft = g_realloc(riff->dataleft, newsize); - memcpy(riff->dataleft+riff->dataleft_size, GST_BUFFER_DATA(buf), size); - gst_buffer_unref(buf); - - buf = gst_buffer_new(); - GST_BUFFER_DATA(buf) = riff->dataleft; - size = GST_BUFFER_SIZE(buf) = newsize; - off -= riff->dataleft_size; - /*last -= riff->dataleft_size; */ - riff->dataleft = NULL; - } - - if (off == 0) { - guint32 *words = (guint32 *)GST_BUFFER_DATA(buf); - - /* don't even try to parse the head if it's not there FIXME */ - if (last < 12) { - riff->state = GST_RIFF_ENOTRIFF; - return riff->state; - } - - /*g_print("testing is 0x%08lx '%s'\n",words[0],gst_riff_id_to_fourcc(words[0])); */ - /* verify this is a valid RIFF file, first of all */ - if (GUINT32_FROM_LE (words[0]) != GST_RIFF_TAG_RIFF) { - riff->state = GST_RIFF_ENOTRIFF; - return riff->state; - } - riff->form = GUINT32_FROM_LE (words[2]); - /*g_print("form is 0x%08lx '%s'\n",words[2],gst_riff_id_to_fourcc(words[2])); */ - riff->nextlikely = 12; /* skip 'RIFF', length, and form */ - /* all OK here */ - riff->incomplete_chunk = NULL; - } - - /* if we have an incomplete chunk from the previous buffer */ - if (riff->incomplete_chunk) { - guint leftover; - GST_DEBUG ("gst_riff_parser: have incomplete chunk %08x filled", riff->incomplete_chunk_size); - leftover = riff->incomplete_chunk->size - riff->incomplete_chunk_size; - if (leftover <= size) { - GST_DEBUG ("gst_riff_parser: we can fill it from %08x with %08x bytes = %08x", - riff->incomplete_chunk_size, leftover, - riff->incomplete_chunk_size+leftover); - memcpy(riff->incomplete_chunk->data+riff->incomplete_chunk_size, GST_BUFFER_DATA(buf), leftover); - - if (riff->new_tag_found) { - riff->new_tag_found(riff->incomplete_chunk, riff->callback_data); - } - g_free(riff->incomplete_chunk->data); - g_free(riff->incomplete_chunk); - riff->incomplete_chunk = NULL; - } - else { - GST_DEBUG ("gst_riff_parser: we cannot fill it %08x >= %08lx", leftover, size); - memcpy(riff->incomplete_chunk->data+riff->incomplete_chunk_size, GST_BUFFER_DATA(buf), size); - riff->incomplete_chunk_size += size; - return 0; - } - } - - if (riff->nextlikely & 0x01) riff->nextlikely++; - - GST_DEBUG ("gst_riff_parser: next 0x%08x last 0x%08lx offset %08lx",riff->nextlikely, last, off); - /* loop while the next likely chunk header is in this buffer */ - while ((riff->nextlikely+12) <= last) { - guint32 *words = (guint32 *)((guchar *)GST_BUFFER_DATA(buf) + riff->nextlikely - off ); - - /* loop over all of the chunks to check which one is finished */ - while (riff->chunks) { - chunk = g_list_nth_data(riff->chunks, 0); - - GST_DEBUG ("gst_riff_parser: next 0x%08x offset 0x%08lx size 0x%08x",riff->nextlikely, - chunk->offset, chunk->size); - if (riff->nextlikely >= chunk->offset+chunk->size) { - GST_DEBUG ("gst_riff_parser: found END LIST"); - /* we have the end of the chunk on the stack, remove it */ - riff->chunks = g_list_remove(riff->chunks, chunk); - } - else break; - } - - GST_DEBUG ("gst_riff_parser: next likely chunk is at offset 0x%08x",riff->nextlikely); - - chunk = (GstRiffChunk *)g_malloc(sizeof(GstRiffChunk)); - g_return_val_if_fail(chunk != NULL, GST_RIFF_ENOMEM); - - chunk->offset = riff->nextlikely+8; /* point to the actual data */ - chunk->id = GUINT32_FROM_LE (words[0]); - chunk->size = GUINT32_FROM_LE (words[1]); - chunk->data = (gchar *)(words+2); - /* we need word alignment */ - /*if (chunk->size & 0x01) chunk->size++; */ - chunk->form = GUINT32_FROM_LE (words[2]); /* fill in the form, might not be valid */ - - - if (chunk->id == GST_RIFF_TAG_LIST) { - GST_DEBUG ("found LIST %s", gst_riff_id_to_fourcc(chunk->form)); - riff->nextlikely += 12; - /* we push the list chunk on our 'stack' */ - riff->chunks = g_list_prepend(riff->chunks,chunk); - /* send the buffer to the listener if we have received a function */ - if (riff->new_tag_found) { - riff->new_tag_found(chunk, riff->callback_data); - } - } - else { - - GST_DEBUG ("gst_riff_parser: chunk id offset %08x is 0x%08x '" GST_FOURCC_FORMAT "' and is 0x%08x long", - riff->nextlikely, chunk->id, GST_FOURCC_ARGS(chunk->id), - chunk->size); - - riff->nextlikely += 8 + chunk->size; /* doesn't include hdr */ - /* if this buffer is incomplete */ - if (riff->nextlikely > last) { - guint left = size - (riff->nextlikely - chunk->size - off); - - GST_DEBUG ("make incomplete buffer %08x", left); - chunk->data = g_malloc(chunk->size); - memcpy(chunk->data, (gchar *)(words+2), left); - riff->incomplete_chunk = chunk; - riff->incomplete_chunk_size = left; - } - else { - /* send the buffer to the listener if we have received a function */ - if (riff->new_tag_found) { - riff->new_tag_found(chunk, riff->callback_data); - } - g_free(chunk); - } - if (riff->nextlikely & 0x01) riff->nextlikely++; - - /*riff->chunks = g_list_prepend(riff->chunks,chunk);*/ - } - } - if ((riff->nextlikely+12) > last && !riff->incomplete_chunk) { - guint left = last - riff->nextlikely; - GST_DEBUG ("gst_riff_parser: not enough data next 0x%08x last 0x%08lx %08x %08lx",riff->nextlikely, - last, left, off); - - riff->dataleft = g_malloc(left); - riff->dataleft_size = left; - memcpy(riff->dataleft, GST_BUFFER_DATA(buf)+size-left, left); - - return 0; - } - - return 0; -} - -void -gst_riff_parser_resync (GstRiff *riff, gulong offset) -{ - riff->incomplete_chunk = NULL; - riff->dataleft = NULL; - riff->nextlikely = offset; -} - - -GstRiffChunk *gst_riff_parser_get_chunk(GstRiff *riff, guint32 fourcc) -{ - GList *chunk; - - g_return_val_if_fail(riff != NULL, NULL); - - chunk = riff->chunks; - while (chunk) { - if (((GstRiffChunk *)(chunk->data))->id == fourcc) - return (GstRiffChunk *)(chunk->data); - chunk = g_list_next(chunk); - } - - return NULL; -} - -guint32 gst_riff_parser_get_nextlikely(GstRiff *riff) -{ - g_return_val_if_fail(riff != NULL, 0); - - return riff->nextlikely; -} - diff --git a/gst-libs/gst/riff/riffutil.c b/gst-libs/gst/riff/riffutil.c deleted file mode 100644 index d33aefe34..000000000 --- a/gst-libs/gst/riff/riffutil.c +++ /dev/null @@ -1,47 +0,0 @@ -/* 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - - -gulong gst_riff_fourcc_to_id(gchar *fourcc) { - g_return_val_if_fail(fourcc != NULL, 0); - - return GUINT32_FROM_LE((gulong)(fourcc[0] << 0) | (fourcc[1] << 8) | - (fourcc[2] << 16) | (fourcc[3] << 24)); -} - -gchar *gst_riff_id_to_fourcc(gulong id) { - static gchar fourcc[5]; - - g_return_val_if_fail(fourcc != NULL, NULL); - - id = GUINT32_FROM_LE(id); - fourcc[0] = (id >> 0) & 0xff; - fourcc[1] = (id >> 8) & 0xff; - fourcc[2] = (id >> 16) & 0xff; - fourcc[3] = (id >> 24) & 0xff; - fourcc[4] = 0; - - return fourcc; -} diff --git a/gst-libs/gst/tag/Makefile.am b/gst-libs/gst/tag/Makefile.am new file mode 100644 index 000000000..002d6ffbf --- /dev/null +++ b/gst-libs/gst/tag/Makefile.am @@ -0,0 +1,5 @@ +libgsttagincludedir = \ + $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/tag + +libgsttaginclude_HEADERS = \ + tag.h diff --git a/gst-libs/gst/tag/tag.h b/gst-libs/gst/tag/tag.h new file mode 100644 index 000000000..97eaf9361 --- /dev/null +++ b/gst-libs/gst/tag/tag.h @@ -0,0 +1,62 @@ +/* GStreamer + * Copyright (C) 2003 Benjamin Otte + * + * 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_TAG_TAG_H__ +#define __GST_TAG_TAG_H__ + +#include + +G_BEGIN_DECLS + + +/* functions for vorbis comment manipulation */ + +G_CONST_RETURN gchar * gst_tag_from_vorbis_tag (const gchar * vorbis_tag); +G_CONST_RETURN gchar * gst_tag_to_vorbis_tag (const gchar * gst_tag); +void gst_vorbis_tag_add (GstTagList * list, + const gchar * tag, + const gchar * value); + +GList * gst_tag_to_vorbis_comments (const GstTagList * list, + const gchar * tag); + +/* functions to convert GstBuffers with vorbiscomment contents to GstTagLists and back */ +GstTagList * gst_tag_list_from_vorbiscomment_buffer (const GstBuffer * buffer, + const guint8 * id_data, + const guint id_data_length, + gchar ** vendor_string); +GstBuffer * gst_tag_list_to_vorbiscomment_buffer (const GstTagList * list, + const guint8 * id_data, + const guint id_data_length, + const gchar * vendor_string); + +/* functions for ID3 tag manipulation */ + +guint gst_tag_id3_genre_count (void); +G_CONST_RETURN gchar * gst_tag_id3_genre_get (const guint id); +GstTagList * gst_tag_list_new_from_id3v1 (const guint8 * data); + +G_CONST_RETURN gchar * gst_tag_from_id3_tag (const gchar * vorbis_tag); +G_CONST_RETURN gchar * gst_tag_to_id3_tag (const gchar * gst_tag); + + +G_END_DECLS + +#endif /* __GST_TAG_TAG_H__ */ diff --git a/gst-libs/gst/tuner/Makefile.am b/gst-libs/gst/tuner/Makefile.am index 6d14130d9..f25ab297b 100644 --- a/gst-libs/gst/tuner/Makefile.am +++ b/gst-libs/gst/tuner/Makefile.am @@ -11,6 +11,25 @@ noinst_LTLIBRARIES = libgsttuner.la libgsttuner_la_SOURCES = \ tuner.c \ tunernorm.c \ - tunerchannel.c + tunerchannel.c \ + tunermarshal.c libgsttuner_la_CFLAGS = $(GST_CFLAGS) +BUILT_SOURCES = \ + tunermarshal.c \ + tunermarshal.h +built_headers = \ + tunermarshal.h + +EXTRA_DIST = tunermarshal.list + +CLEANFILES = $(BUILT_SOURCES) + +tunermarshal.h: tunermarshal.list + glib-genmarshal --header --prefix=gst_tuner_marshal $^ > tunermarshal.h.tmp + mv tunermarshal.h.tmp tunermarshal.h + +tunermarshal.c: tunermarshal.list + echo "#include \"tunermarshal.h\"" >> tunermarshal.c.tmp + glib-genmarshal --body --prefix=gst_tuner_marshal $^ >> tunermarshal.c.tmp + mv tunermarshal.c.tmp tunermarshal.c diff --git a/gst-libs/gst/tuner/tuner.c b/gst-libs/gst/tuner/tuner.c index 43dda8d0e..24c4aa032 100644 --- a/gst-libs/gst/tuner/tuner.c +++ b/gst-libs/gst/tuner/tuner.c @@ -24,9 +24,20 @@ #endif #include "tuner.h" +#include "tunermarshal.h" + +enum { + NORM_CHANGED, + CHANNEL_CHANGED, + FREQUENCY_CHANGED, + SIGNAL_CHANGED, + LAST_SIGNAL +}; static void gst_tuner_class_init (GstTunerClass *klass); +static guint gst_tuner_signals[LAST_SIGNAL] = { 0 }; + GType gst_tuner_get_type (void) { @@ -49,7 +60,7 @@ gst_tuner_get_type (void) "GstTuner", &gst_tuner_info, 0); g_type_interface_add_prerequisite (gst_tuner_type, - GST_TYPE_INTERFACE); + GST_TYPE_IMPLEMENTS_INTERFACE); } return gst_tuner_type; @@ -58,6 +69,41 @@ gst_tuner_get_type (void) static void gst_tuner_class_init (GstTunerClass *klass) { + static gboolean initialized = FALSE; + + if (!initialized) { + gst_tuner_signals[NORM_CHANGED] = + g_signal_new ("norm_changed", + GST_TYPE_TUNER, G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstTunerClass, norm_changed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, + GST_TYPE_TUNER_NORM); + gst_tuner_signals[CHANNEL_CHANGED] = + g_signal_new ("channel_changed", + GST_TYPE_TUNER, G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstTunerClass, channel_changed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, + GST_TYPE_TUNER_CHANNEL); + gst_tuner_signals[NORM_CHANGED] = + g_signal_new ("frequency_changed", + GST_TYPE_TUNER, G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstTunerClass, frequency_changed), + NULL, NULL, + gst_tuner_marshal_VOID__OBJECT_ULONG, G_TYPE_NONE, 2, + GST_TYPE_TUNER_CHANNEL, G_TYPE_ULONG); + gst_tuner_signals[NORM_CHANGED] = + g_signal_new ("signal_changed", + GST_TYPE_TUNER, G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstTunerClass, signal_changed), + NULL, NULL, + gst_tuner_marshal_VOID__OBJECT_INT, G_TYPE_NONE, 2, + GST_TYPE_TUNER_CHANNEL, G_TYPE_INT); + + initialized = TRUE; + } + /* default virtual functions */ klass->list_channels = NULL; klass->set_channel = NULL; @@ -188,3 +234,49 @@ gst_tuner_signal_strength (GstTuner *tuner, return 0; } + +void +gst_tuner_channel_changed (GstTuner *tuner, + GstTunerChannel *channel) +{ + g_signal_emit (G_OBJECT (tuner), + gst_tuner_signals[CHANNEL_CHANGED], 0, + channel); +} + +void +gst_tuner_norm_changed (GstTuner *tuner, + GstTunerNorm *norm) +{ + g_signal_emit (G_OBJECT (tuner), + gst_tuner_signals[NORM_CHANGED], 0, + norm); +} + +void +gst_tuner_frequency_changed (GstTuner *tuner, + GstTunerChannel *channel, + gulong frequency) +{ + g_signal_emit (G_OBJECT (tuner), + gst_tuner_signals[FREQUENCY_CHANGED], 0, + channel, frequency); + + g_signal_emit_by_name (G_OBJECT (channel), + "frequency_changed", + frequency); +} + +void +gst_tuner_signal_changed (GstTuner *tuner, + GstTunerChannel *channel, + gint signal) +{ + g_signal_emit (G_OBJECT (tuner), + gst_tuner_signals[SIGNAL_CHANGED], 0, + channel, signal); + + g_signal_emit_by_name (G_OBJECT (channel), + "signal_changed", + signal); +} diff --git a/gst-libs/gst/tuner/tuner.h b/gst-libs/gst/tuner/tuner.h index 1cd51e111..b1991c2c3 100644 --- a/gst-libs/gst/tuner/tuner.h +++ b/gst-libs/gst/tuner/tuner.h @@ -31,11 +31,11 @@ G_BEGIN_DECLS #define GST_TYPE_TUNER \ (gst_tuner_get_type ()) #define GST_TUNER(obj) \ - (GST_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TUNER, GstTuner)) + (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TUNER, GstTuner)) #define GST_TUNER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TUNER, GstTunerClass)) #define GST_IS_TUNER(obj) \ - (GST_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TUNER)) + (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TUNER)) #define GST_IS_TUNER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TUNER)) #define GST_TUNER_GET_CLASS(inst) \ @@ -66,6 +66,20 @@ typedef struct _GstTunerClass { GstTunerChannel *channel); gint (* signal_strength) (GstTuner *tuner, GstTunerChannel *channel); + + /* signals */ + void (*channel_changed) (GstTuner *tuner, + GstTunerChannel *channel); + void (*norm_changed) (GstTuner *tuner, + GstTunerNorm *norm); + void (*frequency_changed) (GstTuner *tuner, + GstTunerChannel *channel, + gulong frequency); + void (*signal_changed) (GstTuner *tuner, + GstTunerChannel *channel, + gint signal); + + gpointer _gst_reserved[GST_PADDING]; } GstTunerClass; GType gst_tuner_get_type (void); @@ -91,6 +105,18 @@ gulong gst_tuner_get_frequency (GstTuner *tuner, gint gst_tuner_signal_strength (GstTuner *tuner, GstTunerChannel *channel); +/* trigger signals */ +void gst_tuner_channel_changed (GstTuner *tuner, + GstTunerChannel *channel); +void gst_tuner_norm_changed (GstTuner *tuner, + GstTunerNorm *norm); +void gst_tuner_frequency_changed (GstTuner *tuner, + GstTunerChannel *channel, + gulong frequency); +void gst_tuner_signal_changed (GstTuner *tuner, + GstTunerChannel *channel, + gint signal); + G_END_DECLS #endif /* __GST_TUNER_H__ */ diff --git a/gst-libs/gst/tuner/tunerchannel.h b/gst-libs/gst/tuner/tunerchannel.h index b80314550..ee5654d0f 100644 --- a/gst-libs/gst/tuner/tunerchannel.h +++ b/gst-libs/gst/tuner/tunerchannel.h @@ -64,10 +64,12 @@ typedef struct _GstTunerChannelClass { GObjectClass parent; /* signals */ - void (*frequency_changed) (GstTunerChannel *tuner, + void (*frequency_changed) (GstTunerChannel *channel, gulong frequency); - void (*signal_changed) (GstTunerChannel *tuner, + void (*signal_changed) (GstTunerChannel *channel, gint signal); + + gpointer _gst_reserved[GST_PADDING]; } GstTunerChannelClass; GType gst_tuner_channel_get_type (void); diff --git a/gst-libs/gst/tuner/tunermarshal.list b/gst-libs/gst/tuner/tunermarshal.list new file mode 100644 index 000000000..c99ddc7d2 --- /dev/null +++ b/gst-libs/gst/tuner/tunermarshal.list @@ -0,0 +1,2 @@ +VOID:OBJECT,ULONG +VOID:OBJECT,INT diff --git a/gst-libs/gst/tuner/tunernorm.h b/gst-libs/gst/tuner/tunernorm.h index 3e6e801d7..cd89e1ee8 100644 --- a/gst-libs/gst/tuner/tunernorm.h +++ b/gst-libs/gst/tuner/tunernorm.h @@ -46,6 +46,8 @@ typedef struct _GstTunerNorm { typedef struct _GstTunerNormClass { GObjectClass parent; + + gpointer _gst_reserved[GST_PADDING]; } GstTunerNormClass; GType gst_tuner_norm_get_type (void); diff --git a/gst-libs/gst/video/gstvideosink.h b/gst-libs/gst/video/gstvideosink.h index 5e829b177..6ba23fd43 100644 --- a/gst-libs/gst/video/gstvideosink.h +++ b/gst-libs/gst/video/gstvideosink.h @@ -56,7 +56,7 @@ struct _GstVideoSink { GstClock *clock; - GST_OBJECT_PADDING + gpointer _gst_reserved[GST_PADDING]; }; struct _GstVideoSinkClass { @@ -65,7 +65,7 @@ struct _GstVideoSinkClass { /* signals */ void (*have_video_size) (GstVideoSink *element, gint width, gint height); - GST_CLASS_PADDING + gpointer _gst_reserved[GST_PADDING]; }; GType gst_videosink_get_type (void); diff --git a/gst-libs/gst/video/video.c b/gst-libs/gst/video/video.c index abcf9bc65..2fc54003a 100644 --- a/gst-libs/gst/video/video.c +++ b/gst-libs/gst/video/video.c @@ -113,7 +113,6 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, GST_LICENSE, - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN ) diff --git a/gst-libs/gst/video/videosink.h b/gst-libs/gst/video/videosink.h index 5e829b177..6ba23fd43 100644 --- a/gst-libs/gst/video/videosink.h +++ b/gst-libs/gst/video/videosink.h @@ -56,7 +56,7 @@ struct _GstVideoSink { GstClock *clock; - GST_OBJECT_PADDING + gpointer _gst_reserved[GST_PADDING]; }; struct _GstVideoSinkClass { @@ -65,7 +65,7 @@ struct _GstVideoSinkClass { /* signals */ void (*have_video_size) (GstVideoSink *element, gint width, gint height); - GST_CLASS_PADDING + gpointer _gst_reserved[GST_PADDING]; }; GType gst_videosink_get_type (void); diff --git a/gst-libs/gst/xoverlay/xoverlay.c b/gst-libs/gst/xoverlay/xoverlay.c index b4c737ff8..390453c15 100644 --- a/gst-libs/gst/xoverlay/xoverlay.c +++ b/gst-libs/gst/xoverlay/xoverlay.c @@ -56,7 +56,7 @@ gst_x_overlay_get_type (void) "GstXOverlay", &gst_x_overlay_info, 0); g_type_interface_add_prerequisite (gst_x_overlay_type, - GST_TYPE_INTERFACE); + GST_TYPE_IMPLEMENTS_INTERFACE); } return gst_x_overlay_type; @@ -65,6 +65,7 @@ gst_x_overlay_get_type (void) static void gst_x_overlay_base_init (gpointer g_class) { + GstXOverlayClass *overlay_class = (GstXOverlayClass *) g_class; static gboolean initialized = FALSE; if (! initialized) @@ -79,6 +80,8 @@ gst_x_overlay_base_init (gpointer g_class) initialized = TRUE; } + + overlay_class->set_xwindow_id = NULL; } /** diff --git a/gst-libs/gst/xoverlay/xoverlay.h b/gst-libs/gst/xoverlay/xoverlay.h index 65ac1dc78..062fadf4e 100644 --- a/gst-libs/gst/xoverlay/xoverlay.h +++ b/gst-libs/gst/xoverlay/xoverlay.h @@ -31,11 +31,12 @@ G_BEGIN_DECLS #define GST_TYPE_X_OVERLAY \ (gst_x_overlay_get_type ()) #define GST_X_OVERLAY(obj) \ - (GST_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_X_OVERLAY, GstXOverlay)) + (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_X_OVERLAY, \ + GstXOverlay)) #define GST_X_OVERLAY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_X_OVERLAY, GstXOverlayClass)) #define GST_IS_X_OVERLAY(obj) \ - (GST_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_X_OVERLAY)) + (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_X_OVERLAY)) #define GST_IS_X_OVERLAY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_X_OVERLAY)) #define GST_X_OVERLAY_GET_CLASS(inst) \ @@ -53,6 +54,8 @@ typedef struct _GstXOverlayClass { /* signals */ void (*have_xwindow_id) (GstXOverlay *overlay, XID xwindow_id); + + gpointer _gst_reserved[GST_PADDING]; } GstXOverlayClass; GType gst_x_overlay_get_type (void); diff --git a/gst-libs/gst/xwindowlistener/xwindowlistener.c b/gst-libs/gst/xwindowlistener/xwindowlistener.c index dda220c0e..a2b769941 100644 --- a/gst-libs/gst/xwindowlistener/xwindowlistener.c +++ b/gst-libs/gst/xwindowlistener/xwindowlistener.c @@ -650,7 +650,6 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, GST_LICENSE, - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN ) diff --git a/gst/smoothwave/gstsmoothwave.c b/gst/smoothwave/gstsmoothwave.c index a113bc539..57c267e51 100644 --- a/gst/smoothwave/gstsmoothwave.c +++ b/gst/smoothwave/gstsmoothwave.c @@ -310,6 +310,5 @@ GST_PLUGIN_DEFINE ( plugin_init, VERSION, "LGPL", - GST_COPYRIGHT, GST_PACKAGE, GST_ORIGIN) -- cgit v1.2.1