ext/flac/: Port flactag to 0.10, add documentation for it and clean it up a bit.

Original commit message from CVS:
Based on a patch by: Jonathan Matthew <notverysmart at gmail dot com>
* ext/flac/Makefile.am:
* ext/flac/gstflac.c: (plugin_init):
* ext/flac/gstflactag.c: (gst_flac_tag_setup_interfaces),
(gst_flac_tag_base_init), (gst_flac_tag_class_init),
(gst_flac_tag_dispose), (gst_flac_tag_init),
(gst_flac_tag_sink_setcaps), (gst_flac_tag_chain),
(gst_flac_tag_change_state):
* ext/flac/gstflactag.h:
Port flactag to 0.10, add documentation for it and clean it up a bit.
Fixes bug #413841.
* docs/plugins/Makefile.am:
* docs/plugins/gst-plugins-good-plugins-docs.sgml:
* docs/plugins/gst-plugins-good-plugins-sections.txt:
* docs/plugins/gst-plugins-good-plugins.hierarchy:
* docs/plugins/gst-plugins-good-plugins.interfaces:
* docs/plugins/gst-plugins-good-plugins.prerequisites:
* docs/plugins/inspect/plugin-flac.xml:
* ext/flac/gstflacdec.c: (gst_flac_dec_base_init):
* ext/flac/gstflacdec.h:
* ext/flac/gstflacenc.c: (gst_flac_enc_base_init):
* ext/flac/gstflacenc.h:
Add flactag and flacenc to the documentation and mark
the private parts of the flacdec instance structure as private.
Also use gst_element_class_set_details_simple() in flacdec and
flacenc.
This commit is contained in:
Jonathan Matthew 2008-08-06 15:34:55 +00:00 committed by Sebastian Dröge
parent dfd580b207
commit 8ced1b35ff
16 changed files with 499 additions and 459 deletions

View file

@ -1,3 +1,35 @@
2008-08-06 Sebastian Dröge <sebastian.droege@collabora.co.uk>
Based on a patch by: Jonathan Matthew <notverysmart at gmail dot com>
* ext/flac/Makefile.am:
* ext/flac/gstflac.c: (plugin_init):
* ext/flac/gstflactag.c: (gst_flac_tag_setup_interfaces),
(gst_flac_tag_base_init), (gst_flac_tag_class_init),
(gst_flac_tag_dispose), (gst_flac_tag_init),
(gst_flac_tag_sink_setcaps), (gst_flac_tag_chain),
(gst_flac_tag_change_state):
* ext/flac/gstflactag.h:
Port flactag to 0.10, add documentation for it and clean it up a bit.
Fixes bug #413841.
* docs/plugins/Makefile.am:
* docs/plugins/gst-plugins-good-plugins-docs.sgml:
* docs/plugins/gst-plugins-good-plugins-sections.txt:
* docs/plugins/gst-plugins-good-plugins.hierarchy:
* docs/plugins/gst-plugins-good-plugins.interfaces:
* docs/plugins/gst-plugins-good-plugins.prerequisites:
* docs/plugins/inspect/plugin-flac.xml:
* ext/flac/gstflacdec.c: (gst_flac_dec_base_init):
* ext/flac/gstflacdec.h:
* ext/flac/gstflacenc.c: (gst_flac_enc_base_init):
* ext/flac/gstflacenc.h:
Add flactag and flacenc to the documentation and mark
the private parts of the flacdec instance structure as private.
Also use gst_element_class_set_details_simple() in flacdec and
flacenc.
2008-08-06 Stefan Kost <ensonic@users.sf.net> 2008-08-06 Stefan Kost <ensonic@users.sf.net>
* gst/qtdemux/qtdemux.c: * gst/qtdemux/qtdemux.c:

View file

@ -84,6 +84,8 @@ EXTRA_HFILES = \
$(top_srcdir)/ext/dv/gstdvdemux.h \ $(top_srcdir)/ext/dv/gstdvdemux.h \
$(top_srcdir)/ext/esd/esdsink.h \ $(top_srcdir)/ext/esd/esdsink.h \
$(top_srcdir)/ext/flac/gstflacdec.h \ $(top_srcdir)/ext/flac/gstflacdec.h \
$(top_srcdir)/ext/flac/gstflacenc.h \
$(top_srcdir)/ext/flac/gstflactag.h \
$(top_srcdir)/ext/gdk_pixbuf/gstgdkpixbufsink.h \ $(top_srcdir)/ext/gdk_pixbuf/gstgdkpixbufsink.h \
$(top_srcdir)/ext/hal/gsthalaudiosink.h \ $(top_srcdir)/ext/hal/gsthalaudiosink.h \
$(top_srcdir)/ext/hal/gsthalaudiosrc.h \ $(top_srcdir)/ext/hal/gsthalaudiosrc.h \

View file

@ -46,6 +46,8 @@
<xi:include href="xml/element-equalizer-nbands.xml" /> <xi:include href="xml/element-equalizer-nbands.xml" />
<xi:include href="xml/element-esdsink.xml" /> <xi:include href="xml/element-esdsink.xml" />
<xi:include href="xml/element-flacdec.xml" /> <xi:include href="xml/element-flacdec.xml" />
<xi:include href="xml/element-flacenc.xml" />
<xi:include href="xml/element-flactag.xml" />
<xi:include href="xml/element-gamma.xml" /> <xi:include href="xml/element-gamma.xml" />
<xi:include href="xml/element-gdkpixbufsink.xml" /> <xi:include href="xml/element-gdkpixbufsink.xml" />
<xi:include href="xml/element-goom.xml" /> <xi:include href="xml/element-goom.xml" />

View file

@ -538,6 +538,34 @@ gst_flac_dec_get_type
LEGACY_FLAC LEGACY_FLAC
</SECTION> </SECTION>
<SECTION>
<FILE>element-flacenc</FILE>
<TITLE>flacenc</TITLE>
GstFlacEnc
<SUBSECTION Standard>
GstFlacEncClass
GST_TYPE_FLAC_ENC
GST_FLAC_ENC
GST_FLAC_ENC_CLASS
GST_IS_FLAC_ENC
GST_IS_FLAC_ENC_CLASS
gst_flac_enc_get_type
</SECTION>
<SECTION>
<FILE>element-flactag</FILE>
<TITLE>flactag</TITLE>
GstFlacTag
<SUBSECTION Standard>
GstFlacTagClass
GST_TYPE_FLAC_TAG
GST_FLAC_TAG
GST_FLAC_TAG_CLASS
GST_IS_FLAC_TAG
GST_IS_FLAC_TAG_CLASS
gst_flac_tag_get_type
</SECTION>
<SECTION> <SECTION>
<FILE>element-gamma</FILE> <FILE>element-gamma</FILE>
<TITLE>gamma</TITLE> <TITLE>gamma</TITLE>

View file

