mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-29 04:15:35 +00:00
id3tag: port to 0.11
This commit is contained in:
parent
77377c55a2
commit
38c749ca2f
3 changed files with 110 additions and 78 deletions
|
@ -314,7 +314,7 @@ GST_PLUGINS_NONPORTED=" aiff \
|
|||
cdxaparse \
|
||||
dccp faceoverlay \
|
||||
fieldanalysis freeverb freeze frei0r \
|
||||
hdvparse id3tag inter ivfparse jpegformat jp2kdecimator \
|
||||
hdvparse inter ivfparse jpegformat jp2kdecimator \
|
||||
kate liveadder librfb \
|
||||
mpegpsmux mve mxf mythtv nsf nuvdemux \
|
||||
patchdetect pnm real \
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* GStreamer ID3 v1 and v2 muxer
|
||||
*
|
||||
* Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org>
|
||||
* Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
|
||||
* Copyright (C) 2006-2012 Tim-Philipp Müller <tim centricular net>
|
||||
* Copyright (C) 2009 Pioneers of the Inevitable <songbird@songbirdnest.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
|
@ -81,7 +81,7 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
|
|||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS ("application/x-id3"));
|
||||
|
||||
GST_BOILERPLATE (GstId3Mux, gst_id3_mux, GstTagMux, GST_TYPE_TAG_MUX);
|
||||
G_DEFINE_TYPE (GstId3Mux, gst_id3_mux, GST_TYPE_TAG_MUX);
|
||||
|
||||
static GstBuffer *gst_id3_mux_render_v2_tag (GstTagMux * mux,
|
||||
const GstTagList * taglist);
|
||||
|
@ -93,27 +93,10 @@ static void gst_id3_mux_set_property (GObject * object, guint prop_id,
|
|||
static void gst_id3_mux_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static void
|
||||
gst_id3_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 (&sink_template));
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&src_template));
|
||||
|
||||
gst_element_class_set_details_simple (element_class,
|
||||
"ID3 v1 and v2 Muxer", "Formatter/Metadata",
|
||||
"Adds an ID3v2 header and ID3v1 footer to a file",
|
||||
"Michael Smith <msmith@songbirdnest.com>, "
|
||||
"Tim-Philipp Müller <tim centricular net>");
|
||||
}
|
||||
|
||||
static void
|
||||
gst_id3_mux_class_init (GstId3MuxClass * klass)
|
||||
{
|
||||
GstElementClass *element_class = (GstElementClass *) klass;
|
||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||
|
||||
gobject_class->set_property = gst_id3_mux_set_property;
|
||||
|
@ -139,10 +122,22 @@ gst_id3_mux_class_init (GstId3MuxClass * klass)
|
|||
GST_DEBUG_FUNCPTR (gst_id3_mux_render_v2_tag);
|
||||
GST_TAG_MUX_CLASS (klass)->render_end_tag =
|
||||
GST_DEBUG_FUNCPTR (gst_id3_mux_render_v1_tag);
|
||||
|
||||
gst_element_class_set_details_simple (element_class,
|
||||
"ID3 v1 and v2 Muxer", "Formatter/Metadata",
|
||||
"Adds an ID3v2 header and ID3v1 footer to a file",
|
||||
"Michael Smith <msmith@songbirdnest.com>, "
|
||||
"Tim-Philipp Müller <tim centricular net>");
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&sink_template));
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&src_template));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_id3_mux_init (GstId3Mux * id3mux, GstId3MuxClass * id3mux_class)
|
||||
gst_id3_mux_init (GstId3Mux * id3mux)
|
||||
{
|
||||
id3mux->write_v1 = DEFAULT_WRITE_V1;
|
||||
id3mux->write_v2 = DEFAULT_WRITE_V2;
|
||||
|
|
|
@ -192,6 +192,7 @@ static GstBuffer *
|
|||
id3v2_tag_to_buffer (GstId3v2Tag * tag)
|
||||
{
|
||||
GstByteWriter *w;
|
||||
GstMapInfo info;
|
||||
GstBuffer *buf;
|
||||
guint8 *dest;
|
||||
guint i, size, offset, size_frames = 0;
|
||||
|
@ -217,8 +218,9 @@ id3v2_tag_to_buffer (GstId3v2Tag * tag)
|
|||
gst_byte_writer_write_uint8 (w, 0); /* flags */
|
||||
gst_byte_writer_write_uint32_syncsafe (w, size - 10);
|
||||
|
||||
buf = gst_buffer_new_and_alloc (size);
|
||||
dest = GST_BUFFER_DATA (buf);
|
||||
buf = gst_buffer_new_allocate (NULL, size, NULL);
|
||||
gst_buffer_map (buf, &info, GST_MAP_WRITE);
|
||||
dest = info.data;
|
||||
gst_byte_writer_copy_bytes (w, dest, 0, 10);
|
||||
offset = 10;
|
||||
|
||||
|
@ -233,6 +235,7 @@ id3v2_tag_to_buffer (GstId3v2Tag * tag)
|
|||
memset (dest + offset, 0, size - offset);
|
||||
|
||||
gst_byte_writer_free (w);
|
||||
gst_buffer_unmap (buf, &info);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
@ -472,6 +475,7 @@ add_text_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
|
|||
g_free (strings);
|
||||
}
|
||||
|
||||
/* FIXME: id3v2-private frames need to be extracted as samples */
|
||||
static void
|
||||
add_id3v2frame_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
|
||||
const gchar * tag, guint num_tags, const gchar * unused)
|
||||
|
@ -479,42 +483,57 @@ add_id3v2frame_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
|
|||
guint i;
|
||||
|
||||
for (i = 0; i < num_tags; ++i) {
|
||||
const GValue *val;
|
||||
GstSample *sample;
|
||||
GstBuffer *buf;
|
||||
GstCaps *caps;
|
||||
|
||||
val = gst_tag_list_get_value_index (list, tag, i);
|
||||
buf = gst_value_get_buffer (val);
|
||||
if (!gst_tag_list_get_sample_index (list, tag, i, &sample))
|
||||
continue;
|
||||
|
||||
if (buf && GST_BUFFER_CAPS (buf)) {
|
||||
buf = gst_sample_get_buffer (sample);
|
||||
|
||||
/* FIXME: should use auxiliary sample struct instead of caps for this */
|
||||
caps = gst_sample_get_caps (sample);
|
||||
|
||||
if (buf && caps) {
|
||||
GstStructure *s;
|
||||
gint version = 0;
|
||||
|
||||
s = gst_caps_get_structure (GST_BUFFER_CAPS (buf), 0);
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
/* We can only add it if this private buffer is for the same ID3 version,
|
||||
because we don't understand the contents at all. */
|
||||
if (s && gst_structure_get_int (s, "version", &version) &&
|
||||
version == id3v2tag->major_version) {
|
||||
GstId3v2Frame frame;
|
||||
GstMapInfo mapinfo;
|
||||
gchar frame_id[5];
|
||||
guint16 flags;
|
||||
guint8 *data = GST_BUFFER_DATA (buf);
|
||||
gint size = GST_BUFFER_SIZE (buf);
|
||||
guint8 *data;
|
||||
gint size;
|
||||
|
||||
if (size < 10) /* header size */
|
||||
return;
|
||||
if (!gst_buffer_map (buf, &mapinfo, GST_MAP_READ))
|
||||
continue;
|
||||
|
||||
/* We only reach here if the frame version matches the muxer. Since the
|
||||
muxer only does v2.3 or v2.4, the frame must be one of those - and
|
||||
so the frame header is the same format */
|
||||
memcpy (frame_id, data, 4);
|
||||
frame_id[4] = 0;
|
||||
flags = GST_READ_UINT16_BE (data + 8);
|
||||
size = mapinfo.size;
|
||||
data = mapinfo.data;
|
||||
|
||||
id3v2_frame_init (&frame, frame_id, flags);
|
||||
id3v2_frame_write_bytes (&frame, data + 10, size - 10);
|
||||
if (size >= 10) { /* header size */
|
||||
/* We only get here if the frame version matches the muxer. Since the
|
||||
* muxer only does v2.3 or v2.4, the frame must be one of those - and
|
||||
* so the frame header is the same format */
|
||||
memcpy (frame_id, data, 4);
|
||||
frame_id[4] = 0;
|
||||
flags = GST_READ_UINT16_BE (data + 8);
|
||||
|
||||
g_array_append_val (id3v2tag->frames, frame);
|
||||
GST_DEBUG ("Added unparsed tag with %d bytes", size);
|
||||
id3v2_frame_init (&frame, frame_id, flags);
|
||||
id3v2_frame_write_bytes (&frame, data + 10, size - 10);
|
||||
|
||||
g_array_append_val (id3v2tag->frames, frame);
|
||||
GST_DEBUG ("Added unparsed tag with %d bytes", size);
|
||||
gst_buffer_unmap (buf, &mapinfo);
|
||||
} else {
|
||||
GST_WARNING ("Short ID3v2 frame");
|
||||
}
|
||||
} else {
|
||||
GST_WARNING ("Discarding unrecognised ID3 tag for different ID3 "
|
||||
"version");
|
||||
|
@ -687,25 +706,29 @@ add_image_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
|
|||
guint n;
|
||||
|
||||
for (n = 0; n < num_tags; ++n) {
|
||||
const GValue *val;
|
||||
GstSample *sample;
|
||||
GstBuffer *image;
|
||||
GstCaps *caps;
|
||||
|
||||
GST_DEBUG ("image %u/%u", n + 1, num_tags);
|
||||
|
||||
val = gst_tag_list_get_value_index (list, tag, n);
|
||||
image = gst_value_get_buffer (val);
|
||||
if (!gst_tag_list_get_sample_index (list, tag, n, &sample))
|
||||
continue;
|
||||
|
||||
if (GST_IS_BUFFER (image) && GST_BUFFER_SIZE (image) > 0 &&
|
||||
GST_BUFFER_CAPS (image) != NULL &&
|
||||
!gst_caps_is_empty (GST_BUFFER_CAPS (image))) {
|
||||
image = gst_sample_get_buffer (sample);
|
||||
caps = gst_sample_get_caps (sample);
|
||||
|
||||
if (image != NULL && gst_buffer_get_size (image) > 0 &&
|
||||
caps != NULL && !gst_caps_is_empty (caps)) {
|
||||
const gchar *mime_type;
|
||||
GstStructure *s;
|
||||
|
||||
s = gst_caps_get_structure (GST_BUFFER_CAPS (image), 0);
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
mime_type = gst_structure_get_name (s);
|
||||
if (mime_type != NULL) {
|
||||
const gchar *desc;
|
||||
GstId3v2Frame frame;
|
||||
GstMapInfo mapinfo;
|
||||
int encoding;
|
||||
|
||||
/* APIC frame specifies "-->" if we're providing a URL to the image
|
||||
|
@ -713,8 +736,8 @@ add_image_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
|
|||
if (strcmp (mime_type, "text/uri-list") == 0)
|
||||
mime_type = "-->";
|
||||
|
||||
GST_DEBUG ("Attaching picture of %u bytes and mime type %s",
|
||||
GST_BUFFER_SIZE (image), mime_type);
|
||||
GST_DEBUG ("Attaching picture of %" G_GSIZE_FORMAT " bytes and "
|
||||
"mime type %s", gst_buffer_get_size (image), mime_type);
|
||||
|
||||
id3v2_frame_init (&frame, "APIC", 0);
|
||||
|
||||
|
@ -734,14 +757,17 @@ add_image_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
|
|||
|
||||
id3v2_frame_write_string (&frame, encoding, desc, TRUE);
|
||||
|
||||
id3v2_frame_write_bytes (&frame, GST_BUFFER_DATA (image),
|
||||
GST_BUFFER_SIZE (image));
|
||||
|
||||
g_array_append_val (id3v2tag->frames, frame);
|
||||
if (gst_buffer_map (image, &mapinfo, GST_MAP_READ)) {
|
||||
id3v2_frame_write_bytes (&frame, mapinfo.data, mapinfo.size);
|
||||
g_array_append_val (id3v2tag->frames, frame);
|
||||
gst_buffer_unmap (image, &mapinfo);
|
||||
} else {
|
||||
GST_WARNING ("Couldn't map image tag buffer");
|
||||
id3v2_frame_unset (&frame);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GST_WARNING ("NULL image or no caps on image buffer (%p, caps=%"
|
||||
GST_PTR_FORMAT ")", image, (image) ? GST_BUFFER_CAPS (image) : NULL);
|
||||
GST_WARNING ("no image or caps: %p, caps=%" GST_PTR_FORMAT, image, caps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -839,28 +865,32 @@ add_date_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
|
|||
else
|
||||
frame_id = "TDRC";
|
||||
|
||||
GST_LOG ("Adding date frame");
|
||||
GST_LOG ("Adding date time frame");
|
||||
|
||||
strings = g_new0 (gchar *, num_tags + 1);
|
||||
for (n = 0; n < num_tags; ++n) {
|
||||
GDate *date = NULL;
|
||||
GstDateTime *dt = NULL;
|
||||
guint year;
|
||||
gchar *s;
|
||||
|
||||
if (gst_tag_list_get_date_index (list, tag, n, &date) && date != NULL) {
|
||||
GDateYear year;
|
||||
gchar *s;
|
||||
if (!gst_tag_list_get_date_time_index (list, tag, n, &dt) || dt == NULL)
|
||||
continue;
|
||||
|
||||
year = g_date_get_year (date);
|
||||
if (year > 500 && year < 2100) {
|
||||
s = g_strdup_printf ("%u", year);
|
||||
GST_LOG ("%s[%u] = '%s'", tag, n, s);
|
||||
strings[i] = s;
|
||||
i++;
|
||||
} else {
|
||||
GST_WARNING ("invalid year %u, skipping", year);
|
||||
}
|
||||
|
||||
g_date_free (date);
|
||||
year = gst_date_time_get_year (dt);
|
||||
if (year > 500 && year < 2100) {
|
||||
s = g_strdup_printf ("%u", year);
|
||||
GST_LOG ("%s[%u] = '%s'", tag, n, s);
|
||||
strings[i] = s;
|
||||
i++;
|
||||
} else {
|
||||
GST_WARNING ("invalid year %u, skipping", year);
|
||||
}
|
||||
|
||||
if (gst_date_time_has_month (dt)) {
|
||||
if (id3v2tag->major_version == 3)
|
||||
GST_FIXME ("write TDAT and possibly also TIME frame");
|
||||
}
|
||||
gst_date_time_free (dt);
|
||||
}
|
||||
|
||||
if (strings[0] != NULL) {
|
||||
|
@ -1089,7 +1119,7 @@ static const struct
|
|||
/* Up to here, all the frame ids and contents have been the same between
|
||||
versions 2.3 and 2.4. The rest of them differ... */
|
||||
/* Date (in ID3v2.3, this is a TYER tag. In v2.4, it's a TDRC tag */
|
||||
GST_TAG_DATE, add_date_tag, NULL}, {
|
||||
GST_TAG_DATE_TIME, add_date_tag, NULL}, {
|
||||
|
||||
/* Replaygain data (not really supported in 2.3, we use an experimental
|
||||
tag there) */
|
||||
|
@ -1159,7 +1189,7 @@ id3_mux_render_v2_tag (GstTagMux * mux, const GstTagList * taglist, int version)
|
|||
|
||||
/* Create buffer with tag */
|
||||
buf = id3v2_tag_to_buffer (&tag);
|
||||
GST_LOG_OBJECT (mux, "tag size = %d bytes", GST_BUFFER_SIZE (buf));
|
||||
GST_LOG_OBJECT (mux, "tag size = %d bytes", (int) gst_buffer_get_size (buf));
|
||||
|
||||
id3v2_tag_unset (&tag);
|
||||
|
||||
|
@ -1265,6 +1295,7 @@ track_number_convert (const GstTagList * list, const gchar * tag,
|
|||
}
|
||||
}
|
||||
|
||||
/* FIXME: get rid of silly table */
|
||||
static const struct
|
||||
{
|
||||
const gchar *gst_tag;
|
||||
|
@ -1286,11 +1317,15 @@ static const struct
|
|||
GstBuffer *
|
||||
id3_mux_render_v1_tag (GstTagMux * mux, const GstTagList * taglist)
|
||||
{
|
||||
GstBuffer *buf = gst_buffer_new_and_alloc (ID3_V1_TAG_SIZE);
|
||||
guint8 *data = GST_BUFFER_DATA (buf);
|
||||
GstMapInfo info;
|
||||
GstBuffer *buf;
|
||||
guint8 *data;
|
||||
gboolean wrote_tag = FALSE;
|
||||
int i;
|
||||
|
||||
buf = gst_buffer_new_allocate (NULL, ID3_V1_TAG_SIZE, NULL);
|
||||
gst_buffer_map (buf, &info, GST_MAP_WRITE);
|
||||
data = info.data;
|
||||
memset (data, 0, ID3_V1_TAG_SIZE);
|
||||
|
||||
data[0] = 'T';
|
||||
|
@ -1305,6 +1340,8 @@ id3_mux_render_v1_tag (GstTagMux * mux, const GstTagList * taglist)
|
|||
v1_funcs[i].length, &wrote_tag);
|
||||
}
|
||||
|
||||
gst_buffer_unmap (buf, &info);
|
||||
|
||||
if (!wrote_tag) {
|
||||
GST_WARNING_OBJECT (mux, "no ID3v1 tag written (no suitable tags found)");
|
||||
gst_buffer_unref (buf);
|
||||
|
|
Loading…
Reference in a new issue