diff options
author | Sebastian Dröge <mail@slomosnail.de> | 2006-05-30 14:35:18 +0000 |
---|---|---|
committer | Tim-Philipp Müller <tim@centricular.net> | 2006-05-30 14:35:18 +0000 |
commit | c121cab661eb9f123cd9deab32609570226a4e0d (patch) | |
tree | 6e81fb6d8e9443d3f4a7636b34aa64d3c39904af /ext/taglib | |
parent | 8f1c9746eae406efa1619a890bfc35d96fb485e4 (diff) |
Add apev2mux element (#343122).
Original commit message from CVS:
Patch by: Sebastian Dröge <mail at slomosnail de >
* docs/plugins/gst-plugins-good-plugins-docs.sgml:
* docs/plugins/gst-plugins-good-plugins-sections.txt:
* ext/taglib/Makefile.am:
* ext/taglib/gstapev2mux.cc:
* ext/taglib/gstapev2mux.h:
* ext/taglib/gstid3v2mux.cc:
* ext/taglib/gsttaglibmux.c: (plugin_init):
* ext/taglib/gsttaglibmux.h:
Add apev2mux element (#343122).
* tests/check/Makefile.am:
* tests/check/elements/apev2mux.c:
(test_taglib_apev2mux_create_tags),
(test_taglib_apev2mux_check_tags), (fill_mp3_buffer), (got_buffer),
(demux_pad_added), (test_taglib_apev2mux_check_output_buffer),
(test_taglib_apev2mux_with_tags), (GST_START_TEST),
(apev2mux_suite), (main):
Add unit test for apev2mux element.
Diffstat (limited to 'ext/taglib')
-rw-r--r-- | ext/taglib/Makefile.am | 4 | ||||
-rw-r--r-- | ext/taglib/gstapev2mux.cc | 382 | ||||
-rw-r--r-- | ext/taglib/gstapev2mux.h | 55 | ||||
-rw-r--r-- | ext/taglib/gstid3v2mux.cc | 10 | ||||
-rw-r--r-- | ext/taglib/gsttaglibmux.c | 14 | ||||
-rw-r--r-- | ext/taglib/gsttaglibmux.h | 2 |
6 files changed, 457 insertions, 10 deletions
diff --git a/ext/taglib/Makefile.am b/ext/taglib/Makefile.am index e1ffd5cd..03774428 100644 --- a/ext/taglib/Makefile.am +++ b/ext/taglib/Makefile.am @@ -1,6 +1,6 @@ plugin_LTLIBRARIES = libgsttaglib.la -libgsttaglib_la_SOURCES = gsttaglibmux.c gstid3v2mux.cc +libgsttaglib_la_SOURCES = gsttaglibmux.c gstid3v2mux.cc gstapev2mux.cc libgsttaglib_la_CFLAGS = \ $(GST_CFLAGS) \ $(GST_PLUGINS_BASE_CFLAGS) \ @@ -15,4 +15,4 @@ libgsttaglib_la_LIBADD = \ $(TAGLIB_LIBS) libgsttaglib_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -noinst_HEADERS = gsttaglibmux.h gstid3v2mux.h +noinst_HEADERS = gsttaglibmux.h gstid3v2mux.h gstapev2mux.h diff --git a/ext/taglib/gstapev2mux.cc b/ext/taglib/gstapev2mux.cc new file mode 100644 index 00000000..637286e8 --- /dev/null +++ b/ext/taglib/gstapev2mux.cc @@ -0,0 +1,382 @@ +/* GStreamer taglib-based APEv2 muxer + * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org> + * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net> + * Copyright (C) 2006 Sebastian Dröge <mail@slomosnail.de> + * + * 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. + */ + +/** + * SECTION:element-apev2mux + * @see_also: #GstTagSetter + * + * <refsect2> + * <para> + * This element adds APEv2 tags to the beginning of a stream using the taglib + * library. + * </para> + * <para> + * Applications can set the tags to write using the #GstTagSetter interface. + * Tags sent by upstream elements will be picked up automatically (and merged + * according to the merge mode set via the tag setter interface). + * </para> + * <para> + * Here is a simple pipeline that transcodes a file from Ogg/Vorbis to mp3 + * format with an APEv2 that contains the same as the the Ogg/Vorbis file: + * <programlisting> + * gst-launch -v filesrc location=foo.ogg ! decodebin ! audioconvert ! lame ! apev2mux ! filesink location=foo.mp3 + * </programlisting> + * Make sure the Ogg/Vorbis file actually has comments to preserve. + * You can verify the tags were written using: + * <programlisting> + * gst-launch -m filesrc location=foo.mp3 ! apedemux ! fakesink silent=TRUE 2> /dev/null | grep taglist + * </programlisting> + * </para> + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "gstapev2mux.h" + +#include <string.h> + +#include <apetag.h> +#include <gst/tag/tag.h> + +using namespace TagLib; + +GST_DEBUG_CATEGORY_STATIC (gst_apev2_mux_debug); +#define GST_CAT_DEFAULT gst_apev2_mux_debug + +static const GstElementDetails gst_apev2_mux_details = +GST_ELEMENT_DETAILS ("TagLib-based APEv2 Muxer", + "Formatter/Metadata", + "Adds an APEv2 header to the beginning of files using taglib", + "Sebastian Dröge <mail@slomosnail.de>"); + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-apetag")); + + +GST_BOILERPLATE (GstApev2Mux, gst_apev2_mux, GstTagLibMux, + GST_TYPE_TAG_LIB_MUX); + +static GstBuffer *gst_apev2_mux_render_tag (GstTagLibMux * mux, + GstTagList * taglist); + +static void +gst_apev2_mux_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template)); + + gst_element_class_set_details (element_class, &gst_apev2_mux_details); + + GST_DEBUG_CATEGORY_INIT (gst_apev2_mux_debug, "apev2mux", 0, + "taglib-based APEv2 tag muxer"); +} + +static void +gst_apev2_mux_class_init (GstApev2MuxClass * klass) +{ + GST_TAG_LIB_MUX_CLASS (klass)->render_tag = + GST_DEBUG_FUNCPTR (gst_apev2_mux_render_tag); +} + +static void +gst_apev2_mux_init (GstApev2Mux * apev2mux, GstApev2MuxClass * apev2mux_class) +{ + /* nothing to do */ +} + +static void +add_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data) +{ + APE::Tag * apev2tag = (APE::Tag *) user_data; + gboolean result; + + /* FIXME: if there are several values set for the same tag, this won't + * work, only the first value will be taken into account + */ + if (strcmp (tag, GST_TAG_TITLE) == 0) { + char *title; + + result = gst_tag_list_get_string_index (list, tag, 0, &title); + if (result != FALSE) { + GST_DEBUG ("Setting title to %s", title); + apev2tag->setTitle (String::String (title, String::UTF8)); + } + g_free (title); + } else if (strcmp (tag, GST_TAG_ALBUM) == 0) { + char *album; + + result = gst_tag_list_get_string_index (list, tag, 0, &album); + if (result != FALSE) { + GST_DEBUG ("Setting album to %s", album); + apev2tag->setAlbum (String::String (album, String::UTF8)); + } + g_free (album); + } else if (strcmp (tag, GST_TAG_ARTIST) == 0) { + char *artist; + + result = gst_tag_list_get_string_index (list, tag, 0, &artist); + if (result != FALSE) { + GST_DEBUG ("Setting artist to %s", artist); + apev2tag->setArtist (String::String (artist, String::UTF8)); + } + g_free (artist); + } else if (strcmp (tag, GST_TAG_GENRE) == 0) { + char *genre; + + result = gst_tag_list_get_string_index (list, tag, 0, &genre); + if (result != FALSE) { + GST_DEBUG ("Setting genre to %s", genre); + apev2tag->setGenre (String::String (genre, String::UTF8)); + } + g_free (genre); + } else if (strcmp (tag, GST_TAG_COMMENT) == 0) { + char *comment; + + result = gst_tag_list_get_string_index (list, tag, 0, &comment); + if (result != FALSE) { + GST_DEBUG ("Setting comment to %s", comment); + apev2tag->setComment (String::String (comment, String::UTF8)); + } + g_free (comment); + } else if (strcmp (tag, GST_TAG_DATE) == 0) { + GDate *date; + + result = gst_tag_list_get_date_index (list, tag, 0, &date); + if (result != FALSE) { + GDateYear year; + + year = g_date_get_year (date); + GST_DEBUG ("Setting track year to %d", year); + apev2tag->setYear (year); + g_date_free (date); + } + } else if (strcmp (tag, GST_TAG_TRACK_NUMBER) == 0) { + guint track_number; + + result = gst_tag_list_get_uint_index (list, tag, 0, &track_number); + if (result != FALSE) { + guint total_tracks; + + result = gst_tag_list_get_uint_index (list, GST_TAG_TRACK_COUNT, + 0, &total_tracks); + if (result) { + gchar *tag_str; + + tag_str = g_strdup_printf ("%d/%d", track_number, total_tracks); + GST_DEBUG ("Setting track number to %s", tag_str); + apev2tag->addValue (String::String ("TRACK", String::UTF8), + String::String (tag_str, String::UTF8), true); + g_free (tag_str); + } else { + GST_DEBUG ("Setting track number to %d", track_number); + apev2tag->setTrack (track_number); + } + } + } else if (strcmp (tag, GST_TAG_TRACK_COUNT) == 0) { + guint n; + + if (gst_tag_list_get_uint_index (list, GST_TAG_TRACK_NUMBER, 0, &n)) { + GST_DEBUG ("track-count handled with track-number, skipping"); + } else if (gst_tag_list_get_uint_index (list, GST_TAG_TRACK_COUNT, 0, &n)) { + gchar *tag_str; + + tag_str = g_strdup_printf ("0/%d", n); + GST_DEBUG ("Setting track number to %s", tag_str); + apev2tag->addValue (String::String ("TRACK", String::UTF8), + String::String (tag_str, String::UTF8), true); + g_free (tag_str); + } +#if 0 + } else if (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0) { + guint volume_number; + + result = gst_tag_list_get_uint_index (list, tag, 0, &volume_number); + + if (result != FALSE) { + guint volume_count; + gchar *tag_str; + + result = gst_tag_list_get_uint_index (list, GST_TAG_ALBUM_VOLUME_COUNT, + 0, &volume_count); + + if (result) { + tag_str = g_strdup_printf ("CD %d/%d", volume_number, volume_count); + } else { + tag_str = g_strdup_printf ("CD %d", volume_number); + } + + GST_DEBUG ("Setting album number to %s", tag_str); + + apev2tag->addValue (String::String ("MEDIA", String::UTF8), + String::String (tag_str, String::UTF8), true); + g_free (tag_str); + } + } else if (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0) { + guint n; + + if (gst_tag_list_get_uint_index (list, GST_TAG_ALBUM_VOLUME_NUMBER, 0, &n)) { + GST_DEBUG ("volume-count handled with volume-number, skipping"); + } else if (gst_tag_list_get_uint_index (list, GST_TAG_ALBUM_VOLUME_COUNT, + 0, &n)) { + gchar *tag_str; + + tag_str = g_strdup_printf ("CD 0/%u", n); + GST_DEBUG ("Setting album volume number/count to %s", tag_str); + + apev2tag->addValue (String::String ("MEDIA", String::UTF8), + String::String (tag_str, String::UTF8), true); + g_free (tag_str); + } +#endif + } else if (strcmp (tag, GST_TAG_COPYRIGHT) == 0) { + gchar *copyright; + + result = gst_tag_list_get_string_index (list, tag, 0, ©right); + + if (result != FALSE) { + GST_DEBUG ("Setting copyright to %s", copyright); + apev2tag->addValue (String::String ("COPYRIGHT", String::UTF8), + String::String (copyright, String::UTF8), true); + g_free (copyright); + } + } else if (strcmp (tag, GST_TAG_LOCATION) == 0) { + gchar *location; + + result = gst_tag_list_get_string_index (list, tag, 0, &location); + + if (result != FALSE) { + GST_DEBUG ("Setting location to %s", location); + apev2tag->addValue (String::String ("FILE", String::UTF8), + String::String (location, String::UTF8), true); + g_free (location); + } + } else if (strcmp (tag, GST_TAG_ISRC) == 0) { + gchar *isrc; + + result = gst_tag_list_get_string_index (list, tag, 0, &isrc); + + if (result != FALSE) { + GST_DEBUG ("Setting ISRC to %s", isrc); + apev2tag->addValue (String::String ("ISRC", String::UTF8), + String::String (isrc, String::UTF8), true); + g_free (isrc); + } + } else if (strcmp (tag, GST_TAG_TRACK_GAIN) == 0) { + gdouble value; + + result = gst_tag_list_get_double_index (list, tag, 0, &value); + + if (result != FALSE) { + gchar *track_gain = (gchar *) g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE); + + track_gain = g_ascii_dtostr (track_gain, G_ASCII_DTOSTR_BUF_SIZE, value); + GST_DEBUG ("Setting track gain to %s", track_gain); + apev2tag->addValue (String::String ("REPLAYGAIN_TRACK_GAIN", + String::UTF8), String::String (track_gain, String::UTF8), true); + g_free (track_gain); + } + } else if (strcmp (tag, GST_TAG_TRACK_PEAK) == 0) { + gdouble value; + + result = gst_tag_list_get_double_index (list, tag, 0, &value); + + if (result != FALSE) { + gchar *track_peak = (gchar *) g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE); + + track_peak = g_ascii_dtostr (track_peak, G_ASCII_DTOSTR_BUF_SIZE, value); + GST_DEBUG ("Setting track peak to %s", track_peak); + apev2tag->addValue (String::String ("REPLAYGAIN_TRACK_PEAK", + String::UTF8), String::String (track_peak, String::UTF8), true); + g_free (track_peak); + } + } else if (strcmp (tag, GST_TAG_ALBUM_GAIN) == 0) { + gdouble value; + + result = gst_tag_list_get_double_index (list, tag, 0, &value); + + if (result != FALSE) { + gchar *album_gain = (gchar *) g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE); + + album_gain = g_ascii_dtostr (album_gain, G_ASCII_DTOSTR_BUF_SIZE, value); + GST_DEBUG ("Setting album gain to %s", album_gain); + apev2tag->addValue (String::String ("REPLAYGAIN_ALBUM_GAIN", + String::UTF8), String::String (album_gain, String::UTF8), true); + g_free (album_gain); + } + } else if (strcmp (tag, GST_TAG_ALBUM_PEAK) == 0) { + gdouble value; + + result = gst_tag_list_get_double_index (list, tag, 0, &value); + + if (result != FALSE) { + gchar *album_peak = (gchar *) g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE); + + album_peak = g_ascii_dtostr (album_peak, G_ASCII_DTOSTR_BUF_SIZE, value); + GST_DEBUG ("Setting album peak to %s", album_peak); + apev2tag->addValue (String::String ("REPLAYGAIN_ALBUM_PEAK", + String::UTF8), String::String (album_peak, String::UTF8), true); + g_free (album_peak); + } + } else { + GST_WARNING ("Unsupported tag: %s", tag); + } +} + +static GstBuffer * +gst_apev2_mux_render_tag (GstTagLibMux * mux, GstTagList * taglist) +{ + APE::Tag apev2tag; + ByteVector rendered_tag; + GstBuffer *buf; + guint tag_size; + + /* Render the tag */ + gst_tag_list_foreach (taglist, add_one_tag, &apev2tag); + + rendered_tag = apev2tag.render (); + tag_size = rendered_tag.size (); + + GST_LOG_OBJECT (mux, "tag size = %d bytes", tag_size); + + /* Create buffer with tag */ + buf = gst_buffer_new_and_alloc (tag_size); + memcpy (GST_BUFFER_DATA (buf), rendered_tag.data (), tag_size); + gst_buffer_set_caps (buf, GST_PAD_CAPS (mux->srcpad)); + + return buf; +} + +gboolean +gst_apev2_mux_plugin_init (GstPlugin * plugin) +{ + if (!gst_element_register (plugin, "apev2mux", GST_RANK_NONE, + GST_TYPE_APEV2_MUX)) + return FALSE; + + return TRUE; +} diff --git a/ext/taglib/gstapev2mux.h b/ext/taglib/gstapev2mux.h new file mode 100644 index 00000000..1c05bd47 --- /dev/null +++ b/ext/taglib/gstapev2mux.h @@ -0,0 +1,55 @@ +/* GStreamer taglib-based APEv2 muxer + * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org> + * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net> + * Copyright (C) 2006 Sebastian Dröge <mail@slomosnail.de> + * + * 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_APEV2_MUX_H +#define GST_APEV2_MUX_H + +#include "gsttaglibmux.h" + +G_BEGIN_DECLS + +typedef struct _GstApev2Mux GstApev2Mux; +typedef struct _GstApev2MuxClass GstApev2MuxClass; + +typedef struct _GstApev2Mux { + GstTagLibMux taglibmux; +}; + +typedef struct _GstApev2MuxClass { + GstTagLibMuxClass taglibmux_class; +}; + +#define GST_TYPE_APEV2_MUX \ + (gst_apev2_mux_get_type()) +#define GST_APEV2_MUX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_APEV2_MUX,GstApev2Mux)) +#define GST_APEV2_MUX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_APEV2_MUX,GstApev2MuxClass)) +#define GST_IS_APEV2_MUX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_APEV2_MUX)) +#define GST_IS_APEV2_MUX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_APEV2_MUX)) + +GType gst_apev2_mux_get_type (void); + +G_END_DECLS + +#endif /* GST_APEV2_MUX_H */ diff --git a/ext/taglib/gstid3v2mux.cc b/ext/taglib/gstid3v2mux.cc index 6427b82c..0a40d9e4 100644 --- a/ext/taglib/gstid3v2mux.cc +++ b/ext/taglib/gstid3v2mux.cc @@ -424,8 +424,8 @@ gst_id3v2_mux_render_tag (GstTagLibMux * mux, GstTagList * taglist) return buf; } -static gboolean -plugin_init (GstPlugin * plugin) +gboolean +gst_id3v2_mux_plugin_init (GstPlugin * plugin) { if (!gst_element_register (plugin, "id3v2mux", GST_RANK_NONE, GST_TYPE_ID3V2_MUX)) @@ -435,9 +435,3 @@ plugin_init (GstPlugin * plugin) return TRUE; } - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "taglib", - "Tag writing plug-in based on taglib", - plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); diff --git a/ext/taglib/gsttaglibmux.c b/ext/taglib/gsttaglibmux.c index f3321d32..b0f22eaa 100644 --- a/ext/taglib/gsttaglibmux.c +++ b/ext/taglib/gsttaglibmux.c @@ -1,6 +1,7 @@ /* GStreamer taglib-based muxer base class * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org> * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net> + * Copyright (C) 2006 Sebastian Dröge <mail@slomosnail.de> * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -386,3 +387,16 @@ gst_tag_lib_mux_change_state (GstElement * element, GstStateChange transition) return result; } + +static gboolean +plugin_init (GstPlugin * plugin) +{ + return (gst_id3v2_mux_plugin_init (plugin) + && gst_apev2_mux_plugin_init (plugin)); +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "taglib", + "Tag writing plug-in based on taglib", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); diff --git a/ext/taglib/gsttaglibmux.h b/ext/taglib/gsttaglibmux.h index 26c9de7b..d26ff308 100644 --- a/ext/taglib/gsttaglibmux.h +++ b/ext/taglib/gsttaglibmux.h @@ -63,6 +63,8 @@ struct _GstTagLibMuxClass { /* Standard function returning type information. */ GType gst_tag_lib_mux_get_type (void); +gboolean gst_apev2_mux_plugin_init (GstPlugin * plugin); +gboolean gst_id3v2_mux_plugin_init (GstPlugin * plugin); G_END_DECLS |