@ -11,34 +11,89 @@ GObject
GstElement GstElement
GstBin GstBin
GstPipeline GstPipeline
GstRTSPSrc GstHalAudioSink
GstRgVolume GstHalAudioSrc
GstAutoVideoSink
GstAutoAudioSink
GstGConfVideoSink GstGConfVideoSink
GstGConfVideoSrc GstGConfVideoSrc
GstSwitchSink GstSwitchSink
GstGConfAudioSink GstGConfAudioSink
GstGConfAudioSrc GstGConfAudioSrc
GstHalAudioSink GstAutoVideoSink
GstHalAudioSrc GstAutoAudioSink
GstAviDemux GstRgVolume
GstAviMux GstRTSPSrc
GstAviSubtitle GstPngDec
GstGoom2k1 GstPngEnc
GstEbmlRead GstJpegEnc
GstMatroskaDemux GstJpegDec
GstMatroskaMux GstSmokeEnc
GstFlxDec GstSmokeDec
GstBaseSink
GstBaseAudioSink
GstAudioSink
GstEsdSink
GstPulseSink
GstOssSink
GstAASink
GstCACASink
GstVideoSink
GstGdkPixbufSink
GstShout2send
GstTest
GstMultiUDPSink
GstUDPSink
GstDynUDPSink
GstMultiFileSink
GstCmmlEnc
GstCmmlDec
GstWavpackParse
GstWavpackDec
GstWavpackEnc
GstBaseSrc
GstPushSrc
GstDV1394Src
GstSoupHTTPSrc
GstBaseAudioSrc
GstAudioSrc
GstPulseSrc
GstOssSrc
GstCddaBaseSrc
GstCdioCddaSrc
GstV4l2Src
GstXImageSrc
GstUDPSrc
GstMultiFileSrc
GstPulseMixer
GstFlacEnc
GstFlacDec
GstFlacTag
GstCairoTextOverlay
GstBaseTransform GstBaseTransform
GstCairoTimeOverlay
GstPixbufScale
GstVideoCrop GstVideoCrop
GstAudioFilter
GstSpectrum
GstIirEqualizer
GstIirEqualizerNBands
GstIirEqualizer3Bands
GstIirEqualizer10Bands
GstAudioInvert
GstAudioKaraoke
GstAudioAmplify
GstAudioDynamic
GstAudioChebLimit
GstAudioChebBand
GstAudioWSincLimit
GstAudioWSincBand
GstVideoBox GstVideoBox
GstLevel
GstVideoFilter GstVideoFilter
GstSMPTEAlpha
GstNavigationtest GstNavigationtest
GstGamma GstGamma
GstVideoFlip
GstVideoBalance GstVideoBalance
GstVideoFlip
GstSMPTEAlpha
GstEdgeTV GstEdgeTV
GstAgingTV GstAgingTV
GstDiceTV GstDiceTV
@ -52,77 +107,46 @@ GObject
GstProgressReport GstProgressReport
GstTagInject GstTagInject
GstAudioPanorama GstAudioPanorama
GstAudioFilter
GstAudioInvert
GstAudioKaraoke
GstAudioAmplify
GstAudioDynamic
GstAudioChebLimit
GstAudioChebBand
GstAudioWSincLimit
GstAudioWSincBand
GstIirEqualizer
GstIirEqualizerNBands
GstIirEqualizer3Bands
GstIirEqualizer10Bands
GstSpectrum
GstAlphaColor
GstAlpha
GstRgAnalysis GstRgAnalysis
GstRgLimiter GstRgLimiter
GstLevel GstAlphaColor
GstPixbufScale GstAlpha
GstCairoTimeOverlay GstDVDemux
GstMonoscope GstDVDec
GstAuParse GstGdkPixbuf
GstSpeexEnc
GstSpeexDec
GstTagLibMux
GstId3v2Mux
GstApev2Mux
GstOssMixerElement
GstCutter
GstAviDemux
GstAviMux
GstAviSubtitle
GstGoom2k1
GstALawEnc
GstALawDec
GstMuLawEnc
GstMuLawDec
GstWavEnc
GstWavParse
GstICYDemux
GstVideoMixer GstVideoMixer
GstBaseSrc
GstPushSrc
GstMultiFileSrc
GstUDPSrc
GstXImageSrc
GstV4l2Src
GstBaseAudioSrc
GstAudioSrc
GstOssSrc
GstPulseSrc
GstDV1394Src
GstSoupHTTPSrc
GstCddaBaseSrc
GstCdioCddaSrc
GstBaseSink
GstMultiFileSink
GstMultiUDPSink
GstUDPSink
GstDynUDPSink
GstTest
GstBaseAudioSink
GstAudioSink
GstOssSink
GstPulseSink
GstEsdSink
GstAASink
GstVideoSink
GstGdkPixbufSink
GstCACASink
GstShout2send
GstInterleave
GstDeinterleave
GstRTPDec
GstSMPTE
GstRndBufferSize GstRndBufferSize
GstEFence GstEFence
GstFlxDec
GstTagDemux GstTagDemux
GstApeDemux GstApeDemux
GstID3Demux GstID3Demux
GstGoom GstAuParse
GstSMPTE
GstMultipartDemux GstMultipartDemux
GstMultipartMux GstMultipartMux
GstCutter GstInterleave
GstWavParse GstDeinterleave
GstQTDemux GstRTPDepay
GstBaseRTPDepayload GstBaseRTPDepayload
GstRtpXQTDepay
GstRtpAC3Depay GstRtpAC3Depay
GstRTPDVDepay GstRTPDVDepay
GstRTPiLBCDepay GstRTPiLBCDepay
@ -147,12 +171,7 @@ GObject
GstRtpTheoraDepay GstRtpTheoraDepay
GstRtpVorbisDepay GstRtpVorbisDepay
GstRtpVRawDepay GstRtpVRawDepay
GstMuLawEnc GstRtpXQTDepay
GstMuLawDec
GstALawEnc
GstALawDec
GstICYDemux
GstRTPDepay
GstBaseRTPPayload GstBaseRTPPayload
GstRTPDVPay GstRTPDVPay
GstBaseRTPAudioPayload GstBaseRTPAudioPayload
@ -177,31 +196,13 @@ GObject
GstRtpVorbisPay GstRtpVorbisPay
GstRtpVRawPay GstRtpVRawPay
GstAsteriskh263 GstAsteriskh263
GstWavEnc GstRTPDec
GstOssMixerElement GstEbmlRead
GstDVDemux GstMatroskaDemux
GstDVDec GstMatroskaMux
GstSpeexEnc GstMonoscope
GstSpeexDec GstGoom
GstCmmlEnc GstQTDemux
GstCmmlDec
GstGdkPixbuf
GstWavpackParse
GstWavpackDec
GstWavpackEnc
GstPngDec
GstPngEnc
GstCairoTextOverlay
GstTagLibMux
GstId3v2Mux
GstApev2Mux
GstFlacEnc
GstFlacDec
GstPulseMixer
GstJpegEnc
GstJpegDec
GstSmokeEnc
GstSmokeDec
GstBus GstBus
GstTask GstTask
GstClock GstClock
@ -211,23 +212,21 @@ GObject
GstRegistry GstRegistry
GstRingBuffer GstRingBuffer
GstSignalObject GstSignalObject
GstColorBalanceChannel
GstTunerNorm
GstTunerChannel
GstMixerTrack
GstMixerOptions
GstCmmlTagStream GstCmmlTagStream
GstCmmlTagHead GstCmmlTagHead
GstCmmlTagClip GstCmmlTagClip
GdkPixbuf GdkPixbuf
GstTunerNorm
GstTunerChannel
GstColorBalanceChannel
GInterface GInterface
GTypePlugin GTypePlugin
GstChildProxy GstChildProxy
GstURIHandler GstURIHandler
GstTagSetter
GstImplementsInterface
GstColorBalance
GstTuner
GstVideoOrientation
GstPropertyProbe GstPropertyProbe
GstImplementsInterface
GstMixer GstMixer
GstTagSetter
GstTuner
GstColorBalance
GstVideoOrientation

View file

@ -1,38 +1,39 @@
GstBin GstChildProxy GstBin GstChildProxy
GstPipeline GstChildProxy GstPipeline GstChildProxy
GstRTSPSrc GstChildProxy GstURIHandler GstHalAudioSink GstChildProxy
GstRgVolume GstChildProxy GstHalAudioSrc GstChildProxy
GstAutoVideoSink GstChildProxy
GstAutoAudioSink GstChildProxy
GstGConfVideoSink GstChildProxy GstGConfVideoSink GstChildProxy
GstGConfVideoSrc GstChildProxy GstGConfVideoSrc GstChildProxy
GstSwitchSink GstChildProxy GstSwitchSink GstChildProxy
GstGConfAudioSink GstChildProxy GstGConfAudioSink GstChildProxy
GstGConfAudioSrc GstChildProxy GstGConfAudioSrc GstChildProxy
GstHalAudioSink GstChildProxy GstAutoVideoSink GstChildProxy
GstHalAudioSrc GstChildProxy GstAutoAudioSink GstChildProxy
GstAviMux GstTagSetter GstRgVolume GstChildProxy
GstMatroskaMux GstTagSetter GstRTSPSrc GstChildProxy GstURIHandler
GstVideoBalance GstImplementsInterface GstColorBalance GstShout2send GstTagSetter
GstUDPSink GstURIHandler
GstDV1394Src GstURIHandler GstPropertyProbe
GstSoupHTTPSrc GstURIHandler
GstPulseSrc GstImplementsInterface GstMixer
GstOssSrc GstImplementsInterface GstMixer
GstCddaBaseSrc GstURIHandler
GstCdioCddaSrc GstURIHandler
GstV4l2Src GstPropertyProbe GstImplementsInterface GstTuner GstColorBalance GstVideoOrientation
GstUDPSrc GstURIHandler
GstPulseMixer GstPropertyProbe GstImplementsInterface GstMixer
GstFlacEnc GstTagSetter
GstFlacTag GstTagSetter
GstIirEqualizer GstChildProxy GstIirEqualizer GstChildProxy
GstIirEqualizerNBands GstChildProxy GstIirEqualizerNBands GstChildProxy
GstIirEqualizer3Bands GstChildProxy GstIirEqualizer3Bands GstChildProxy
GstIirEqualizer10Bands GstChildProxy GstIirEqualizer10Bands GstChildProxy
GstVideoMixer GstChildProxy GstVideoBalance GstImplementsInterface GstColorBalance
GstUDPSrc GstURIHandler
GstV4l2Src GstImplementsInterface GstColorBalance GstTuner GstVideoOrientation GstPropertyProbe
GstOssSrc GstImplementsInterface GstMixer
GstPulseSrc GstImplementsInterface GstMixer
GstDV1394Src GstURIHandler GstPropertyProbe
GstSoupHTTPSrc GstURIHandler
GstCddaBaseSrc GstURIHandler
GstCdioCddaSrc GstURIHandler
GstUDPSink GstURIHandler
GstShout2send GstTagSetter
GstOssMixerElement GstImplementsInterface GstMixer
GstSpeexEnc GstTagSetter GstSpeexEnc GstTagSetter
GstTagLibMux GstTagSetter GstTagLibMux GstTagSetter
GstId3v2Mux GstTagSetter GstId3v2Mux GstTagSetter
GstApev2Mux GstTagSetter GstApev2Mux GstTagSetter
GstFlacEnc GstTagSetter GstOssMixerElement GstImplementsInterface GstMixer
GstPulseMixer GstImplementsInterface GstMixer GstPropertyProbe GstAviMux GstTagSetter
GstVideoMixer GstChildProxy
GstMatroskaMux GstTagSetter

View file

@ -1,7 +1,7 @@
GstChildProxy GstObject GstChildProxy GstObject
GstTagSetter GstObject GstElement
GstImplementsInterface GstObject GstElement GstImplementsInterface GstObject GstElement
GstColorBalance GstObject GstImplementsInterface GstElement
GstTuner GstObject GstImplementsInterface GstElement
GstVideoOrientation GstObject GstImplementsInterface GstElement
GstMixer GstObject GstImplementsInterface GstElement GstMixer GstObject GstImplementsInterface GstElement
GstTagSetter GstObject GstElement
GstTuner GstObject GstImplementsInterface GstElement
GstColorBalance GstObject GstImplementsInterface GstElement
GstVideoOrientation GstObject GstImplementsInterface GstElement

View file

@ -3,10 +3,10 @@
<description>The FLAC Lossless compressor Codec</description> <description>The FLAC Lossless compressor Codec</description>
<filename>../../ext/flac/.libs/libgstflac.so</filename> <filename>../../ext/flac/.libs/libgstflac.so</filename>
<basename>libgstflac.so</basename> <basename>libgstflac.so</basename>
<version>0.10.9</version> <version>0.10.9.1</version>
<license>LGPL</license> <license>LGPL</license>
<source>gst-plugins-good</source> <source>gst-plugins-good</source>
<package>GStreamer Good Plug-ins source release</package> <package>GStreamer Good Plug-ins CVS/prerelease</package>
<origin>Unknown package origin</origin> <origin>Unknown package origin</origin>
<elements> <elements>
<element> <element>
@ -16,18 +16,18 @@
<description>Decodes FLAC lossless audio streams</description> <description>Decodes FLAC lossless audio streams</description>
<author>Wim Taymans &lt;wim@fluendo.com&gt;</author> <author>Wim Taymans &lt;wim@fluendo.com&gt;</author>
<pads> <pads>
<caps>
<name>src</name>
<direction>source</direction>
<presence>always</presence>
<details>audio/x-raw-int, endianness=(int)1234, signed=(boolean)true, width=(int){ 8, 16, 32 }, depth=(int)[ 4, 32 ], rate=(int)[ 1, 655350 ], channels=(int)[ 1, 8 ]</details>
</caps>
<caps> <caps>
<name>sink</name> <name>sink</name>
<direction>sink</direction> <direction>sink</direction>
<presence>always</presence> <presence>always</presence>
<details>audio/x-flac</details> <details>audio/x-flac</details>
</caps> </caps>
<caps>
<name>src</name>
<direction>source</direction>
<presence>always</presence>
<details>audio/x-raw-int, endianness=(int)1234, signed=(boolean)true, width=(int){ 8, 16, 32 }, depth=(int){ 8, 12, 16, 20, 24, 32 }, rate=(int)[ 8000, 96000 ], channels=(int)[ 1, 8 ]</details>
</caps>
</pads> </pads>
</element> </element>
<element> <element>
@ -36,6 +36,27 @@
<class>Codec/Encoder/Audio</class> <class>Codec/Encoder/Audio</class>
<description>Encodes audio with the FLAC lossless audio encoder</description> <description>Encodes audio with the FLAC lossless audio encoder</description>
<author>Wim Taymans &lt;wim.taymans@chello.be&gt;</author> <author>Wim Taymans &lt;wim.taymans@chello.be&gt;</author>
<pads>
<caps>
<name>sink</name>
<direction>sink</direction>
<presence>always</presence>
<details>audio/x-raw-int, endianness=(int)1234, signed=(boolean)true, width=(int)8, depth=(int)8, rate=(int)[ 1, 655350 ], channels=(int)[ 1, 8 ]; audio/x-raw-int, endianness=(int)1234, signed=(boolean)true, width=(int)16, depth=(int){ 12, 16 }, rate=(int)[ 1, 655350 ], channels=(int)[ 1, 8 ]; audio/x-raw-int, endianness=(int)1234, signed=(boolean)true, width=(int)32, depth=(int){ 20, 24 }, rate=(int)[ 1, 655350 ], channels=(int)[ 1, 8 ]</details>
</caps>
<caps>
<name>src</name>
<direction>source</direction>
<presence>always</presence>
<details>audio/x-flac</details>
</caps>
</pads>
</element>
<element>
<name>flactag</name>
<longname>FLAC tagger</longname>
<class>Formatter/Metadata</class>
<description>Rewrite tags in a FLAC file</description>
<author>Christophe Fergeau &lt;teuf@gnome.org&gt;</author>
<pads> <pads>
<caps> <caps>
<name>src</name> <name>src</name>
@ -47,7 +68,7 @@
<name>sink</name> <name>sink</name>
<direction>sink</direction> <direction>sink</direction>
<presence>always</presence> <presence>always</presence>
<details>audio/x-raw-int, endianness=(int)1234, signed=(boolean)true, width=(int)16, depth=(int)16, rate=(int)[ 8000, 96000 ], channels=(int)[ 1, 2 ]</details> <details>audio/x-flac</details>
</caps> </caps>
</pads> </pads>
</element> </element>

