mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 09:10:36 +00:00
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:
parent
2d179ebf90
commit
fa86bf26df
2 changed files with 120 additions and 6 deletions
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue