diff options
-rw-r--r-- | gst/id3demux/id3tags.c | 7 | ||||
-rw-r--r-- | gst/id3demux/id3tags.h | 2 | ||||
-rw-r--r-- | gst/id3demux/id3v2frames.c | 28 | ||||
-rw-r--r-- | tests/check/elements/id3demux.c | 54 | ||||
-rw-r--r-- | tests/files/Makefile.am | 1 | ||||
-rw-r--r-- | tests/files/id3-588148-unsynced-v24.tag | bin | 0 -> 39000 bytes |
6 files changed, 80 insertions, 12 deletions
diff --git a/gst/id3demux/id3tags.c b/gst/id3demux/id3tags.c index 1d511f33..96d25521 100644 --- a/gst/id3demux/id3tags.c +++ b/gst/id3demux/id3tags.c @@ -97,7 +97,7 @@ id3demux_calc_id3v2_tag_size (GstBuffer * buf) return size; } -static guint8 * +guint8 * id3demux_ununsync_data (const guint8 * unsync_data, guint32 * size) { const guint8 *end; @@ -195,7 +195,10 @@ 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)) { + /* in v2.3 the frame sizes are not syncsafe, so the entire tag had to be + * unsynced. In v2.4 the frame sizes are syncsafe so it's just the frame + * data that needs un-unsyncing, but not the frame headers. */ + if ((flags & ID3V2_HDR_FLAG_UNSYNC) != 0 && ID3V2_VER_MAJOR (version) <= 3) { GST_DEBUG ("Un-unsyncing entire tag"); uu_data = id3demux_ununsync_data (work.hdr.frame_data, &work.hdr.frame_data_size); diff --git a/gst/id3demux/id3tags.h b/gst/id3demux/id3tags.h index b5bc950d..14a42de3 100644 --- a/gst/id3demux/id3tags.h +++ b/gst/id3demux/id3tags.h @@ -115,6 +115,8 @@ enum { /* From id3v2frames.c */ gboolean id3demux_id3v2_parse_frame (ID3TagsWorking *work); +guint8 * id3demux_ununsync_data (const guint8 * unsync_data, guint32 * size); + G_END_DECLS #endif diff --git a/gst/id3demux/id3v2frames.c b/gst/id3demux/id3v2frames.c index 377d84cf..a0331ef3 100644 --- a/gst/id3demux/id3v2frames.c +++ b/gst/id3demux/id3v2frames.c @@ -73,6 +73,7 @@ id3demux_id3v2_parse_frame (ID3TagsWorking * work) guint frame_data_size = work->cur_frame_size; gchar *tag_str = NULL; GArray *tag_fields = NULL; + guint8 *uu_data = NULL; #ifdef HAVE_ZLIB guint8 *uncompressed_data = NULL; @@ -86,17 +87,14 @@ id3demux_id3v2_parse_frame (ID3TagsWorking * work) } } - /* Can't handle encrypted frames right now */ + /* Can't handle encrypted frames right now (in case we ever do, we'll have + * to do the decryption after the un-unsynchronisation and decompression, + * not here) */ if (work->frame_flags & ID3V2_FRAME_FORMAT_ENCRYPTION) { GST_WARNING ("Encrypted frames are not supported"); return FALSE; } - if (work->frame_flags & ID3V2_FRAME_FORMAT_UNSYNCHRONISATION) { - GST_WARNING ("ID3v2 frame with unsupported unsynchronisation applied. " - "May fail badly"); - } - tag_name = gst_tag_from_id3_tag (work->frame_id); if (tag_name == NULL && strncmp (work->frame_id, "RVA2", 4) != 0 && @@ -120,6 +118,19 @@ id3demux_id3v2_parse_frame (ID3TagsWorking * work) } } + /* in v2.3 the frame sizes are not syncsafe, so the entire tag had to be + * unsynced. In v2.4 the frame sizes are syncsafe so it's just the frame + * data that needs un-unsyncing, but not the frame headers. */ + if (ID3V2_VER_MAJOR (work->hdr.version) == 4) { + if ((work->hdr.flags & ID3V2_HDR_FLAG_UNSYNC) != 0 || + ((work->frame_flags & ID3V2_FRAME_FORMAT_UNSYNCHRONISATION) != 0)) { + GST_DEBUG ("Un-unsyncing frame %s", work->frame_id); + uu_data = id3demux_ununsync_data (frame_data, &frame_data_size); + frame_data = uu_data; + GST_MEMDUMP ("ID3v2 frame (un-unsyced)", frame_data, frame_data_size); + } + } + work->parse_size = frame_data_size; if (work->frame_flags & ID3V2_FRAME_FORMAT_COMPRESSION) { @@ -134,6 +145,7 @@ id3demux_id3v2_parse_frame (ID3TagsWorking * work) if (uncompress (dest, &destSize, src, frame_data_size) != Z_OK) { g_free (uncompressed_data); + g_free (uu_data); return FALSE; } if (destSize != work->parse_size) { @@ -141,12 +153,14 @@ id3demux_id3v2_parse_frame (ID3TagsWorking * work) ("Decompressing ID3v2 frame %s did not produce expected size %d bytes (got %lu)", tag_name, work->parse_size, destSize); g_free (uncompressed_data); + g_free (uu_data); return FALSE; } work->parse_data = uncompressed_data; #else GST_WARNING ("Compressed ID3v2 tag frame could not be decompressed" " because gstid3demux was compiled without zlib support"); + g_free (uu_data); return FALSE; #endif } else { @@ -209,6 +223,8 @@ id3demux_id3v2_parse_frame (ID3TagsWorking * work) free_tag_strings (tag_fields); } + g_free (uu_data); + return result; } diff --git a/tests/check/elements/id3demux.c b/tests/check/elements/id3demux.c index ef1d4538..724461bd 100644 --- a/tests/check/elements/id3demux.c +++ b/tests/check/elements/id3demux.c @@ -198,7 +198,7 @@ GST_START_TEST (test_wcop) GST_END_TEST; static void -check_unsync (const GstTagList * tags, const gchar * file) +check_unsync_v23 (const GstTagList * tags, const gchar * file) { gchar *album = NULL; gchar *title = NULL; @@ -220,9 +220,54 @@ check_unsync (const GstTagList * tags, const gchar * file) g_free (artist); } -GST_START_TEST (test_unsync) +GST_START_TEST (test_unsync_v23) { - run_check_for_file ("id3-577468-unsynced-tag.tag", check_unsync); + run_check_for_file ("id3-577468-unsynced-tag.tag", check_unsync_v23); +} + +GST_END_TEST; + +static void +check_unsync_v24 (const GstTagList * tags, const gchar * file) +{ + const GValue *val; + GstBuffer *buf; + gchar *album = NULL; + gchar *title = NULL; + gchar *artist = NULL; + + fail_unless (gst_tag_list_get_string (tags, GST_TAG_TITLE, &title)); + fail_unless (title != NULL); + fail_unless_equals_string (title, "Starlight"); + g_free (title); + + fail_unless (gst_tag_list_get_string (tags, GST_TAG_ALBUM, &album)); + fail_unless (album != NULL); + fail_unless_equals_string (album, "L'albumRockVol.4 CD1"); + g_free (album); + + fail_unless (gst_tag_list_get_string (tags, GST_TAG_ARTIST, &artist)); + fail_unless (artist != NULL); + fail_unless_equals_string (artist, "Muse"); + g_free (artist); + + val = gst_tag_list_get_value_index (tags, GST_TAG_IMAGE, 0); + fail_unless (val != NULL); + fail_unless (GST_VALUE_HOLDS_BUFFER (val)); + buf = gst_value_get_buffer (val); + fail_unless (buf != NULL); + fail_unless (GST_BUFFER_CAPS (buf) != NULL); + fail_unless_equals_int (GST_BUFFER_SIZE (buf), 38022); + /* check for jpeg start/end markers */ + fail_unless_equals_int (GST_BUFFER_DATA (buf)[0], 0xff); + fail_unless_equals_int (GST_BUFFER_DATA (buf)[1], 0xd8); + fail_unless_equals_int (GST_BUFFER_DATA (buf)[38020], 0xff); + fail_unless_equals_int (GST_BUFFER_DATA (buf)[38021], 0xd9); +} + +GST_START_TEST (test_unsync_v24) +{ + run_check_for_file ("id3-588148-unsynced-v24.tag", check_unsync_v24); } GST_END_TEST; @@ -236,7 +281,8 @@ id3demux_suite (void) suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_tdat_tyer); tcase_add_test (tc_chain, test_wcop); - tcase_add_test (tc_chain, test_unsync); + tcase_add_test (tc_chain, test_unsync_v23); + tcase_add_test (tc_chain, test_unsync_v24); return s; } diff --git a/tests/files/Makefile.am b/tests/files/Makefile.am index 73ab4f2d..a0a28293 100644 --- a/tests/files/Makefile.am +++ b/tests/files/Makefile.am @@ -5,6 +5,7 @@ EXTRA_DIST = \ id3-407349-2.tag \ id3-447000-wcop.tag \ id3-577468-unsynced-tag.tag \ + id3-588148-unsynced-v24.tag \ pcm16sine.flv \ test-cert.pem \ test-key.pem diff --git a/tests/files/id3-588148-unsynced-v24.tag b/tests/files/id3-588148-unsynced-v24.tag Binary files differnew file mode 100644 index 00000000..099d930e --- /dev/null +++ b/tests/files/id3-588148-unsynced-v24.tag |