id3v2mux: write RVA2 frames containing peak/gain volume data

This commit is contained in:
Jonathan Matthew 2009-04-02 00:20:02 +01:00 committed by Tim-Philipp Müller
parent f1fb1f80fa
commit 9b7c9208c3
2 changed files with 106 additions and 8 deletions

View file

@ -55,6 +55,7 @@
#include <textidentificationframe.h>
#include <uniquefileidentifierframe.h>
#include <attachedpictureframe.h>
#include <relativevolumeframe.h>
#include <commentsframe.h>
#include <unknownframe.h>
#include <id3v2synchdata.h>
@ -560,6 +561,71 @@ add_uri_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
}
}
static void
add_relative_volume_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
const gchar * tag, guint num_tags, const gchar * frame_id)
{
const char *gain_tag_name;
const char *peak_tag_name;
gdouble peak_val;
gdouble gain_val;
ID3v2::RelativeVolumeFrame * frame;
frame = new ID3v2::RelativeVolumeFrame ();
/* figure out tag names and the identification string to use */
if (strcmp (tag, GST_TAG_TRACK_PEAK) == 0 ||
strcmp (tag, GST_TAG_TRACK_GAIN) == 0) {
gain_tag_name = GST_TAG_TRACK_GAIN;
peak_tag_name = GST_TAG_TRACK_PEAK;
frame->setIdentification ("track");
GST_DEBUG ("adding track relative-volume frame");
} else {
gain_tag_name = GST_TAG_ALBUM_GAIN;
peak_tag_name = GST_TAG_ALBUM_PEAK;
frame->setIdentification ("album");
GST_DEBUG ("adding album relative-volume frame");
}
/* find the value for the paired tag (gain, if this is peak, and
* vice versa). if both tags exist, only write the frame when
* we're processing the peak tag.
*/
if (strcmp (tag, GST_TAG_TRACK_PEAK) == 0 ||
strcmp (tag, GST_TAG_ALBUM_PEAK) == 0) {
ID3v2::RelativeVolumeFrame::PeakVolume encoded_peak;
short peak_int;
gst_tag_list_get_double (list, tag, &peak_val);
if (gst_tag_list_get_tag_size (list, gain_tag_name) > 0) {
gst_tag_list_get_double (list, gain_tag_name, &gain_val);
GST_DEBUG ("setting volume adjustment %g", gain_val);
frame->setVolumeAdjustment (gain_val);
}
/* copying mutagen: always write as 16 bits for sanity. */
peak_int = (short)(peak_val * G_MAXSHORT);
encoded_peak.bitsRepresentingPeak = 16;
encoded_peak.peakVolume = ByteVector::fromShort(peak_int, true);
GST_DEBUG ("setting peak value %g", peak_val);
frame->setPeakVolume(encoded_peak);
} else {
gst_tag_list_get_double (list, tag, &gain_val);
GST_DEBUG ("setting volume adjustment %g", gain_val);
frame->setVolumeAdjustment (gain_val);
if (gst_tag_list_get_tag_size (list, peak_tag_name) != 0) {
GST_DEBUG ("both gain and peak tags exist, not adding frame this time around");
delete frame;
return;
}
}
id3v2tag->addFrame (frame);
}
/* id3demux produces these for frames it cannot parse */
#define GST_ID3_DEMUX_TAG_ID3V2_FRAME "private-id3v2-frame"
@ -599,7 +665,11 @@ static const struct
GST_TAG_ENCODER, add_encoder_tag, ""}, {
GST_TAG_ENCODER_VERSION, add_encoder_tag, ""}, {
GST_TAG_COPYRIGHT_URI, add_uri_tag, "WCOP"}, {
GST_TAG_LICENSE_URI, add_uri_tag, "WCOP"}
GST_TAG_LICENSE_URI, add_uri_tag, "WCOP"}, {
GST_TAG_TRACK_PEAK, add_relative_volume_tag, ""}, {
GST_TAG_TRACK_GAIN, add_relative_volume_tag, ""}, {
GST_TAG_ALBUM_PEAK, add_relative_volume_tag, ""}, {
GST_TAG_ALBUM_GAIN, add_relative_volume_tag, ""}
};

