brasero r826 - in trunk: . src src/plugins/transcode
- From: philippr svn gnome org
- To: svn-commits-list gnome org
- Subject: brasero r826 - in trunk: . src src/plugins/transcode
- Date: Sun, 25 May 2008 17:49:51 +0000 (UTC)
Author: philippr
Date: Sun May 25 17:49:51 2008
New Revision: 826
URL: http://svn.gnome.org/viewvc/brasero?rev=826&view=rev
Log:
Add normalization for audio:
- one new plugin
- modified transcode to comply with replaygain tags
Added possibility to add arbitrary GValues to session and tracks for plugins
* src/burn-job.c (brasero_job_tag_lookup), (brasero_job_tag_add):
* src/burn-job.h:
* src/burn-session.c (brasero_burn_session_tag_value_free),
(brasero_burn_session_tag_add), (brasero_burn_session_tag_lookup),
(brasero_burn_session_finalize):
* src/burn-session.h:
* src/burn-task-ctx.c (brasero_task_ctx_get_session):
* src/burn-track.c (brasero_track_clean),
(brasero_track_tag_value_free), (brasero_track_tag_add),
(brasero_track_tag_lookup):
* src/burn-track.h:
* src/plugins/transcode/Makefile.am:
* src/plugins/transcode/burn-normalize.c
(brasero_normalize_set_next_track),
(brasero_normalize_stop_pipeline), (brasero_normalize_stop),
(foreach_tag), (brasero_normalize_song_end_reached),
(brasero_normalize_bus_messages),
(brasero_normalize_new_decoded_pad_cb),
(brasero_normalize_build_pipeline), (brasero_normalize_start),
(brasero_normalize_activate), (brasero_normalize_clock_tick),
(brasero_normalize_init), (brasero_normalize_finalize),
(brasero_normalize_class_init), (brasero_normalize_export_caps):
* src/plugins/transcode/burn-normalize.h:
* src/plugins/transcode/burn-transcode.c
(brasero_transcode_send_volume_event),
(brasero_transcode_create_volume),
(brasero_transcode_create_pipeline),
(brasero_transcode_stop_pipeline),
(brasero_transcode_new_decoded_pad_cb):
Added:
trunk/src/plugins/transcode/burn-normalize.c (contents, props changed)
trunk/src/plugins/transcode/burn-normalize.h (contents, props changed)
Modified:
trunk/ChangeLog
trunk/src/burn-job.c
trunk/src/burn-job.h
trunk/src/burn-session.c
trunk/src/burn-session.h
trunk/src/burn-task-ctx.c
trunk/src/burn-track.c
trunk/src/burn-track.h
trunk/src/plugins/transcode/Makefile.am
trunk/src/plugins/transcode/burn-transcode.c
Modified: trunk/src/burn-job.c
==============================================================================
--- trunk/src/burn-job.c (original)
+++ trunk/src/burn-job.c Sun May 25 17:49:51 2008
@@ -791,6 +791,47 @@
iface->clock_tick = brasero_job_item_clock_tick;
}
+BraseroBurnResult
+brasero_job_tag_lookup (BraseroJob *self,
+ const gchar *tag,
+ GValue **value)
+{
+ BraseroJobPrivate *priv;
+ BraseroBurnSession *session;
+
+ BRASERO_JOB_DEBUG (self);
+
+ priv = BRASERO_JOB_PRIVATE (self);
+
+ session = brasero_task_ctx_get_session (priv->ctx);
+ return brasero_burn_session_tag_lookup (session,
+ tag,
+ value);
+}
+
+BraseroBurnResult
+brasero_job_tag_add (BraseroJob *self,
+ const gchar *tag,
+ GValue *value)
+{
+ BraseroJobPrivate *priv;
+ BraseroBurnSession *session;
+
+ BRASERO_JOB_DEBUG (self);
+
+ priv = BRASERO_JOB_PRIVATE (self);
+
+ if (!brasero_job_is_last_active (self))
+ return BRASERO_BURN_ERR;
+
+ session = brasero_task_ctx_get_session (priv->ctx);
+ brasero_burn_session_tag_add (session,
+ tag,
+ value);
+
+ return BRASERO_BURN_OK;
+}
+
/**
* Means a job successfully completed its task.
* track can be NULL, depending on whether or not the job created a track.
Modified: trunk/src/burn-job.h
==============================================================================
--- trunk/src/burn-job.h (original)
+++ trunk/src/burn-job.h Sun May 25 17:49:51 2008
@@ -205,6 +205,20 @@
GError **error);
/**
+ * Each tag can be retrieved by any job
+ */
+
+BraseroBurnResult
+brasero_job_tag_lookup (BraseroJob *job,
+ const gchar *tag,
+ GValue **value);
+
+BraseroBurnResult
+brasero_job_tag_add (BraseroJob *job,
+ const gchar *tag,
+ GValue *value);
+
+/**
* Used to give job results and tell when a job has finished
*/
Modified: trunk/src/burn-session.c
==============================================================================
--- trunk/src/burn-session.c (original)
+++ trunk/src/burn-session.c Sun May 25 17:49:51 2008
@@ -85,6 +85,8 @@
BraseroTrackType input;
+ GHashTable *tags;
+
guint src_added_sig;
guint src_removed_sig;
guint dest_added_sig;
@@ -1083,6 +1085,59 @@
return priv->settings->label;
}
+static void
+brasero_burn_session_tag_value_free (gpointer user_data)
+{
+ GValue *value = user_data;
+
+ g_value_reset (value);
+ g_free (value);
+}
+
+BraseroBurnResult
+brasero_burn_session_tag_add (BraseroBurnSession *self,
+ const gchar *tag,
+ GValue *value)
+{
+ BraseroBurnSessionPrivate *priv;
+
+ g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
+
+ priv = BRASERO_BURN_SESSION_PRIVATE (self);
+ if (!priv->tags)
+ priv->tags = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ brasero_burn_session_tag_value_free);
+ g_hash_table_insert (priv->tags, g_strdup (tag), value);
+ return BRASERO_BURN_OK;
+}
+
+BraseroBurnResult
+brasero_burn_session_tag_lookup (BraseroBurnSession *self,
+ const gchar *tag,
+ GValue **value)
+{
+ BraseroBurnSessionPrivate *priv;
+ gpointer data;
+
+ g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
+
+ priv = BRASERO_BURN_SESSION_PRIVATE (self);
+ if (!value)
+ return BRASERO_BURN_ERR;
+
+ if (!priv->tags)
+ return BRASERO_BURN_ERR;
+
+ data = g_hash_table_lookup (priv->tags, tag);
+ if (!data)
+ return BRASERO_BURN_ERR;
+
+ *value = data;
+ return BRASERO_BURN_OK;
+}
+
/**
* Used to save and restore settings/sources
*/
@@ -1615,6 +1670,11 @@
priv = BRASERO_BURN_SESSION_PRIVATE (object);
+ if (priv->tags) {
+ g_hash_table_destroy (priv->tags);
+ priv->tags = NULL;
+ }
+
if (priv->dest_added_sig) {
g_signal_handler_disconnect (priv->settings->burner,
priv->dest_added_sig);
Modified: trunk/src/burn-session.h
==============================================================================
--- trunk/src/burn-session.h (original)
+++ trunk/src/burn-session.h Sun May 25 17:49:51 2008
@@ -95,7 +95,15 @@
brasero_burn_session_set_label (BraseroBurnSession *session,
const gchar *label);
+BraseroBurnResult
+brasero_burn_session_tag_lookup (BraseroBurnSession *session,
+ const gchar *tag,
+ GValue **value);
+BraseroBurnResult
+brasero_burn_session_tag_add (BraseroBurnSession *session,
+ const gchar *tag,
+ GValue *value);
/**
*
*/
Modified: trunk/src/burn-task-ctx.c
==============================================================================
--- trunk/src/burn-task-ctx.c (original)
+++ trunk/src/burn-task-ctx.c Sun May 25 17:49:51 2008
@@ -201,6 +201,8 @@
{
BraseroTaskCtxPrivate *priv;
+ g_return_val_if_fail (BRASERO_IS_TASK_CTX (self), NULL);
+
priv = BRASERO_TASK_CTX_PRIVATE (self);
if (!priv->session)
return NULL;
Modified: trunk/src/burn-track.c
==============================================================================
--- trunk/src/burn-track.c (original)
+++ trunk/src/burn-track.c Sun May 25 17:49:51 2008
@@ -47,6 +47,8 @@
int ref;
+ GHashTable *tags;
+
gchar *checksum;
BraseroChecksumType checksum_type;
};
@@ -209,6 +211,11 @@
{
g_return_if_fail (track != NULL);
+ if (track->tags) {
+ g_hash_table_destroy (track->tags);
+ track->tags = NULL;
+ }
+
if (track->type.type == BRASERO_TRACK_TYPE_AUDIO) {
BraseroTrackAudio *audio = (BraseroTrackAudio *) track;
@@ -1115,3 +1122,50 @@
return BRASERO_BURN_OK;
}
+
+/**
+ * Can be used to set arbitrary data
+ */
+static void
+brasero_track_tag_value_free (gpointer user_data)
+{
+ GValue *value = user_data;
+
+ g_value_reset (value);
+ g_free (value);
+}
+
+BraseroBurnResult
+brasero_track_tag_add (BraseroTrack *track,
+ const gchar *tag,
+ GValue *value)
+{
+ if (!track->tags)
+ track->tags = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ brasero_track_tag_value_free);
+ g_hash_table_insert (track->tags, g_strdup (tag), value);
+ return BRASERO_BURN_OK;
+}
+
+BraseroBurnResult
+brasero_track_tag_lookup (BraseroTrack *track,
+ const gchar *tag,
+ GValue **value)
+{
+ gpointer data;
+
+ if (!track->tags)
+ return BRASERO_BURN_ERR;
+
+ data = g_hash_table_lookup (track->tags, tag);
+ if (!data)
+ return BRASERO_BURN_ERR;
+
+ if (value)
+ *value = data;
+
+ return BRASERO_BURN_OK;
+}
+
Modified: trunk/src/burn-track.h
==============================================================================
--- trunk/src/burn-track.h (original)
+++ trunk/src/burn-track.h Sun May 25 17:49:51 2008
@@ -292,6 +292,20 @@
brasero_track_get_data_file_num (BraseroTrack *track,
gint64 *num_files);
+/**
+ *
+ */
+
+BraseroBurnResult
+brasero_track_tag_add (BraseroTrack *track,
+ const gchar *tag,
+ GValue *value);
+
+BraseroBurnResult
+brasero_track_tag_lookup (BraseroTrack *track,
+ const gchar *tag,
+ GValue **value);
+
G_END_DECLS
#endif /* _BURN_TRACK_H */
Modified: trunk/src/plugins/transcode/Makefile.am
==============================================================================
--- trunk/src/plugins/transcode/Makefile.am (original)
+++ trunk/src/plugins/transcode/Makefile.am Sun May 25 17:49:51 2008
@@ -1,5 +1,3 @@
-plugindir = $(libdir)/brasero/plugins
-
DISABLE_DEPRECATED = -DG_DISABLE_DEPRECATED
INCLUDES = \
@@ -17,8 +15,16 @@
AM_CFLAGS = -g
-plugin_LTLIBRARIES = libbrasero-transcode.la
+transcodedir = $(libdir)/brasero/plugins
+transcode_LTLIBRARIES = libbrasero-transcode.la
-libbrasero_transcode_la_SOURCES = burn-transcode.c burn-transcode.h
+libbrasero_transcode_la_SOURCES = burn-transcode.c burn-transcode.h burn-normalize.h
libbrasero_transcode_la_LIBADD = $(BRASERO_BASE_LIBS) $(BRASERO_GSTREAMER_CFLAGS)
libbrasero_transcode_la_LDFLAGS = -module -avoid-version
+
+normalizedir = $(libdir)/brasero/plugins
+normalize_LTLIBRARIES = libbrasero-normalize.la
+
+libbrasero_normalize_la_SOURCES = burn-normalize.c burn-normalize.h
+libbrasero_normalize_la_LIBADD = $(BRASERO_BASE_LIBS) $(BRASERO_GSTREAMER_CFLAGS)
+libbrasero_normalize_la_LDFLAGS = -module -avoid-version
Added: trunk/src/plugins/transcode/burn-normalize.c
==============================================================================
--- (empty file)
+++ trunk/src/plugins/transcode/burn-normalize.c Sun May 25 17:49:51 2008
@@ -0,0 +1,569 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero-normalize.c
+ * Copyright (C) Rouquier Philippe 2008 <bonfire-app wanadoo fr>
+ *
+ * brasero-normalize.c is free software.
+ *
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * brasero-normalize.c 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with brasero-normalize.c. If not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include <gst/gst.h>
+
+#include "burn-basics.h"
+#include "burn-job.h"
+#include "burn-plugin.h"
+#include "burn-normalize.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroNormalize, brasero_normalize, BRASERO_TYPE_JOB, BraseroJob);
+
+typedef struct _BraseroNormalizePrivate BraseroNormalizePrivate;
+struct _BraseroNormalizePrivate
+{
+ GstElement *pipeline;
+ GstElement *analysis;
+ GstElement *decode;
+ GstElement *source;
+
+ GSList *tracks;
+ BraseroTrack *track;
+
+ gdouble album_peak;
+ gdouble album_gain;
+ gdouble track_peak;
+ gdouble track_gain;
+};
+
+#define BRASERO_NORMALIZE_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_NORMALIZE, BraseroNormalizePrivate))
+
+static GObjectClass *parent_class = NULL;
+
+
+static gboolean
+brasero_normalize_bus_messages (GstBus *bus,
+ GstMessage *msg,
+ BraseroNormalize *normalize);
+
+static gboolean
+brasero_normalize_set_next_track (BraseroJob *job,
+ BraseroTrack *track,
+ GError **error)
+{
+ gchar *uri;
+ GstBus *bus = NULL;
+ GstElement *source;
+ BraseroNormalizePrivate *priv;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (job);
+
+ /* destroy previous source */
+ if (priv->source) {
+ gst_element_unlink (priv->source, priv->decode);
+ gst_bin_remove (GST_BIN (priv->pipeline), priv->source);
+ priv->source = NULL;
+ }
+
+ /* create a new one */
+ uri = brasero_track_get_audio_source (track, TRUE);
+ source = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
+ if (source == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("source can't be created"));
+ return FALSE;
+ }
+ gst_bin_add (GST_BIN (priv->pipeline), source);
+ g_object_set (source,
+ "typefind", FALSE,
+ NULL);
+
+ priv->source = source;
+ gst_element_link_many (source, priv->decode, NULL);
+
+ /* reconnect to the bus */
+ bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
+ gst_bus_add_watch (bus,
+ (GstBusFunc) brasero_normalize_bus_messages,
+ job);
+ gst_object_unref (bus);
+
+ priv->track = track;
+
+ return TRUE;
+}
+
+static void
+brasero_normalize_stop_pipeline (BraseroNormalize *normalize)
+{
+ BraseroNormalizePrivate *priv;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+ if (!priv->pipeline)
+ return;
+
+ gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+ gst_object_unref (GST_OBJECT (priv->pipeline));
+ priv->pipeline = NULL;
+ priv->analysis = NULL;
+ priv->decode = NULL;
+ priv->source = NULL;
+}
+
+static BraseroBurnResult
+brasero_normalize_stop (BraseroJob *job,
+ GError **error)
+{
+ BraseroNormalizePrivate *priv;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (job);
+
+ brasero_normalize_stop_pipeline (BRASERO_NORMALIZE (job));
+ if (priv->tracks) {
+ g_slist_free (priv->tracks);
+ priv->tracks = NULL;
+ }
+
+ priv->track = NULL;
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+foreach_tag (const GstTagList *list,
+ const gchar *tag,
+ BraseroNormalize *normalize)
+{
+ gdouble value = 0.0;
+ BraseroNormalizePrivate *priv;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+
+ /* Those next two are generated at the end only */
+ if (!strcmp (tag, GST_TAG_ALBUM_GAIN)) {
+ gst_tag_list_get_double (list, tag, &value);
+ priv->album_gain = value;
+ }
+ else if (!strcmp (tag, GST_TAG_ALBUM_PEAK)) {
+ gst_tag_list_get_double (list, tag, &value);
+ priv->album_peak = value;
+ }
+ else if (!strcmp (tag, GST_TAG_TRACK_PEAK)) {
+ gst_tag_list_get_double (list, tag, &value);
+ priv->track_peak = value;
+ }
+ else if (!strcmp (tag, GST_TAG_TRACK_GAIN)) {
+ gst_tag_list_get_double (list, tag, &value);
+ priv->track_gain = value;
+ }
+}
+
+static void
+brasero_normalize_song_end_reached (BraseroNormalize *normalize)
+{
+ GValue *value;
+ BraseroTrack *track;
+ GError *error = NULL;
+ BraseroNormalizePrivate *priv;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+
+ /* finished track: set tags */
+ BRASERO_JOB_LOG (normalize,
+ "Setting track peak (%lf) and gain (%lf)",
+ priv->track_peak,
+ priv->track_gain);
+
+ value = g_new0 (GValue, 1);
+ g_value_init (value, G_TYPE_DOUBLE);
+ g_value_set_double (value, priv->track_peak);
+ brasero_track_tag_add (priv->track,
+ BRASERO_TRACK_PEAK_VALUE,
+ value);
+
+ value = g_new0 (GValue, 1);
+ g_value_init (value, G_TYPE_DOUBLE);
+ g_value_set_double (value, priv->track_gain);
+ brasero_track_tag_add (priv->track,
+ BRASERO_TRACK_GAIN_VALUE,
+ value);
+
+ priv->track_peak = 0.0;
+ priv->track_gain = 0.0;
+
+ if (!priv->tracks) {
+ BRASERO_JOB_LOG (normalize,
+ "Setting album peak (%lf) and gain (%lf)",
+ priv->album_peak,
+ priv->album_gain);
+
+ /* finished: set tags */
+ value = g_new0 (GValue, 1);
+ g_value_init (value, G_TYPE_DOUBLE);
+ g_value_set_double (value, priv->album_peak);
+ brasero_job_tag_add (BRASERO_JOB (normalize),
+ BRASERO_ALBUM_PEAK_VALUE,
+ value);
+
+ value = g_new0 (GValue, 1);
+ g_value_init (value, G_TYPE_DOUBLE);
+ g_value_set_double (value, priv->album_gain);
+ brasero_job_tag_add (BRASERO_JOB (normalize),
+ BRASERO_ALBUM_GAIN_VALUE,
+ value);
+
+ brasero_job_finished_session (BRASERO_JOB (normalize));
+ return;
+ }
+
+ /* jump to next track */
+ gst_element_set_locked_state (priv->analysis, TRUE);
+ gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+
+ track = priv->tracks->data;
+ priv->tracks = g_slist_remove (priv->tracks, track);
+ if (!brasero_normalize_set_next_track (BRASERO_JOB (normalize), track, &error)) {
+ gst_element_set_locked_state (priv->analysis, FALSE);
+ brasero_job_error (BRASERO_JOB (normalize), error);
+ return;
+ }
+
+ gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+ gst_element_set_locked_state (priv->analysis, FALSE);
+}
+
+static gboolean
+brasero_normalize_bus_messages (GstBus *bus,
+ GstMessage *msg,
+ BraseroNormalize *normalize)
+{
+ BraseroNormalizePrivate *priv;
+ GstTagList *tags = NULL;
+ GError *error = NULL;
+ gchar *debug;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+ switch (GST_MESSAGE_TYPE (msg)) {
+ case GST_MESSAGE_TAG:
+ /* This is the information we've been waiting for.
+ * NOTE: levels for whole album is delivered at the end */
+ gst_message_parse_tag (msg, &tags);
+ gst_tag_list_foreach (tags, (GstTagForeachFunc) foreach_tag, normalize);
+ gst_tag_list_free (tags);
+ return TRUE;
+
+ case GST_MESSAGE_ERROR:
+ gst_message_parse_error (msg, &error, &debug);
+ BRASERO_JOB_LOG (normalize, debug);
+ g_free (debug);
+
+ brasero_job_error (BRASERO_JOB (normalize), error);
+ return FALSE;
+
+ case GST_MESSAGE_EOS:
+ brasero_normalize_song_end_reached (normalize);
+ return FALSE;
+
+ case GST_MESSAGE_STATE_CHANGED:
+ break;
+
+ default:
+ return TRUE;
+ }
+
+ return TRUE;
+}
+
+static void
+brasero_normalize_new_decoded_pad_cb (GstElement *decode,
+ GstPad *pad,
+ gboolean arg2,
+ GstElement *convert)
+{
+ GstPad *sink;
+ GstCaps *caps;
+ GstStructure *structure;
+
+ sink = gst_element_get_pad (convert, "sink");
+ if (GST_PAD_IS_LINKED (sink))
+ return;
+
+ /* make sure we only have audio */
+ caps = gst_pad_get_caps (pad);
+ if (!caps)
+ return;
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (structure && g_strrstr (gst_structure_get_name (structure), "audio"))
+ gst_pad_link (pad, sink);
+
+ gst_object_unref (sink);
+ gst_caps_unref (caps);
+}
+
+static gboolean
+brasero_normalize_build_pipeline (BraseroNormalize *normalize,
+ GError **error)
+{
+ GstElement *decode;
+ GstElement *pipeline;
+ GstElement *sink = NULL;
+ GstElement *convert = NULL;
+ GstElement *analysis = NULL;
+ GstElement *resample = NULL;
+ BraseroNormalizePrivate *priv;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (normalize);
+
+ BRASERO_JOB_LOG (normalize, "Creating new pipeline");
+
+ /* create filesrc ! decodebin ! audioresample ! audioconvert ! rganalysis ! fakesink */
+ pipeline = gst_pipeline_new (NULL);
+ priv->pipeline = pipeline;
+
+ /* NOTE: a new source is created at start of every track */
+
+ /* decode */
+ decode = gst_element_factory_make ("decodebin", NULL);
+ if (decode == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("decode can't be created"));
+ goto error;
+ }
+ gst_bin_add (GST_BIN (pipeline), decode);
+ priv->decode = decode;
+
+ /* audioconvert */
+ convert = gst_element_factory_make ("audioconvert", NULL);
+ if (convert == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("audioconvert can't be created"));
+ goto error;
+ }
+ gst_bin_add (GST_BIN (pipeline), convert);
+
+ /* audioresample */
+ resample = gst_element_factory_make ("audioresample", NULL);
+ if (resample == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("audioresample can't be created"));
+ goto error;
+ }
+ gst_bin_add (GST_BIN (pipeline), resample);
+
+ /* rganalysis: set the number of tracks to be expected */
+ analysis = gst_element_factory_make ("rganalysis", NULL);
+ if (analysis == NULL) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("rganalysis can't be created"));
+ goto error;
+ }
+ priv->analysis = analysis;
+ gst_bin_add (GST_BIN (pipeline), analysis);
+
+ /* sink */
+ sink = gst_element_factory_make ("fakesink", NULL);
+ if (!sink) {
+ g_set_error (error,
+ BRASERO_BURN_ERROR,
+ BRASERO_BURN_ERROR_GENERAL,
+ _("sink can't be created"));
+ goto error;
+ }
+ gst_bin_add (GST_BIN (pipeline), sink);
+ g_object_set (sink,
+ "sync", FALSE,
+ NULL);
+
+ /* link everything */
+ g_signal_connect (G_OBJECT (decode),
+ "new-decoded-pad",
+ G_CALLBACK (brasero_normalize_new_decoded_pad_cb),
+ resample);
+ gst_element_link_many (resample,
+ convert,
+ analysis,
+ sink,
+ NULL);
+ return TRUE;
+
+error:
+
+ if (error && (*error))
+ BRASERO_JOB_LOG (normalize,
+ "can't create object : %s \n",
+ (*error)->message);
+
+ gst_object_unref (GST_OBJECT (pipeline));
+ return FALSE;
+}
+
+static BraseroBurnResult
+brasero_normalize_start (BraseroJob *job,
+ GError **error)
+{
+ BraseroNormalizePrivate *priv;
+ BraseroTrack *track;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (job);
+
+ priv->album_gain = -1.0;
+ priv->album_peak = -1.0;
+
+ /* get tracks */
+ brasero_job_get_tracks (job, &priv->tracks);
+ if (!priv->tracks)
+ return BRASERO_BURN_ERR;
+
+ priv->tracks = g_slist_copy (priv->tracks);
+ track = priv->tracks->data;
+ priv->tracks = g_slist_remove (priv->tracks, track);
+
+ if (!brasero_normalize_build_pipeline (BRASERO_NORMALIZE (job), error))
+ return BRASERO_BURN_ERR;
+
+ g_object_set (priv->analysis,
+ "num-tracks", g_slist_length (priv->tracks),
+ NULL);
+
+ if (!brasero_normalize_set_next_track (job, track, error))
+ return BRASERO_BURN_ERR;
+
+ /* ready to go */
+ brasero_job_set_current_action (job,
+ BRASERO_BURN_ACTION_ANALYSING,
+ _("Normalizing tracks"),
+ FALSE);
+ gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_normalize_activate (BraseroJob *job,
+ GError **error)
+{
+ GSList *tracks;
+ BraseroJobAction action;
+
+ brasero_job_get_action (job, &action);
+ if (action != BRASERO_JOB_ACTION_IMAGE)
+ return BRASERO_BURN_NOT_RUNNING;
+
+ /* check we have more than one track */
+ brasero_job_get_tracks (job, &tracks);
+ if (g_slist_length (tracks) < 2)
+ return BRASERO_BURN_NOT_RUNNING;
+
+ return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_normalize_clock_tick (BraseroJob *job)
+{
+ gint64 position = 0.0;
+ gint64 duration = 0.0;
+ BraseroNormalizePrivate *priv;
+ GstFormat format = GST_FORMAT_TIME;
+
+ priv = BRASERO_NORMALIZE_PRIVATE (job);
+
+ gst_element_query_duration (priv->pipeline, &format, &duration);
+ gst_element_query_position (priv->pipeline, &format, &position);
+
+ if (duration > 0) {
+ GSList *tracks;
+ gdouble progress;
+
+ brasero_job_get_tracks (job, &tracks);
+ progress = (gdouble) position / (gdouble) duration;
+
+ if (tracks) {
+ gdouble num_tracks;
+
+ num_tracks = g_slist_length (tracks);
+ progress = (gdouble) (num_tracks - 1.0 - (gdouble) g_slist_length (priv->tracks) + progress) / (gdouble) num_tracks;
+ brasero_job_set_progress (job, progress);
+ }
+ }
+
+ return BRASERO_BURN_OK;
+}
+
+static void
+brasero_normalize_init (BraseroNormalize *object)
+{}
+
+static void
+brasero_normalize_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_normalize_class_init (BraseroNormalizeClass *klass)
+{
+ GObjectClass* object_class = G_OBJECT_CLASS (klass);
+ BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (BraseroNormalizePrivate));
+
+ object_class->finalize = brasero_normalize_finalize;
+
+ job_class->activate = brasero_normalize_activate;
+ job_class->start = brasero_normalize_start;
+ job_class->clock_tick = brasero_normalize_clock_tick;
+ job_class->stop = brasero_normalize_stop;
+}
+
+static BraseroBurnResult
+brasero_normalize_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+ GSList *input;
+
+ brasero_plugin_define (plugin,
+ "normalize",
+ _("Normalize allows to set consistent sound levels between tracks"),
+ "Philippe Rouquier",
+ 0);
+
+ input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+ BRASERO_AUDIO_FORMAT_UNDEFINED);
+ brasero_plugin_process_caps (plugin, input);
+ brasero_plugin_set_process_flags (plugin, BRASERO_PLUGIN_RUN_FIRST);
+ g_slist_free (input);
+
+ return BRASERO_BURN_OK;
+}
Added: trunk/src/plugins/transcode/burn-normalize.h
==============================================================================
--- (empty file)
+++ trunk/src/plugins/transcode/burn-normalize.h Sun May 25 17:49:51 2008
@@ -0,0 +1,48 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero-normalize.c
+ * Copyright (C) Rouquier Philippe 2008 <bonfire-app wanadoo fr>
+ *
+ * brasero-normalize.c is free software.
+ *
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * brasero-normalize.c 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with brasero-normalize.c. If not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _BRASERO_NORMALIZE_H_
+#define _BRASERO_NORMALIZE_H_
+
+#include <glib-object.h>
+
+#include "burn-job.h"
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_NORMALIZE (brasero_normalize_get_type ())
+#define BRASERO_NORMALIZE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BRASERO_TYPE_NORMALIZE, BraseroNormalize))
+#define BRASERO_NORMALIZE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BRASERO_TYPE_NORMALIZE, BraseroNormalizeClass))
+#define BRASERO_IS_NORMALIZE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BRASERO_TYPE_NORMALIZE))
+#define BRASERO_IS_NORMALIZE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BRASERO_TYPE_NORMALIZE))
+#define BRASERO_NORMALIZE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BRASERO_TYPE_NORMALIZE, BraseroNormalizeClass))
+
+#define BRASERO_ALBUM_PEAK_VALUE "peak_value"
+#define BRASERO_ALBUM_GAIN_VALUE "gain_value"
+#define BRASERO_TRACK_PEAK_VALUE "peak_value"
+#define BRASERO_TRACK_GAIN_VALUE "gain_value"
+
+G_END_DECLS
+
+#endif /* _BRASERO_NORMALIZE_H_ */
Modified: trunk/src/plugins/transcode/burn-transcode.c
==============================================================================
--- trunk/src/plugins/transcode/burn-transcode.c (original)
+++ trunk/src/plugins/transcode/burn-transcode.c Sun May 25 17:49:51 2008
@@ -43,6 +43,7 @@
#include "burn-job.h"
#include "burn-plugin.h"
#include "burn-transcode.h"
+#include "burn-normalize.h"
BRASERO_PLUGIN_BOILERPLATE (BraseroTranscode, brasero_transcode, BRASERO_TYPE_JOB, BraseroJob);
@@ -52,15 +53,18 @@
static void brasero_transcode_new_decoded_pad_cb (GstElement *decode,
GstPad *pad,
gboolean arg2,
- GstElement *convert);
+ BraseroTranscode *transcode);
struct BraseroTranscodePrivate {
GstElement *pipeline;
GstElement *convert;
- GstElement *decode;
GstElement *source;
+ GstElement *decode;
GstElement *sink;
+ /* element to link decode to */
+ GstElement *link;
+
gint pad_size;
gint pad_fd;
gint pad_id;
@@ -191,8 +195,68 @@
return BRASERO_BURN_OK;
}
+static void
+brasero_transcode_send_volume_event (BraseroTranscode *transcode)
+{
+ BraseroTranscodePrivate *priv;
+ gdouble track_peak = 0.0;
+ gdouble track_gain = 0.0;
+ GstTagList *tag_list;
+ BraseroTrack *track;
+ GstEvent *event;
+ GValue *value;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (transcode);
+
+ brasero_job_get_current_track (BRASERO_JOB (transcode), &track);
+
+ BRASERO_JOB_LOG (transcode, "Sending audio levels tags");
+ if (brasero_track_tag_lookup (track, BRASERO_TRACK_PEAK_VALUE, &value) == BRASERO_BURN_OK)
+ track_peak = g_value_get_double (value);
+
+ if (brasero_track_tag_lookup (track, BRASERO_TRACK_GAIN_VALUE, &value) == BRASERO_BURN_OK)
+ track_gain = g_value_get_double (value);
+
+ /* it's possible we fail */
+ tag_list = gst_tag_list_new ();
+ gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
+ GST_TAG_TRACK_GAIN, track_gain,
+ GST_TAG_TRACK_PEAK, track_peak,
+ NULL);
+
+ /* NOTE: that event is goind downstream */
+ event = gst_event_new_tag (tag_list);
+ if (!gst_element_send_event (priv->convert, event))
+ BRASERO_JOB_LOG (transcode, "Couldn't send tags to rgvolume");
+
+ BRASERO_JOB_LOG (transcode, "Set %lf %lf", track_gain, track_peak);
+}
+
+static GstElement *
+brasero_transcode_create_volume (BraseroTranscode *transcode,
+ BraseroTrack *track)
+{
+ GstElement *volume = NULL;
+
+ /* see if we need a volume object */
+ if (brasero_track_tag_lookup (track, BRASERO_TRACK_PEAK_VALUE, NULL) == BRASERO_BURN_OK
+ || brasero_track_tag_lookup (track, BRASERO_TRACK_GAIN_VALUE, NULL) == BRASERO_BURN_OK) {
+ BRASERO_JOB_LOG (transcode, "Found audio levels tags");
+ volume = gst_element_factory_make ("rgvolume", NULL);
+ g_object_set (volume,
+ "album-mode", FALSE,
+ NULL);
+
+ if (!volume)
+ BRASERO_JOB_LOG (transcode, "rgvolume object couldn't be created");
+ }
+
+ return volume;
+}
+
static gboolean
-brasero_transcode_create_pipeline (BraseroTranscode *transcode, GError **error)
+brasero_transcode_create_pipeline (BraseroTranscode *transcode,
+ GError **error)
{
gchar *uri;
GstPad *sinkpad;
@@ -204,6 +268,7 @@
GstElement *sink = NULL;
BraseroJobAction action;
GstElement *filter = NULL;
+ GstElement *volume = NULL;
GstElement *convert = NULL;
BraseroTrack *track = NULL;
GstElement *resample = NULL;
@@ -219,14 +284,14 @@
if (priv->pipeline) {
gst_element_set_state (priv->pipeline, GST_STATE_NULL);
gst_object_unref (G_OBJECT (priv->pipeline));
- priv->pipeline = NULL;
+ priv->link = NULL;
priv->sink = NULL;
priv->source = NULL;
priv->convert = NULL;
priv->pipeline = NULL;
}
- /* create three types of pipeline according to the needs:
+ /* create three types of pipeline according to the needs: (possibly adding grvolume)
* - filesrc ! decodebin ! audioconvert ! fakesink (find size)
* - filesrc ! decodebin ! audioresample ! audioconvert ! audio/x-raw-int,rate=44100,width=16,depth=16,endianness=4321,signed ! filesink
* - filesrc ! decodebin ! audioresample ! audioconvert ! audio/x-raw-int,rate=44100,width=16,depth=16,endianness=4321,signed ! fdsink
@@ -263,6 +328,8 @@
break;
case BRASERO_JOB_ACTION_IMAGE:
+ volume = brasero_transcode_create_volume (transcode, track);
+
if (brasero_job_get_fd_out (BRASERO_JOB (transcode), NULL) != BRASERO_BURN_OK) {
gchar *output;
@@ -362,24 +429,37 @@
if (action == BRASERO_JOB_ACTION_IMAGE) {
gst_element_link_many (source, decode, NULL);
+ priv->link = resample;
g_signal_connect (G_OBJECT (decode),
"new-decoded-pad",
G_CALLBACK (brasero_transcode_new_decoded_pad_cb),
- resample);
- gst_element_link_many (resample,
- convert,
- filter,
- sink,
- NULL);
+ transcode);
+
+ if (volume) {
+ gst_bin_add (GST_BIN (pipeline), volume);
+ gst_element_link_many (resample,
+ convert,
+ volume,
+ filter,
+ sink,
+ NULL);
+ }
+ else
+ gst_element_link_many (resample,
+ convert,
+ filter,
+ sink,
+ NULL);
}
else {
gst_element_link (source, decode);
gst_element_link (convert, sink);
+ priv->link = convert;
g_signal_connect (G_OBJECT (decode),
"new-decoded-pad",
G_CALLBACK (brasero_transcode_new_decoded_pad_cb),
- convert);
+ transcode);
}
priv->sink = sink;
@@ -686,7 +766,8 @@
gst_element_set_state (priv->pipeline, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (priv->pipeline));
- priv->pipeline = NULL;
+
+ priv->link = NULL;
priv->sink = NULL;
priv->source = NULL;
priv->convert = NULL;
@@ -1262,13 +1343,16 @@
brasero_transcode_new_decoded_pad_cb (GstElement *decode,
GstPad *pad,
gboolean arg2,
- GstElement *convert)
+ BraseroTranscode *transcode)
{
GstPad *sink;
GstCaps *caps;
GstStructure *structure;
+ BraseroTranscodePrivate *priv;
+
+ priv = BRASERO_TRANSCODE_PRIVATE (transcode);
- sink = gst_element_get_pad (convert, "sink");
+ sink = gst_element_get_pad (priv->link, "sink");
if (GST_PAD_IS_LINKED (sink))
return;
@@ -1277,6 +1361,9 @@
if (!caps)
return;
+ /* before linking pads (before any data reach grvolume), send tags */
+ brasero_transcode_send_volume_event (transcode);
+
structure = gst_caps_get_structure (caps, 0);
if (structure
&& g_strrstr (gst_structure_get_name (structure), "audio"))
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]