flacparse: add TOC support

Add support embedded cuesheets in flac files.
Parsing METADATA_BLOCK_CUESHEET as TOC.

https://bugzilla.gnome.org/show_bug.cgi?id=540891
This commit is contained in:
Anton Belka 2012-07-05 14:15:25 +03:00 committed by Sebastian Dröge
parent a94d5d9f3b
commit ffc204e6bd
2 changed files with 121 additions and 1 deletions

View file

@ -295,6 +295,10 @@ gst_flac_parse_finalize (GObject * object)
gst_tag_list_free (flacparse->tags);
flacparse->tags = NULL;
}
if (flacparse->toc) {
gst_toc_unref (flacparse->toc);
flacparse->toc = NULL;
}
g_list_foreach (flacparse->headers, (GFunc) gst_mini_object_unref, NULL);
g_list_free (flacparse->headers);
@ -346,6 +350,10 @@ gst_flac_parse_stop (GstBaseParse * parse)
gst_tag_list_free (flacparse->tags);
flacparse->tags = NULL;
}
if (flacparse->toc) {
gst_toc_unref (flacparse->toc);
flacparse->toc = NULL;
}
g_list_foreach (flacparse->headers, (GFunc) gst_mini_object_unref, NULL);
g_list_free (flacparse->headers);
@ -969,6 +977,108 @@ gst_flac_parse_handle_vorbiscomment (GstFlacParse * flacparse,
return TRUE;
}
static gboolean
gst_flac_parse_handle_cuesheet (GstFlacParse * flacparse, GstBuffer * buffer)
{
GstByteReader reader;
GstMapInfo map;
guint i, j;
guint8 n_tracks, track_num, index;
guint64 offset;
gint64 start, stop;
gchar *id;
gchar isrc[13];
GstTagList *tags;
GstToc *toc;
GstTocEntry *cur_entry = NULL, *prev_entry = NULL;
gst_buffer_map (buffer, &map, GST_MAP_READ);
gst_byte_reader_init (&reader, map.data, map.size);
toc = gst_toc_new ();
/* skip 4 bytes METADATA_BLOCK_HEADER */
/* http://flac.sourceforge.net/format.html#metadata_block_header */
if (!gst_byte_reader_skip (&reader, 4))
goto error;
/* skip 395 bytes from METADATA_BLOCK_CUESHEET */
/* http://flac.sourceforge.net/format.html#metadata_block_cuesheet */
if (!gst_byte_reader_skip (&reader, 395))
goto error;
if (!gst_byte_reader_get_uint8 (&reader, &n_tracks))
goto error;
/* CUESHEET_TRACK */
/* http://flac.sourceforge.net/format.html#cuesheet_track */
for (i = 0; i < n_tracks; i++) {
if (!gst_byte_reader_get_uint64_be (&reader, &offset))
goto error;
if (!gst_byte_reader_get_uint8 (&reader, &track_num))
goto error;
if (!gst_byte_reader_skip (&reader, 12))
goto error;
memcpy (isrc, map.data + gst_byte_reader_get_pos (&reader), 12);
/* skip 14 bytes from CUESHEET_TRACK */
if (!gst_byte_reader_skip (&reader, 14))
goto error;
if (!gst_byte_reader_get_uint8 (&reader, &index))
goto error;
/* add tracks in TOC */
/* lead-out tack has number 170 or 255 */
if (track_num != 170 && track_num != 255) {
prev_entry = cur_entry;
/* previous track stop time = current track start time */
if (prev_entry != NULL) {
gst_toc_entry_get_start_stop_times (prev_entry, &start, NULL);
stop =
gst_util_uint64_scale_round (offset, GST_SECOND,
flacparse->samplerate);
gst_toc_entry_set_start_stop_times (prev_entry, start, stop);
}
id = g_strdup_printf ("%08x", track_num);
cur_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_TRACK, id);
g_free (id);
start =
gst_util_uint64_scale_round (offset, GST_SECOND,
flacparse->samplerate);
gst_toc_entry_set_start_stop_times (cur_entry, start, -1);
/* add ISRC as tag in track */
if (strlen (isrc) != 0) {
tags = gst_tag_list_new_empty ();
gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_ISRC, isrc, NULL);
gst_toc_entry_set_tags (cur_entry, tags);
}
gst_toc_append_entry (toc, cur_entry);
/* CUESHEET_TRACK_INDEX */
/* http://flac.sourceforge.net/format.html#cuesheet_track_index */
for (j = 0; j < index; j++) {
if (!gst_byte_reader_skip (&reader, 12))
goto error;
}
} else {
/* set stop time in last track */
stop =
gst_util_uint64_scale_round (offset, GST_SECOND,
flacparse->samplerate);
gst_toc_entry_set_start_stop_times (cur_entry, start, stop);
}
}
/* send data as TOC */
if (!flacparse->toc)
flacparse->toc = toc;
gst_buffer_unmap (buffer, &map);
return TRUE;
error:
GST_ERROR_OBJECT (flacparse, "Error reading data");
gst_buffer_unmap (buffer, &map);
return FALSE;
}
static gboolean
gst_flac_parse_handle_picture (GstFlacParse * flacparse, GstBuffer * buffer)
{
@ -1391,13 +1501,16 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame,
if (!gst_flac_parse_handle_vorbiscomment (flacparse, sbuffer))
goto cleanup;
break;
case 5: /* CUESHEET */
if (!gst_flac_parse_handle_cuesheet (flacparse, sbuffer))
goto cleanup;
break;
case 6: /* PICTURE */
if (!gst_flac_parse_handle_picture (flacparse, sbuffer))
goto cleanup;
break;
case 1: /* PADDING */
case 2: /* APPLICATION */
case 5: /* CUESHEET */
default: /* RESERVED */
break;
}
@ -1516,6 +1629,12 @@ gst_flac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
gst_event_new_tag ("GstParser", flacparse->tags));
flacparse->tags = NULL;
}
/* Push toc */
if (flacparse->toc) {
gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (flacparse),
gst_event_new_toc (flacparse->toc, FALSE));
flacparse->toc = NULL;
}
frame->flags |= GST_BASE_PARSE_FRAME_FLAG_CLIP;

View file

@ -77,6 +77,7 @@ struct _GstFlacParse {
gboolean strategy_checked;
GstTagList *tags;
GstToc *toc;
GList *headers;
GstBuffer *seektable;