summaryrefslogtreecommitdiffstats
path: root/ext/flac
diff options
context:
space:
mode:
authorJonathan Matthew <notverysmart@gmail.com>2008-08-06 15:34:55 +0000
committerSebastian Dröge <slomo@circular-chaos.org>2008-08-06 15:34:55 +0000
commit8ced1b35ff4080df103333b58caa27ae86c78f2a (patch)
treeef3db0a72db35975417de4b94a7ec0f8191c9cef /ext/flac
parentdfd580b2075a15b0a7994d31287d9d8bfc13a954 (diff)
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.
Diffstat (limited to 'ext/flac')
-rw-r--r--ext/flac/Makefile.am4
-rw-r--r--ext/flac/gstflac.c4
-rw-r--r--ext/flac/gstflacdec.c12
-rw-r--r--ext/flac/gstflacdec.h2
-rw-r--r--ext/flac/gstflacenc.c11
-rw-r--r--ext/flac/gstflacenc.h2
-rw-r--r--ext/flac/gstflactag.c460
-rw-r--r--ext/flac/gstflactag.h72
8 files changed, 261 insertions, 306 deletions
diff --git a/ext/flac/Makefile.am b/ext/flac/Makefile.am
index 2723680e..0e7d41a2 100644
--- a/ext/flac/Makefile.am
+++ b/ext/flac/Makefile.am
@@ -1,6 +1,6 @@
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_LIBADD = \
$(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) \
@@ -8,4 +8,4 @@ libgstflac_la_LIBADD = \
$(GST_BASE_LIBS) $(GST_LIBS) $(FLAC_LIBS)
libgstflac_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-noinst_HEADERS = gstflacenc.h gstflacdec.h
+noinst_HEADERS = gstflacenc.h gstflacdec.h gstflactag.h
diff --git a/ext/flac/gstflac.c b/ext/flac/gstflac.c
index d07ec479..7d76a41c 100644
--- a/ext/flac/gstflac.c
+++ b/ext/flac/gstflac.c
@@ -23,7 +23,7 @@
#include "gstflacenc.h"
#include "gstflacdec.h"
-/* #include "gstflactag.h" */
+#include "gstflactag.h"
#include <gst/tag/tag.h>
#include <gst/gst-i18n-plugin.h>
@@ -43,11 +43,9 @@ plugin_init (GstPlugin * plugin)
if (!gst_element_register (plugin, "flacdec", GST_RANK_PRIMARY,
GST_TYPE_FLAC_DEC))
return FALSE;
-#if 0
if (!gst_element_register (plugin, "flactag", GST_RANK_PRIMARY,
gst_flac_tag_get_type ()))
return FALSE;
-#endif
gst_tag_register_musicbrainz_tags ();
diff --git a/ext/flac/gstflacdec.c b/ext/flac/gstflacdec.c
index 7b8e381f..66d6c14c 100644
--- a/ext/flac/gstflacdec.c
+++ b/ext/flac/gstflacdec.c
@@ -105,15 +105,7 @@ GST_DEBUG_CATEGORY_STATIC (flacdec_debug);
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_loop (GstPad * pad);
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_element_class_add_pad_template (element_class, sink_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");
}
diff --git a/ext/flac/gstflacdec.h b/ext/flac/gstflacdec.h
index b68986d2..100c4e0b 100644
--- a/ext/flac/gstflacdec.h
+++ b/ext/flac/gstflacdec.h
@@ -47,6 +47,8 @@ typedef struct _GstFlacDecClass GstFlacDecClass;
struct _GstFlacDec {
GstElement element;
+ /* < private > */
+
#if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT < 8
FLAC__SeekableStreamDecoder *seekable_decoder; /* for pull-based operation */
#else
diff --git a/ext/flac/gstflacenc.c b/ext/flac/gstflacenc.c
index 1a2a34b6..1e29343c 100644
--- a/ext/flac/gstflacenc.c
+++ b/ext/flac/gstflacenc.c
@@ -77,12 +77,6 @@ static const GstAudioChannelPosition channel_positions[8][8] = {
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 \
"audio/x-raw-int, " \
"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_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,
"Flac encoding element");
diff --git a/ext/flac/gstflacenc.h b/ext/flac/gstflacenc.h
index 016a56b6..1c6a6c66 100644
--- a/ext/flac/gstflacenc.h
+++ b/ext/flac/gstflacenc.h
@@ -45,6 +45,8 @@ typedef struct _GstFlacEncClass GstFlacEncClass;
struct _GstFlacEnc {
GstElement element;
+ /* < private > */
+
GstPad *sinkpad;
GstPad *srcpad;
diff --git a/ext/flac/gstflactag.c b/ext/flac/gstflactag.c
index 247e1dea..d7ca61cc 100644
--- a/ext/flac/gstflactag.c
+++ b/ext/flac/gstflactag.c
@@ -1,6 +1,7 @@
-
/* 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
*
@@ -20,78 +21,58 @@
* 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
#include "config.h"
#endif
+
+#include <gst/gst.h>
#include <gst/gsttagsetter.h>
+#include <gst/base/gstadapter.h>
#include <gst/tag/tag.h>
#include <string.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))
+#include "gstflactag.h"
-typedef struct _GstFlacTag GstFlacTag;
-typedef struct _GstFlacTagClass GstFlacTagClass;
-
-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;
-};
+GST_DEBUG_CATEGORY_STATIC (flactag_debug);
+#define GST_CAT_DEFAULT flactag_debug
/* elementfactory information */
-static const GstElementDetails gst_flac_tag_details =
-GST_ELEMENT_DETAILS ("FLAC tagger",
- "Tag",
- "Rewrite tags in a FLAC file",
- "Christope Fergeau <teuf@gnome.org>");
+static GstStaticPadTemplate flac_tag_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ 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 */
enum
@@ -106,121 +87,42 @@ enum
/* FILL ME */
};
-static GstStaticPadTemplate flac_tag_src_template =
- 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 =
-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_dispose (GObject * object);
-static void gst_flac_tag_chain (GstPad * pad, GstData * data);
+static GstFlowReturn gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer);
static GstStateChangeReturn gst_flac_tag_change_state (GstElement * element,
GstStateChange transition);
+static gboolean gst_flac_tag_sink_setcaps (GstPad * pad, GstCaps * caps);
-static GstElementClass *parent_class = NULL;
-
-/* static guint gst_flac_tag_signals[LAST_SIGNAL] = { 0 }; */
-
-GType
-gst_flac_tag_get_type (void)
+static void
+gst_flac_tag_setup_interfaces (GType flac_tag_type)
{
- static GType flac_tag_type = 0;
-
- if (!flac_tag_type) {
- static const GTypeInfo flac_tag_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);
+ static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
- }
- return flac_tag_type;
+ g_type_add_interface_static (flac_tag_type, GST_TYPE_TAG_SETTER,
+ &tag_setter_info);
}
+GST_BOILERPLATE_FULL (GstFlacTag, gst_flac_tag, GstElement, GST_TYPE_ELEMENT,
+ gst_flac_tag_setup_interfaces);
static void
gst_flac_tag_base_init (gpointer 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_static_pad_template_get (&flac_tag_sink_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&flac_tag_src_template));
-}
-
-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;
+ GST_DEBUG_CATEGORY_INIT (flactag_debug, "flactag", 0, "flac tag rewriter");
}
static void
@@ -234,86 +136,96 @@ gst_flac_tag_class_init (GstFlacTagClass * 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;
}
+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
-gst_flac_tag_init (GstFlacTag * tag)
+gst_flac_tag_init (GstFlacTag * tag, GstFlacTagClass * klass)
{
/* create the sink and src pads */
tag->sinkpad =
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_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 =
gst_pad_new_from_static_template (&flac_tag_src_template, "src");
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_SIZE (sizeof (FLAC_MAGIC) - 1)
-static void
-gst_flac_tag_chain (GstPad * pad, GstData * data)
+static GstFlowReturn
+gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer)
{
- GstBuffer *buffer;
GstFlacTag *tag;
+ GstFlowReturn ret;
- if (GST_IS_EVENT (data)) {
- g_print ("Unhandled event\n");
- return;
- }
-
- buffer = GST_BUFFER (data);
+ ret = GST_FLOW_OK;
tag = GST_FLAC_TAG (gst_pad_get_parent (pad));
- if (tag->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;
- }
-
+ gst_adapter_push (tag->adapter, buffer);
/* Initial state, we don't even know if we are dealing with a flac file */
if (tag->state == GST_FLAC_TAG_STATE_INIT) {
- if (!caps_nego (tag)) {
- goto cleanup;
- }
+ GstBuffer *id_buffer;
- if (GST_BUFFER_SIZE (tag->buffer) < sizeof (FLAC_MAGIC)) {
+ if (gst_adapter_available (tag->adapter) < sizeof (FLAC_MAGIC))
goto cleanup;
- }
- if (strncmp (GST_BUFFER_DATA (tag->buffer), FLAC_MAGIC,
- FLAC_MAGIC_SIZE) == 0) {
- GstBuffer *sub;
+ id_buffer = gst_adapter_take_buffer (tag->adapter, FLAC_MAGIC_SIZE);
+ GST_DEBUG_OBJECT (tag, "looking for " FLAC_MAGIC " identifier");
+ 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;
- 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 {
/* 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));
+ ret = GST_FLOW_ERROR;
}
}
@@ -325,8 +237,9 @@ gst_flac_tag_chain (GstPad * pad, GstData * data)
guint size;
guint type;
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);
/* 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
* 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;
- }
- 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;
- size = ((GST_BUFFER_DATA (tag->buffer)[1]) << 16)
- | ((GST_BUFFER_DATA (tag->buffer)[2]) << 8)
- | (GST_BUFFER_DATA (tag->buffer)[3]);
+ block_header = gst_adapter_peek (tag->adapter, 4);
+
+ is_last = ((block_header[0] & 0x80) == 0x80);
+ 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 */
- tag->metadata_bytes_remaining = size + 4;
+ tag->metadata_block_size = size + 4;
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 */
if (type == 0x04) {
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 */
if ((tag->state == GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK) ||
(tag->state == GST_FLAC_TAG_STATE_VC_METADATA_BLOCK)) {
- GstBuffer *sub;
- guint bytes_to_push;
-
- g_assert (tag->metadata_bytes_remaining != 0);
+ GstBuffer *metadata_buffer;
- bytes_to_push = min (tag->metadata_bytes_remaining,
- GST_BUFFER_SIZE (tag->buffer));
+ if (gst_adapter_available (tag->adapter) < tag->metadata_block_size)
+ goto cleanup;
- sub = gst_buffer_create_sub (tag->buffer, 0, bytes_to_push);
+ metadata_buffer = gst_adapter_take_buffer (tag->adapter,
+ tag->metadata_block_size);
+ /* clear the is-last flag, as the last metadata block will
+ * 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) {
- gst_pad_push (tag->srcpad, GST_DATA (sub));
- } else {
- if (tag->vorbiscomment == NULL) {
- 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;
+ 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 {
- tag->state = GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK;
- tag->buffer = NULL;
+ tag->vorbiscomment = metadata_buffer;
}
+ 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
@@ -428,36 +313,25 @@ gst_flac_tag_chain (GstPad * pad, GstData * data)
*/
if (tag->vorbiscomment != NULL) {
/* 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,
GST_BUFFER_DATA (tag->vorbiscomment), 4, 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);
tag->vorbiscomment = NULL;
-
- if (tag->only_output_tags) {
- send_eos (tag);
- goto cleanup;
- }
}
/* Skip to next state */
if (tag->metadata_last_block == FALSE) {
tag->state = GST_FLAC_TAG_STATE_METADATA_BLOCKS;
} else {
- if (tag->only_output_tags) {
- /* 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;
- }
+ 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;
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));
- merged_tags = gst_tag_list_merge (tag->tags, user_tags,
- gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (tag)));
+ if (user_tags != NULL) {
+ 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 we get a NULL list of tags, we must generate a padding block
* which is marked as the last metadata block, otherwise we'll
* 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);
if (buffer == 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,
sizeof (header), NULL);
+ GST_DEBUG_OBJECT (tag, "Writing tags %" GST_PTR_FORMAT, merged_tags);
gst_tag_list_free (merged_tags);
if (buffer == 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)[2] = ((size & 0x00FF00) >> 8);
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;
}
/* The metadata blocks have been read, now we are reading audio data */
if (tag->state == GST_FLAC_TAG_STATE_AUDIO_DATA) {
- gst_pad_push (tag->srcpad, GST_DATA (tag->buffer));
- tag->buffer = NULL;
+ GstBuffer *buffer;
+ 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:
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:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
- if (tag->buffer) {
- gst_buffer_unref (tag->buffer);
- tag->buffer = NULL;
- }
+ gst_adapter_clear (tag->adapter);
if (tag->vorbiscomment) {
gst_buffer_unref (tag->vorbiscomment);
tag->vorbiscomment = NULL;
}
if (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;
break;
case GST_STATE_CHANGE_READY_TO_NULL:
diff --git a/ext/flac/gstflactag.h b/ext/flac/gstflactag.h
index 5107d1c3..a6f90f5e 100644
--- a/ext/flac/gstflactag.h
+++ b/ext/flac/gstflactag.h
@@ -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
#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);
#endif /* GST_FLAC_TAG_H */