View file

@ -1,6 +1,6 @@
plugin_LTLIBRARIES = libgstflac.la plugin_LTLIBRARIES = libgstflac.la
libgstflac_la_SOURCES = gstflac.c gstflacdec.c gstflacenc.c libgstflac_la_SOURCES = gstflac.c gstflacdec.c gstflacenc.c gstflactag.c
libgstflac_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) libgstflac_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
libgstflac_la_LIBADD = \ libgstflac_la_LIBADD = \
$(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) \ $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) \
@ -8,4 +8,4 @@ libgstflac_la_LIBADD = \
$(GST_BASE_LIBS) $(GST_LIBS) $(FLAC_LIBS) $(GST_BASE_LIBS) $(GST_LIBS) $(FLAC_LIBS)
libgstflac_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstflac_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
noinst_HEADERS = gstflacenc.h gstflacdec.h noinst_HEADERS = gstflacenc.h gstflacdec.h gstflactag.h

View file

@ -23,7 +23,7 @@
#include "gstflacenc.h" #include "gstflacenc.h"
#include "gstflacdec.h" #include "gstflacdec.h"
/* #include "gstflactag.h" */ #include "gstflactag.h"
#include <gst/tag/tag.h> #include <gst/tag/tag.h>
#include <gst/gst-i18n-plugin.h> #include <gst/gst-i18n-plugin.h>
@ -43,11 +43,9 @@ plugin_init (GstPlugin * plugin)
if (!gst_element_register (plugin, "flacdec", GST_RANK_PRIMARY, if (!gst_element_register (plugin, "flacdec", GST_RANK_PRIMARY,
GST_TYPE_FLAC_DEC)) GST_TYPE_FLAC_DEC))
return FALSE; return FALSE;
#if 0
if (!gst_element_register (plugin, "flactag", GST_RANK_PRIMARY, if (!gst_element_register (plugin, "flactag", GST_RANK_PRIMARY,
gst_flac_tag_get_type ())) gst_flac_tag_get_type ()))
return FALSE; return FALSE;
#endif
gst_tag_register_musicbrainz_tags (); gst_tag_register_musicbrainz_tags ();

View file

@ -105,15 +105,7 @@ GST_DEBUG_CATEGORY_STATIC (flacdec_debug);
static GstPadTemplate *src_template, *sink_template; static GstPadTemplate *src_template, *sink_template;
static const GstElementDetails flacdec_details =
GST_ELEMENT_DETAILS ("FLAC audio decoder",
"Codec/Decoder/Audio",
"Decodes FLAC lossless audio streams",
"Wim Taymans <wim@fluendo.com>");
static void gst_flac_dec_finalize (GObject * object); static void gst_flac_dec_finalize (GObject * object);
static void gst_flac_dec_loop (GstPad * pad); static void gst_flac_dec_loop (GstPad * pad);
static GstStateChangeReturn gst_flac_dec_change_state (GstElement * element, static GstStateChangeReturn gst_flac_dec_change_state (GstElement * element,
@ -237,7 +229,9 @@ gst_flac_dec_base_init (gpointer g_class)
GST_PAD_ALWAYS, raw_caps); GST_PAD_ALWAYS, raw_caps);
gst_element_class_add_pad_template (element_class, sink_template); gst_element_class_add_pad_template (element_class, sink_template);
gst_element_class_add_pad_template (element_class, src_template); gst_element_class_add_pad_template (element_class, src_template);
gst_element_class_set_details (element_class, &flacdec_details); gst_element_class_set_details_simple (element_class, "FLAC audio decoder",
"Codec/Decoder/Audio",
"Decodes FLAC lossless audio streams", "Wim Taymans <wim@fluendo.com>");
GST_DEBUG_CATEGORY_INIT (flacdec_debug, "flacdec", 0, "flac decoder"); GST_DEBUG_CATEGORY_INIT (flacdec_debug, "flacdec", 0, "flac decoder");
} }

View file

@ -47,6 +47,8 @@ typedef struct _GstFlacDecClass GstFlacDecClass;
struct _GstFlacDec { struct _GstFlacDec {
GstElement element; GstElement element;
/* < private > */
#if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT < 8 #if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT < 8
FLAC__SeekableStreamDecoder *seekable_decoder; /* for pull-based operation */ FLAC__SeekableStreamDecoder *seekable_decoder; /* for pull-based operation */
#else #else

View file

@ -77,12 +77,6 @@ static const GstAudioChannelPosition channel_positions[8][8] = {
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT} GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}
}; };
static const GstElementDetails flacenc_details =
GST_ELEMENT_DETAILS ("FLAC audio encoder",
"Codec/Encoder/Audio",
"Encodes audio with the FLAC lossless audio encoder",
"Wim Taymans <wim.taymans@chello.be>");
#define FLAC_SINK_CAPS \ #define FLAC_SINK_CAPS \
"audio/x-raw-int, " \ "audio/x-raw-int, " \
"endianness = (int) BYTE_ORDER, " \ "endianness = (int) BYTE_ORDER, " \
@ -261,7 +255,10 @@ gst_flac_enc_base_init (gpointer g_class)
gst_element_class_add_pad_template (element_class, gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_factory)); gst_static_pad_template_get (&sink_factory));
gst_element_class_set_details (element_class, &flacenc_details); gst_element_class_set_details_simple (element_class, "FLAC audio encoder",
"Codec/Encoder/Audio",
"Encodes audio with the FLAC lossless audio encoder",
"Wim Taymans <wim.taymans@chello.be>");
GST_DEBUG_CATEGORY_INIT (flacenc_debug, "flacenc", 0, GST_DEBUG_CATEGORY_INIT (flacenc_debug, "flacenc", 0,
"Flac encoding element"); "Flac encoding element");

View file

