flacenc: add TOC support

Add TOC as embedded cuesheets in flac files.

https://bugzilla.gnome.org/show_bug.cgi?id=54089
This commit is contained in:
Anton Belka 2012-07-26 16:19:57 +03:00 committed by Sebastian Dröge
parent 2d179ebf90
commit fa86bf26df
2 changed files with 120 additions and 6 deletions

View file

@ -140,7 +140,9 @@ GST_DEBUG_CATEGORY_STATIC (flacenc_debug);
#define gst_flac_enc_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstFlacEnc, gst_flac_enc, GST_TYPE_AUDIO_ENCODER,
G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL)
G_IMPLEMENT_INTERFACE (GST_TYPE_TOC_SETTER, NULL)
);
static gboolean gst_flac_enc_start (GstAudioEncoder * enc);
static gboolean gst_flac_enc_stop (GstAudioEncoder * enc);
@ -415,6 +417,7 @@ gst_flac_enc_start (GstAudioEncoder * enc)
flacenc->offset = 0;
flacenc->eos = FALSE;
flacenc->tags = gst_tag_list_new_empty ();
flacenc->toc = NULL;
return TRUE;
}
@ -427,6 +430,9 @@ gst_flac_enc_stop (GstAudioEncoder * enc)
GST_DEBUG_OBJECT (enc, "stop");
gst_tag_list_unref (flacenc->tags);
flacenc->tags = NULL;
if (flacenc->toc)
gst_toc_unref (flacenc->toc);
flacenc->toc = NULL;
if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
FLAC__STREAM_ENCODER_UNINITIALIZED) {
flacenc->stopped = TRUE;
@ -441,6 +447,9 @@ gst_flac_enc_stop (GstAudioEncoder * enc)
if (flacenc->meta[2])
FLAC__metadata_object_delete (flacenc->meta[2]);
if (flacenc->meta[3])
FLAC__metadata_object_delete (flacenc->meta[3]);
g_free (flacenc->meta);
flacenc->meta = NULL;
}
@ -449,6 +458,7 @@ gst_flac_enc_stop (GstAudioEncoder * enc)
flacenc->headers = NULL;
gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
gst_toc_setter_reset (GST_TOC_SETTER (enc));
return TRUE;
}
@ -481,17 +491,94 @@ add_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
g_list_free (comments);
}
static gboolean
add_cuesheet (const GstToc * toc, guint sample_rate,
FLAC__StreamMetadata * cuesheet)
{
gint8 track_num = 0;
gint64 start, stop;
gchar *isrc = NULL;
const gchar *is_legal;
GList *list;
GstTagList *tags;
GstTocEntry *entry;
FLAC__StreamMetadata_CueSheet *cs;
FLAC__StreamMetadata_CueSheet_Track *track;
cs = &cuesheet->data.cue_sheet;
if (!cs)
return FALSE;
/* check if the TOC entries is valid */
list = gst_toc_get_entries (toc);
while (list) {
entry = list->data;
if (!gst_toc_entry_is_sequence (entry))
return FALSE;
list = g_list_next (list);
}
/* add tracks in cuesheet */
list = gst_toc_get_entries (toc);
while (list) {
entry = list->data;
gst_toc_entry_get_start_stop_times (entry, &start, &stop);
tags = gst_toc_entry_get_tags (entry);
if (tags)
gst_tag_list_get_string (tags, GST_TAG_ISRC, &isrc);
track = FLAC__metadata_object_cuesheet_track_new ();
track->offset =
(FLAC__uint64) gst_util_uint64_scale_round (start, sample_rate,
GST_SECOND);
track->number = (FLAC__byte) track_num + 1;
if (isrc)
strcpy (track->isrc, isrc);
if (track->number <= 0)
return FALSE;
if (!FLAC__metadata_object_cuesheet_insert_track (cuesheet, track_num,
track, FALSE))
return FALSE;
if (!FLAC__metadata_object_cuesheet_track_insert_blank_index (cuesheet,
track_num, 0))
return FALSE;
track_num++;
list = g_list_next (list);
}
if (cs->num_tracks <= 0)
return FALSE;
/* add lead-out track in cuesheet */
track = FLAC__metadata_object_cuesheet_track_new ();
track->offset =
(FLAC__uint64) gst_util_uint64_scale_round (stop, sample_rate,
GST_SECOND);
track->number = 255;
if (!FLAC__metadata_object_cuesheet_insert_track (cuesheet, cs->num_tracks,
track, FALSE))
return FALSE;
/* check if the cuesheet is valid */
if (!FLAC__metadata_object_cuesheet_is_legal (cuesheet, FALSE, &is_legal)) {
g_warning ("%s\n", is_legal);
return FALSE;
}
return TRUE;
}
static void
gst_flac_enc_set_metadata (GstFlacEnc * flacenc, guint64 total_samples)
gst_flac_enc_set_metadata (GstFlacEnc * flacenc, GstAudioInfo * info,
guint64 total_samples)
{
const GstTagList *user_tags;
GstTagList *copy;
gint entries = 1;
gint n_images, n_preview_images;
GstAudioInfo *info =
gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (flacenc));
FLAC__StreamMetadata *cuesheet;
g_return_if_fail (flacenc != NULL);
user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (flacenc));
if ((flacenc->tags == NULL) && (user_tags == NULL)) {
return;
@ -502,12 +589,26 @@ gst_flac_enc_set_metadata (GstFlacEnc * flacenc, guint64 total_samples)
n_preview_images = gst_tag_list_get_tag_size (copy, GST_TAG_PREVIEW_IMAGE);
flacenc->meta =
g_new0 (FLAC__StreamMetadata *, 3 + n_images + n_preview_images);
g_new0 (FLAC__StreamMetadata *, 4 + n_images + n_preview_images);
flacenc->meta[0] =
FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT);
gst_tag_list_foreach (copy, add_one_tag, flacenc);
if (!flacenc->toc)
flacenc->toc = gst_toc_setter_get_toc (GST_TOC_SETTER (flacenc));
if (flacenc->toc) {
cuesheet = FLAC__metadata_object_new (FLAC__METADATA_TYPE_CUESHEET);
if (add_cuesheet (flacenc->toc, GST_AUDIO_INFO_RATE (info), cuesheet)) {
flacenc->meta[entries] = cuesheet;
entries++;
} else {
FLAC__metadata_object_delete (cuesheet);
flacenc->meta[entries] = NULL;
}
}
if (n_images + n_preview_images > 0) {
GstSample *sample;
GstBuffer *buffer;
@ -727,7 +828,7 @@ gst_flac_enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
FLAC__stream_encoder_set_total_samples_estimate (flacenc->encoder,
MIN (total_samples, G_GUINT64_CONSTANT (0x0FFFFFFFFF)));
gst_flac_enc_set_metadata (flacenc, total_samples);
gst_flac_enc_set_metadata (flacenc, info, total_samples);
/* callbacks clear to go now;
* write callbacks receives headers during init */
@ -1094,6 +1195,7 @@ gst_flac_enc_sink_event (GstAudioEncoder * enc, GstEvent * event)
{
GstFlacEnc *flacenc;
GstTagList *taglist;
GstToc *toc;
gboolean ret = FALSE;
flacenc = GST_FLAC_ENC (enc);
@ -1115,6 +1217,17 @@ gst_flac_enc_sink_event (GstAudioEncoder * enc, GstEvent * event)
}
ret = GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (enc, event);
break;
case GST_EVENT_TOC:
gst_event_parse_toc (event, &toc, NULL);
if (toc) {
if (flacenc->toc != toc) {
if (flacenc->toc)
gst_toc_unref (flacenc->toc);
flacenc->toc = toc;
}
}
ret = GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (enc, event);
break;
default:
ret = GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (enc, event);
break;

View file

@ -57,6 +57,7 @@ struct _GstFlacEnc {
FLAC__StreamMetadata **meta;
GstTagList * tags;
GstToc * toc;
gboolean eos;
/* queue headers until we have them all so we can add streamheaders to caps */