View file

@ -33,9 +33,10 @@
#define TEST_TRACK_COUNT 19
#define TEST_VOLUME_NUMBER 2
#define TEST_VOLUME_COUNT 3
/* #define TEST_TRACK_GAIN 1.45 (not implemented yet) */
/* #define TEST_ALBUM_GAIN 0.78 (not implemented yet) */
#define TEST_TRACK_GAIN 1.45
#define TEST_ALBUM_GAIN 0.78
#define TEST_TRACK_PEAK 0.83
#define TEST_ALBUM_PEAK 0.18
/* for dummy mp3 frame sized MP3_FRAME_SIZE bytes,
* start: ff fb b0 44 00 00 08 00 00 4b 00 00 00 00 00 00 */
@ -45,6 +46,18 @@ static const guint8 mp3_dummyhdr[] = { 0xff, 0xfb, 0xb0, 0x44, 0x00, 0x00,
#define MP3_FRAME_SIZE 626
/* the peak and gain values are stored pretty roughly, so check that they're
* within 2% of the expected value.
*/
#define fail_unless_sorta_equals_float(a, b) \
G_STMT_START { \
double first = a; \
double second = b; \
fail_unless(fabs (first - second) < (0.02 * fabs (first)), \
"'" #a "' (%g) is not equal to '" #b "' (%g)", first, second); \
} G_STMT_END;
static GstTagList *
test_taglib_id3mux_create_tags (guint32 mask)
{
@ -88,12 +101,20 @@ test_taglib_id3mux_create_tags (guint32 mask)
GST_TAG_ALBUM_VOLUME_COUNT, TEST_VOLUME_COUNT, NULL);
}
if (mask & (1 << 8)) {
gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
GST_TAG_TRACK_GAIN, TEST_TRACK_GAIN, NULL);
}
if (mask & (1 << 9)) {
gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
GST_TAG_ALBUM_GAIN, TEST_ALBUM_GAIN, NULL);
}
if (mask & (1 << 10)) {
gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
GST_TAG_TRACK_PEAK, TEST_TRACK_PEAK, NULL);
}
if (mask & (1 << 11)) {
gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
GST_TAG_ALBUM_PEAK, TEST_ALBUM_PEAK, NULL);
}
if (mask & (1 << 12)) {
}
@ -193,23 +214,29 @@ test_taglib_id3mux_check_tags (GstTagList * tags, guint32 mask)
&count));
fail_unless (count == TEST_VOLUME_COUNT);
}
#if 0
if (mask & (1 << 8)) {
gdouble gain;
fail_unless (gst_tag_list_get_double (tags, GST_TAG_TRACK_GAIN, &gain));
fail_unless (gain == TEST_TRACK_GAIN);
fail_unless_sorta_equals_float (gain, TEST_TRACK_GAIN);
}
if (mask & (1 << 9)) {
gdouble gain;
fail_unless (gst_tag_list_get_double (tags, GST_TAG_ALBUM_GAIN, &gain));
fail_unless (gain == TEST_ALBUM_GAIN);
fail_unless_sorta_equals_float (gain, TEST_ALBUM_GAIN);
}
#endif
if (mask & (1 << 10)) {
gdouble peak;
fail_unless (gst_tag_list_get_double (tags, GST_TAG_TRACK_PEAK, &peak));
fail_unless_sorta_equals_float (peak, TEST_TRACK_PEAK);
}
if (mask & (1 << 11)) {
gdouble peak;
fail_unless (gst_tag_list_get_double (tags, GST_TAG_ALBUM_PEAK, &peak));
fail_unless_sorta_equals_float (peak, TEST_ALBUM_PEAK);
}
if (mask & (1 << 12)) {
}
@ -269,6 +296,7 @@ got_buffer (GstElement * fakesink, GstBuffer * buf, GstPad * pad,
memcpy (GST_BUFFER_DATA (*p_buf) + off, GST_BUFFER_DATA (buf), size);
}
}
static void
demux_pad_added (GstElement * id3demux, GstPad * srcpad, GstBuffer ** p_outbuf)
{