@ -45,6 +45,8 @@ typedef struct _GstFlacEncClass GstFlacEncClass;
struct _GstFlacEnc { struct _GstFlacEnc {
GstElement element; GstElement element;
/* < private > */
GstPad *sinkpad; GstPad *sinkpad;
GstPad *srcpad; GstPad *srcpad;

View file

@ -1,6 +1,7 @@
/* GStreamer /* GStreamer
* Copyright (C) 2003 Christophe Fergeau <teuf@gnome.org> * Copyright (C) 2003 Christophe Fergeau <teuf@gnome.org>
* Copyright (C) 2008 Jonathan Matthew <jonathan@d14n.org>
* Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
* *
* gstflactag.c: plug-in for reading/modifying vorbis comments in flac files * gstflactag.c: plug-in for reading/modifying vorbis comments in flac files
* *
@ -20,78 +21,58 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
/**
* SECTION:element-flactag
* @see_also: #flacenc, #flacdec, #GstTagSetter
*
* The flactag element can change the tag contained within a raw
* FLAC stream. Specifically, it modifies the comments header packet
* of the FLAC stream.
*
* Applications can set the tags to write using the #GstTagSetter interface.
* Tags contained withing the FLAC bitstream will be picked up
* automatically (and merged according to the merge mode set via the tag
* setter interface).
*
* <refsect2>
* <title>Example pipelines</title>
* |[
* gst-launch -v filesrc location=foo.flac ! flactag ! filesink location=bar.flac
* ]| This element is not useful with gst-launch, because it does not support
* setting the tags on a #GstTagSetter interface. Conceptually, the element
* will usually be used in this order though.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include <gst/gst.h>
#include <gst/gsttagsetter.h> #include <gst/gsttagsetter.h>
#include <gst/base/gstadapter.h>
#include <gst/tag/tag.h> #include <gst/tag/tag.h>
#include <string.h> #include <string.h>
#define GST_TYPE_FLAC_TAG (gst_flac_tag_get_type()) #include "gstflactag.h"
#define GST_FLAC_TAG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FLAC_TAG, GstFlacTag))
#define GST_FLAC_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FLAC_TAG, GstFlacTag))
#define GST_IS_FLAC_TAG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FLAC_TAG))
#define GST_IS_FLAC_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FLAC_TAG))
typedef struct _GstFlacTag GstFlacTag; GST_DEBUG_CATEGORY_STATIC (flactag_debug);
typedef struct _GstFlacTagClass GstFlacTagClass; #define GST_CAT_DEFAULT flactag_debug
static inline gint
min (gint a, gint b)
{
if (a < b) {
return a;
} else {
return b;
}
}
typedef enum
{
GST_FLAC_TAG_STATE_INIT,
GST_FLAC_TAG_STATE_METADATA_BLOCKS,
GST_FLAC_TAG_STATE_METADATA_NEXT_BLOCK,
GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK,
GST_FLAC_TAG_STATE_VC_METADATA_BLOCK,
GST_FLAC_TAG_STATE_ADD_VORBIS_COMMENT,
GST_FLAC_TAG_STATE_AUDIO_DATA
}
GstFlacTagState;
struct _GstFlacTag
{
GstElement element;
/* pads */
GstPad *sinkpad;
GstPad *srcpad;
GstFlacTagState state;
GstBuffer *buffer;
GstBuffer *vorbiscomment;
GstTagList *tags;
guint metadata_bytes_remaining;
gboolean metadata_last_block;
gboolean only_output_tags;
};
struct _GstFlacTagClass
{
GstElementClass parent_class;
};
/* elementfactory information */ /* elementfactory information */
static const GstElementDetails gst_flac_tag_details = static GstStaticPadTemplate flac_tag_src_template =
GST_ELEMENT_DETAILS ("FLAC tagger", GST_STATIC_PAD_TEMPLATE ("src",
"Tag", GST_PAD_SRC,
"Rewrite tags in a FLAC file", GST_PAD_ALWAYS,
"Christope Fergeau <teuf@gnome.org>"); GST_STATIC_CAPS ("audio/x-flac")
);
static GstStaticPadTemplate flac_tag_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-flac")
);
/* signals and args */ /* signals and args */
enum enum
@ -106,121 +87,42 @@ enum
/* FILL ME */ /* FILL ME */
}; };
static GstStaticPadTemplate flac_tag_src_template = static void gst_flac_tag_dispose (GObject * object);
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-flac; application/x-gst-tags")
);
static GstStaticPadTemplate flac_tag_sink_template = static GstFlowReturn gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer);
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-flac")
);
static void gst_flac_tag_base_init (gpointer g_class);
static void gst_flac_tag_class_init (GstFlacTagClass * klass);
static void gst_flac_tag_init (GstFlacTag * tag);
static void gst_flac_tag_chain (GstPad * pad, GstData * data);
static GstStateChangeReturn gst_flac_tag_change_state (GstElement * element, static GstStateChangeReturn gst_flac_tag_change_state (GstElement * element,
GstStateChange transition); GstStateChange transition);
static gboolean gst_flac_tag_sink_setcaps (GstPad * pad, GstCaps * caps);
static GstElementClass *parent_class = NULL; static void
gst_flac_tag_setup_interfaces (GType flac_tag_type)
/* static guint gst_flac_tag_signals[LAST_SIGNAL] = { 0 }; */
GType
gst_flac_tag_get_type (void)
{ {
static GType flac_tag_type = 0; static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
if (!flac_tag_type) { g_type_add_interface_static (flac_tag_type, GST_TYPE_TAG_SETTER,
static const GTypeInfo flac_tag_info = { &tag_setter_info);
sizeof (GstFlacTagClass),
gst_flac_tag_base_init,
NULL,
(GClassInitFunc) gst_flac_tag_class_init,
NULL,
NULL,
sizeof (GstFlacTag),
0,
(GInstanceInitFunc) gst_flac_tag_init,
};
static const GInterfaceInfo tag_setter_info = {
NULL,
NULL,
NULL
};
flac_tag_type =
g_type_register_static (GST_TYPE_ELEMENT, "GstFlacTag", &flac_tag_info,
0);
g_type_add_interface_static (flac_tag_type, GST_TYPE_TAG_SETTER,
&tag_setter_info);
}
return flac_tag_type;
} }
GST_BOILERPLATE_FULL (GstFlacTag, gst_flac_tag, GstElement, GST_TYPE_ELEMENT,
gst_flac_tag_setup_interfaces);
static void static void
gst_flac_tag_base_init (gpointer g_class) gst_flac_tag_base_init (gpointer g_class)
{ {
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_details (element_class, &gst_flac_tag_details); gst_element_class_set_details_simple (element_class, "FLAC tagger",
"Formatter/Metadata",
"Rewrite tags in a FLAC file", "Christophe Fergeau <teuf@gnome.org>");
gst_element_class_add_pad_template (element_class, gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&flac_tag_sink_template)); gst_static_pad_template_get (&flac_tag_sink_template));
gst_element_class_add_pad_template (element_class, gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&flac_tag_src_template)); gst_static_pad_template_get (&flac_tag_src_template));
}
GST_DEBUG_CATEGORY_INIT (flactag_debug, "flactag", 0, "flac tag rewriter");
static void
send_eos (GstFlacTag * tag)
{
gst_element_set_eos (GST_ELEMENT (tag));
gst_pad_push (tag->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
/* Seek to end of sink stream */
if (gst_pad_send_event (GST_PAD_PEER (tag->sinkpad),
gst_event_new_seek (GST_FORMAT_BYTES | GST_SEEK_METHOD_END |
GST_SEEK_FLAG_FLUSH, 0))) {
} else {
g_warning ("Couldn't seek to eos on sinkpad\n");
}
}
static gboolean
caps_nego (GstFlacTag * tag)
{
/* do caps nego */
GstCaps *caps;
caps = gst_caps_new_simple ("audio/x-flac", NULL);
if (gst_pad_try_set_caps (tag->srcpad, caps) != GST_PAD_LINK_REFUSED) {
tag->only_output_tags = FALSE;
GST_LOG_OBJECT (tag, "normal operation, using audio/x-flac output");
} else {
if (gst_pad_try_set_caps (tag->srcpad,
gst_caps_new_simple ("application/x-gst-tags", NULL))
!= GST_PAD_LINK_REFUSED) {
tag->only_output_tags = TRUE;
GST_LOG_OBJECT (tag, "fast operation, just outputting tags");
printf ("output tags only\n");
} else {
return FALSE;
}
}
return TRUE;
} }
static void static void
@ -234,86 +136,96 @@ gst_flac_tag_class_init (GstFlacTagClass * klass)
parent_class = g_type_class_peek_parent (klass); parent_class = g_type_class_peek_parent (klass);
gobject_class->dispose = gst_flac_tag_dispose;
gstelement_class->change_state = gst_flac_tag_change_state; gstelement_class->change_state = gst_flac_tag_change_state;
} }
static void
gst_flac_tag_dispose (GObject * object)
{
GstFlacTag *tag = GST_FLAC_TAG (object);
if (tag->adapter) {
gst_object_unref (tag->adapter);
tag->adapter = NULL;
}
if (tag->vorbiscomment) {
gst_buffer_unref (tag->vorbiscomment);
tag->vorbiscomment = NULL;
}
if (tag->tags) {
gst_tag_list_free (tag->tags);
tag->tags = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void static void
gst_flac_tag_init (GstFlacTag * tag) gst_flac_tag_init (GstFlacTag * tag, GstFlacTagClass * klass)
{ {
/* create the sink and src pads */ /* create the sink and src pads */
tag->sinkpad = tag->sinkpad =
gst_pad_new_from_static_template (&flac_tag_sink_template, "sink"); gst_pad_new_from_static_template (&flac_tag_sink_template, "sink");
gst_element_add_pad (GST_ELEMENT (tag), tag->sinkpad);
gst_pad_set_chain_function (tag->sinkpad, gst_pad_set_chain_function (tag->sinkpad,
GST_DEBUG_FUNCPTR (gst_flac_tag_chain)); GST_DEBUG_FUNCPTR (gst_flac_tag_chain));
gst_pad_set_setcaps_function (tag->sinkpad,
GST_DEBUG_FUNCPTR (gst_flac_tag_sink_setcaps));
gst_element_add_pad (GST_ELEMENT (tag), tag->sinkpad);
tag->srcpad = tag->srcpad =
gst_pad_new_from_static_template (&flac_tag_src_template, "src"); gst_pad_new_from_static_template (&flac_tag_src_template, "src");
gst_element_add_pad (GST_ELEMENT (tag), tag->srcpad); gst_element_add_pad (GST_ELEMENT (tag), tag->srcpad);
tag->buffer = NULL; tag->adapter = gst_adapter_new ();
}
static gboolean
gst_flac_tag_sink_setcaps (GstPad * pad, GstCaps * caps)
{
GstFlacTag *tag = GST_FLAC_TAG (GST_PAD_PARENT (pad));
return gst_pad_set_caps (tag->srcpad, caps);
} }
#define FLAC_MAGIC "fLaC" #define FLAC_MAGIC "fLaC"
#define FLAC_MAGIC_SIZE (sizeof (FLAC_MAGIC) - 1) #define FLAC_MAGIC_SIZE (sizeof (FLAC_MAGIC) - 1)
static void static GstFlowReturn
gst_flac_tag_chain (GstPad * pad, GstData * data) gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer)
{ {
GstBuffer *buffer;
GstFlacTag *tag; GstFlacTag *tag;
GstFlowReturn ret;
if (GST_IS_EVENT (data)) { ret = GST_FLOW_OK;
g_print ("Unhandled event\n");
return;
}
buffer = GST_BUFFER (data);
tag = GST_FLAC_TAG (gst_pad_get_parent (pad)); tag = GST_FLAC_TAG (gst_pad_get_parent (pad));
if (tag->buffer) { gst_adapter_push (tag->adapter, buffer);
GstBuffer *merge;
merge = gst_buffer_merge (tag->buffer, buffer);
gst_buffer_unref (buffer);
gst_buffer_unref (tag->buffer);
tag->buffer = merge;
} else {
tag->buffer = buffer;
}
/* Initial state, we don't even know if we are dealing with a flac file */ /* Initial state, we don't even know if we are dealing with a flac file */
if (tag->state == GST_FLAC_TAG_STATE_INIT) { if (tag->state == GST_FLAC_TAG_STATE_INIT) {
if (!caps_nego (tag)) { GstBuffer *id_buffer;
goto cleanup;
}
if (GST_BUFFER_SIZE (tag->buffer) < sizeof (FLAC_MAGIC)) { if (gst_adapter_available (tag->adapter) < sizeof (FLAC_MAGIC))
goto cleanup; goto cleanup;
}
if (strncmp (GST_BUFFER_DATA (tag->buffer), FLAC_MAGIC, id_buffer = gst_adapter_take_buffer (tag->adapter, FLAC_MAGIC_SIZE);
FLAC_MAGIC_SIZE) == 0) { GST_DEBUG_OBJECT (tag, "looking for " FLAC_MAGIC " identifier");
GstBuffer *sub; if (memcmp (GST_BUFFER_DATA (id_buffer), FLAC_MAGIC, FLAC_MAGIC_SIZE) == 0) {
GST_DEBUG_OBJECT (tag, "pushing " FLAC_MAGIC " identifier buffer");
gst_buffer_set_caps (id_buffer, GST_PAD_CAPS (tag->srcpad));
ret = gst_pad_push (tag->srcpad, id_buffer);
if (ret != GST_FLOW_OK)
goto cleanup;
tag->state = GST_FLAC_TAG_STATE_METADATA_BLOCKS; tag->state = GST_FLAC_TAG_STATE_METADATA_BLOCKS;
sub = gst_buffer_create_sub (tag->buffer, 0, FLAC_MAGIC_SIZE);
gst_pad_push (tag->srcpad, GST_DATA (sub));
sub =
gst_buffer_create_sub (tag->buffer, FLAC_MAGIC_SIZE,
GST_BUFFER_SIZE (tag->buffer) - FLAC_MAGIC_SIZE);
gst_buffer_unref (tag->buffer);
/* We do a copy because we need a writable buffer, and _create_sub
* sets the buffer it uses to read-only
*/
tag->buffer = gst_buffer_copy (sub);
gst_buffer_unref (sub);
} else { } else {
/* FIXME: does that work well with FLAC files containing ID3v2 tags ? */ /* FIXME: does that work well with FLAC files containing ID3v2 tags ? */
gst_buffer_unref (id_buffer);
GST_ELEMENT_ERROR (tag, STREAM, WRONG_TYPE, (NULL), (NULL)); GST_ELEMENT_ERROR (tag, STREAM, WRONG_TYPE, (NULL), (NULL));
ret = GST_FLOW_ERROR;
} }
} }
@ -325,8 +237,9 @@ gst_flac_tag_chain (GstPad * pad, GstData * data)
guint size; guint size;
guint type; guint type;
gboolean is_last; gboolean is_last;
const guint8 *block_header;
g_assert (tag->metadata_bytes_remaining == 0); g_assert (tag->metadata_block_size == 0);
g_assert (tag->metadata_last_block == FALSE); g_assert (tag->metadata_last_block == FALSE);
/* The header of a flac metadata block is 4 bytes long: /* The header of a flac metadata block is 4 bytes long:
@ -334,26 +247,25 @@ gst_flac_tag_chain (GstPad * pad, GstData * data)
* 7 next bits: 4 if vorbis comment block * 7 next bits: 4 if vorbis comment block
* 24 next bits: size of the metadata to follow (big endian) * 24 next bits: size of the metadata to follow (big endian)
*/ */
if (GST_BUFFER_SIZE (tag->buffer) < 4) { if (gst_adapter_available (tag->adapter) < 4)
goto cleanup; goto cleanup;
}
is_last = (((GST_BUFFER_DATA (tag->buffer)[0]) & 0x80) == 0x80);
/* If we have metadata set on the element, the last metadata block
* will be the vorbis comment block which we will build ourselves
*/
if (is_last) {
(GST_BUFFER_DATA (tag->buffer)[0]) &= (~0x80);
}
type = (GST_BUFFER_DATA (tag->buffer)[0]) & 0x7F; block_header = gst_adapter_peek (tag->adapter, 4);
size = ((GST_BUFFER_DATA (tag->buffer)[1]) << 16)
| ((GST_BUFFER_DATA (tag->buffer)[2]) << 8) is_last = ((block_header[0] & 0x80) == 0x80);
| (GST_BUFFER_DATA (tag->buffer)[3]); type = block_header[0] & 0x7F;
size = (block_header[1] << 16)
| (block_header[2] << 8)
| block_header[3];
/* The 4 bytes long header isn't included in the metadata size */ /* The 4 bytes long header isn't included in the metadata size */
tag->metadata_bytes_remaining = size + 4; tag->metadata_block_size = size + 4;
tag->metadata_last_block = is_last; tag->metadata_last_block = is_last;
GST_DEBUG_OBJECT (tag,
"got metadata block: %d bytes, type %d, is vorbiscomment: %d, is last: %d",
size, type, (type == 0x04), is_last);
/* Metadata blocks of type 4 are vorbis comment blocks */ /* Metadata blocks of type 4 are vorbis comment blocks */
if (type == 0x04) { if (type == 0x04) {
tag->state = GST_FLAC_TAG_STATE_VC_METADATA_BLOCK; tag->state = GST_FLAC_TAG_STATE_VC_METADATA_BLOCK;
@ -366,56 +278,29 @@ gst_flac_tag_chain (GstPad * pad, GstData * data)
/* Reads a metadata block */ /* Reads a metadata block */
if ((tag->state == GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK) || if ((tag->state == GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK) ||
(tag->state == GST_FLAC_TAG_STATE_VC_METADATA_BLOCK)) { (tag->state == GST_FLAC_TAG_STATE_VC_METADATA_BLOCK)) {
GstBuffer *sub; GstBuffer *metadata_buffer;
guint bytes_to_push;
g_assert (tag->metadata_bytes_remaining != 0); if (gst_adapter_available (tag->adapter) < tag->metadata_block_size)
goto cleanup;
bytes_to_push = min (tag->metadata_bytes_remaining, metadata_buffer = gst_adapter_take_buffer (tag->adapter,
GST_BUFFER_SIZE (tag->buffer)); tag->metadata_block_size);
/* clear the is-last flag, as the last metadata block will
sub = gst_buffer_create_sub (tag->buffer, 0, bytes_to_push); * be the vorbis comment block which we will build ourselves.
*/
GST_BUFFER_DATA (metadata_buffer)[0] &= (~0x80);
if (tag->state == GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK) { if (tag->state == GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK) {
gst_pad_push (tag->srcpad, GST_DATA (sub)); GST_DEBUG_OBJECT (tag, "pushing metadata block buffer");
gst_buffer_set_caps (metadata_buffer, GST_PAD_CAPS (tag->srcpad));
ret = gst_pad_push (tag->srcpad, metadata_buffer);
if (ret != GST_FLOW_OK)
goto cleanup;
} else { } else {
if (tag->vorbiscomment == NULL) { tag->vorbiscomment = metadata_buffer;
tag->vorbiscomment = sub;
} else {
GstBuffer *merge;
merge = gst_buffer_merge (tag->vorbiscomment, sub);
gst_buffer_unref (tag->vorbiscomment);
gst_buffer_unref (sub);
tag->vorbiscomment = merge;
}
}
tag->metadata_bytes_remaining -= (bytes_to_push);
if (GST_BUFFER_SIZE (tag->buffer) > bytes_to_push) {
GstBuffer *sub;
sub = gst_buffer_create_sub (tag->buffer, bytes_to_push,
GST_BUFFER_SIZE (tag->buffer) - bytes_to_push);
gst_buffer_unref (tag->buffer);
/* We make a copy because we need a writable buffer, and _create_sub
* sets the buffer it uses to read-only
*/
tag->buffer = gst_buffer_copy (sub);
gst_buffer_unref (sub);
tag->state = GST_FLAC_TAG_STATE_METADATA_NEXT_BLOCK;
} else if (tag->metadata_bytes_remaining == 0) {
gst_buffer_unref (tag->buffer);
tag->buffer = NULL;
tag->state = GST_FLAC_TAG_STATE_METADATA_NEXT_BLOCK;
tag->buffer = NULL;
} else {
tag->state = GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK;
tag->buffer = NULL;
} }
tag->metadata_block_size = 0;
tag->state = GST_FLAC_TAG_STATE_METADATA_NEXT_BLOCK;
} }
/* This state is mainly used to be able to stop as soon as we read /* This state is mainly used to be able to stop as soon as we read
@ -428,36 +313,25 @@ gst_flac_tag_chain (GstPad * pad, GstData * data)
*/ */
if (tag->vorbiscomment != NULL) { if (tag->vorbiscomment != NULL) {
/* We found some tags, try to parse them and notify the other elements /* We found some tags, try to parse them and notify the other elements
* that we encoutered some tags * that we encountered some tags
*/ */
GST_DEBUG_OBJECT (tag, "emitting vorbiscomment tags");
tag->tags = gst_tag_list_from_vorbiscomment_buffer (tag->vorbiscomment, tag->tags = gst_tag_list_from_vorbiscomment_buffer (tag->vorbiscomment,
GST_BUFFER_DATA (tag->vorbiscomment), 4, NULL); GST_BUFFER_DATA (tag->vorbiscomment), 4, NULL);
if (tag->tags != NULL) { if (tag->tags != NULL) {
gst_element_found_tags (GST_ELEMENT (tag), tag->tags); gst_element_found_tags (GST_ELEMENT (tag),
gst_tag_list_copy (tag->tags));
} }
gst_buffer_unref (tag->vorbiscomment); gst_buffer_unref (tag->vorbiscomment);
tag->vorbiscomment = NULL; tag->vorbiscomment = NULL;
if (tag->only_output_tags) {
send_eos (tag);
goto cleanup;
}
} }
/* Skip to next state */ /* Skip to next state */
if (tag->metadata_last_block == FALSE) { if (tag->metadata_last_block == FALSE) {
tag->state = GST_FLAC_TAG_STATE_METADATA_BLOCKS; tag->state = GST_FLAC_TAG_STATE_METADATA_BLOCKS;
} else { } else {
if (tag->only_output_tags) { tag->state = GST_FLAC_TAG_STATE_ADD_VORBIS_COMMENT;
/* If we finished parsing the metadata blocks, we will never find any
* metadata, so just stop now
*/
send_eos (tag);
goto cleanup;
} else {
tag->state = GST_FLAC_TAG_STATE_ADD_VORBIS_COMMENT;
}
} }
} }
@ -471,18 +345,21 @@ gst_flac_tag_chain (GstPad * pad, GstData * data)
const GstTagList *user_tags; const GstTagList *user_tags;
GstTagList *merged_tags; GstTagList *merged_tags;
g_assert (tag->only_output_tags == FALSE); /* merge the tag lists */
user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (tag)); user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (tag));
merged_tags = gst_tag_list_merge (tag->tags, user_tags, if (user_tags != NULL) {
gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (tag))); merged_tags = gst_tag_list_merge (user_tags, tag->tags,
gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (tag)));
} else {
merged_tags = gst_tag_list_copy (tag->tags);
}
if (merged_tags == NULL) { if (merged_tags == NULL) {
/* If we get a NULL list of tags, we must generate a padding block /* If we get a NULL list of tags, we must generate a padding block
* which is marked as the last metadata block, otherwise we'll * which is marked as the last metadata block, otherwise we'll
* end up with a corrupted flac file. * end up with a corrupted flac file.
*/ */
g_warning ("No tags found\n"); GST_WARNING_OBJECT (tag, "No tags found");
buffer = gst_buffer_new_and_alloc (12); buffer = gst_buffer_new_and_alloc (12);
if (buffer == NULL) { if (buffer == NULL) {
GST_ELEMENT_ERROR (tag, CORE, TOO_LAZY, (NULL), GST_ELEMENT_ERROR (tag, CORE, TOO_LAZY, (NULL),
@ -501,6 +378,7 @@ gst_flac_tag_chain (GstPad * pad, GstData * data)
*/ */
buffer = gst_tag_list_to_vorbiscomment_buffer (merged_tags, header, buffer = gst_tag_list_to_vorbiscomment_buffer (merged_tags, header,
sizeof (header), NULL); sizeof (header), NULL);
GST_DEBUG_OBJECT (tag, "Writing tags %" GST_PTR_FORMAT, merged_tags);
gst_tag_list_free (merged_tags); gst_tag_list_free (merged_tags);
if (buffer == NULL) { if (buffer == NULL) {
GST_ELEMENT_ERROR (tag, CORE, TAG, (NULL), GST_ELEMENT_ERROR (tag, CORE, TAG, (NULL),
@ -539,18 +417,30 @@ gst_flac_tag_chain (GstPad * pad, GstData * data)
GST_BUFFER_DATA (buffer)[1] = ((size & 0xFF0000) >> 16); GST_BUFFER_DATA (buffer)[1] = ((size & 0xFF0000) >> 16);
GST_BUFFER_DATA (buffer)[2] = ((size & 0x00FF00) >> 8); GST_BUFFER_DATA (buffer)[2] = ((size & 0x00FF00) >> 8);
GST_BUFFER_DATA (buffer)[3] = (size & 0x0000FF); GST_BUFFER_DATA (buffer)[3] = (size & 0x0000FF);
gst_pad_push (tag->srcpad, GST_DATA (buffer)); GST_DEBUG_OBJECT (tag, "pushing %d byte vorbiscomment buffer",
GST_BUFFER_SIZE (buffer));
gst_buffer_set_caps (buffer, GST_PAD_CAPS (tag->srcpad));
ret = gst_pad_push (tag->srcpad, buffer);
if (ret != GST_FLOW_OK) {
goto cleanup;
}
tag->state = GST_FLAC_TAG_STATE_AUDIO_DATA; tag->state = GST_FLAC_TAG_STATE_AUDIO_DATA;
} }
/* The metadata blocks have been read, now we are reading audio data */ /* The metadata blocks have been read, now we are reading audio data */
if (tag->state == GST_FLAC_TAG_STATE_AUDIO_DATA) { if (tag->state == GST_FLAC_TAG_STATE_AUDIO_DATA) {
gst_pad_push (tag->srcpad, GST_DATA (tag->buffer)); GstBuffer *buffer;
tag->buffer = NULL; buffer =
gst_adapter_take_buffer (tag->adapter,
gst_adapter_available (tag->adapter));
gst_buffer_set_caps (buffer, GST_PAD_CAPS (tag->srcpad));
ret = gst_pad_push (tag->srcpad, buffer);
} }
cleanup: cleanup:
gst_object_unref (tag); gst_object_unref (tag);
return ret;
} }
@ -572,17 +462,17 @@ gst_flac_tag_change_state (GstElement * element, GstStateChange transition)
case GST_STATE_CHANGE_PLAYING_TO_PAUSED: case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break; break;
case GST_STATE_CHANGE_PAUSED_TO_READY: case GST_STATE_CHANGE_PAUSED_TO_READY:
if (tag->buffer) { gst_adapter_clear (tag->adapter);
gst_buffer_unref (tag->buffer);
tag->buffer = NULL;
}
if (tag->vorbiscomment) { if (tag->vorbiscomment) {
gst_buffer_unref (tag->vorbiscomment); gst_buffer_unref (tag->vorbiscomment);
tag->vorbiscomment = NULL; tag->vorbiscomment = NULL;
} }
if (tag->tags) { if (tag->tags) {
gst_tag_list_free (tag->tags); gst_tag_list_free (tag->tags);
tag->tags = NULL;
} }
tag->metadata_block_size = 0;
tag->metadata_last_block = FALSE;
tag->state = GST_FLAC_TAG_STATE_INIT; tag->state = GST_FLAC_TAG_STATE_INIT;
break; break;
case GST_STATE_CHANGE_READY_TO_NULL: case GST_STATE_CHANGE_READY_TO_NULL:

View file

@ -1,6 +1,78 @@
/* GStreamer
* Copyright (C) 2003 Christophe Fergeau <teuf@gnome.org>
* Copyright (C) 2008 Jonathan Matthew <jonathan@d14n.org>
* Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* gstflactag.c: plug-in for reading/modifying vorbis comments in flac files
*
* 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_FLAC_TAG_H #ifndef GST_FLAC_TAG_H
#define GST_FLAC_TAG_H #define GST_FLAC_TAG_H
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
#define GST_TYPE_FLAC_TAG (gst_flac_tag_get_type())
#define GST_FLAC_TAG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FLAC_TAG, GstFlacTag))
#define GST_FLAC_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FLAC_TAG, GstFlacTag))
#define GST_IS_FLAC_TAG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FLAC_TAG))
#define GST_IS_FLAC_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FLAC_TAG))
typedef struct _GstFlacTag GstFlacTag;
typedef struct _GstFlacTagClass GstFlacTagClass;
typedef enum
{
GST_FLAC_TAG_STATE_INIT,
GST_FLAC_TAG_STATE_METADATA_BLOCKS,
GST_FLAC_TAG_STATE_METADATA_NEXT_BLOCK,
GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK,
GST_FLAC_TAG_STATE_VC_METADATA_BLOCK,
GST_FLAC_TAG_STATE_ADD_VORBIS_COMMENT,
GST_FLAC_TAG_STATE_AUDIO_DATA
}
GstFlacTagState;
struct _GstFlacTag
{
GstElement element;
/* < private > */
/* pads */
GstPad *sinkpad;
GstPad *srcpad;
GstFlacTagState state;
GstAdapter *adapter;
GstBuffer *vorbiscomment;
GstTagList *tags;
guint metadata_block_size;
gboolean metadata_last_block;
};
struct _GstFlacTagClass
{
GstElementClass parent_class;
};
GType gst_flac_tag_get_type (void); GType gst_flac_tag_get_type (void);
#endif /* GST_FLAC_TAG_H */ #endif /* GST_FLAC_TAG_H */