summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim-Philipp Müller <tim.muller@collabora.co.uk>2009-04-24 01:51:35 +0100
committerTim-Philipp Müller <tim.muller@collabora.co.uk>2009-04-24 01:58:23 +0100
commita85d7b7059d1955666fe0b93f5dcacdc3e02426b (patch)
treefe7e23c850c0dcb10af88c0cb503cf6e42df3be2
parent19117a39fe32d19cdab89f07aefe9b0ffcff2010 (diff)
id3demux: parse unsynchronised tags properly
We didn't handle unsynchronization at all up to now, which might have caused frames to not be extracted - esp. frames after an APIC picture frame. Fixes #577468.
-rw-r--r--gst/id3demux/id3tags.c59
1 files changed, 58 insertions, 1 deletions
diff --git a/gst/id3demux/id3tags.c b/gst/id3demux/id3tags.c
index f2e06344a..1d511f336 100644
--- a/gst/id3demux/id3tags.c
+++ b/gst/id3demux/id3tags.c
@@ -97,12 +97,40 @@ id3demux_calc_id3v2_tag_size (GstBuffer * buf)
return size;
}
+static guint8 *
+id3demux_ununsync_data (const guint8 * unsync_data, guint32 * size)
+{
+ const guint8 *end;
+ guint8 *out, *uu;
+ guint out_size;
+
+ uu = out = g_malloc (*size);
+
+ for (end = unsync_data + *size; unsync_data < end - 1; ++unsync_data, ++uu) {
+ *uu = *unsync_data;
+ if (G_UNLIKELY (*unsync_data == 0xff && *(unsync_data + 1) == 0x00))
+ ++unsync_data;
+ }
+
+ /* take care of last byte (if last two bytes weren't 0xff 0x00) */
+ if (unsync_data < end) {
+ *uu = *unsync_data;
+ ++uu;
+ }
+
+ out_size = uu - out;
+ GST_DEBUG ("size after un-unsyncing: %u (before: %u)", out_size, *size);
+
+ *size = out_size;
+ return out;
+}
+
/* caller must pass buffer with full ID3 tag */
ID3TagsResult
id3demux_read_id3v2_tag (GstBuffer * buffer, guint * id3v2_size,
GstTagList ** tags)
{
- guint8 *data;
+ guint8 *data, *uu_data = NULL;
guint read_size;
ID3TagsWorking work;
guint8 flags;
@@ -134,6 +162,12 @@ id3demux_read_id3v2_tag (GstBuffer * buffer, guint * id3v2_size,
return ID3TAGS_READ_TAG;
}
+ GST_DEBUG ("ID3v2 header flags: %s %s %s %s",
+ (flags & ID3V2_HDR_FLAG_UNSYNC) ? "UNSYNC" : "",
+ (flags & ID3V2_HDR_FLAG_EXTHDR) ? "EXTENDED_HEADER" : "",
+ (flags & ID3V2_HDR_FLAG_EXPERIMENTAL) ? "EXPERIMENTAL" : "",
+ (flags & ID3V2_HDR_FLAG_FOOTER) ? "FOOTER" : "");
+
/* This shouldn't really happen! Caller should have checked first */
if (GST_BUFFER_SIZE (buffer) < read_size) {
GST_DEBUG
@@ -148,6 +182,8 @@ id3demux_read_id3v2_tag (GstBuffer * buffer, guint * id3v2_size,
g_return_val_if_fail (tags != NULL, ID3TAGS_READ_TAG);
+ GST_MEMDUMP ("ID3v2 tag", GST_BUFFER_DATA (buffer), read_size);
+
memset (&work, 0, sizeof (ID3TagsWorking));
work.buffer = buffer;
work.hdr.version = version;
@@ -159,10 +195,20 @@ id3demux_read_id3v2_tag (GstBuffer * buffer, guint * id3v2_size,
else
work.hdr.frame_data_size = read_size - ID3V2_HDR_SIZE;
+ if ((flags & ID3V2_HDR_FLAG_UNSYNC)) {
+ GST_DEBUG ("Un-unsyncing entire tag");
+ uu_data = id3demux_ununsync_data (work.hdr.frame_data,
+ &work.hdr.frame_data_size);
+ work.hdr.frame_data = uu_data;
+ GST_MEMDUMP ("ID3v2 tag (un-unsyced)", uu_data, work.hdr.frame_data_size);
+ }
+
result = id3demux_id3v2_frames_to_tag_list (&work, work.hdr.frame_data_size);
*tags = work.tags;
+ g_free (uu_data);
+
return result;
}
@@ -425,6 +471,17 @@ id3demux_id3v2_frames_to_tag_list (ID3TagsWorking * work, guint size)
frame_size, work->hdr.frame_data + frame_hdr_size + frame_size - start,
work->hdr.frame_data + frame_hdr_size + frame_size - start,
obsolete_id);
+#define flag_string(flag,str) \
+ ((frame_flags & (flag)) ? (str) : "")
+ GST_LOG ("Frame header flags: 0x%04x %s %s %s %s %s %s %s", frame_flags,
+ flag_string (ID3V2_FRAME_STATUS_FRAME_ALTER_PRESERVE, "ALTER_PRESERVE"),
+ flag_string (ID3V2_FRAME_STATUS_READONLY, "READONLY"),
+ flag_string (ID3V2_FRAME_FORMAT_GROUPING_ID, "GROUPING_ID"),
+ flag_string (ID3V2_FRAME_FORMAT_COMPRESSION, "COMPRESSION"),
+ flag_string (ID3V2_FRAME_FORMAT_ENCRYPTION, "ENCRYPTION"),
+ flag_string (ID3V2_FRAME_FORMAT_UNSYNCHRONISATION, "UNSYNC"),
+ flag_string (ID3V2_FRAME_FORMAT_DATA_LENGTH_INDICATOR, "LENGHT_IND"));
+#undef flag_str
#endif
if (!obsolete_id) {