mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 05:46:13 +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
|
#define gst_flac_enc_parent_class parent_class
|
||||||
G_DEFINE_TYPE_WITH_CODE (GstFlacEnc, gst_flac_enc, GST_TYPE_AUDIO_ENCODER,
|
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_start (GstAudioEncoder * enc);
|
||||||
static gboolean gst_flac_enc_stop (GstAudioEncoder * enc);
|
static gboolean gst_flac_enc_stop (GstAudioEncoder * enc);
|
||||||
|
@ -415,6 +417,7 @@ gst_flac_enc_start (GstAudioEncoder * enc)
|
||||||
flacenc->offset = 0;
|
flacenc->offset = 0;
|
||||||
flacenc->eos = FALSE;
|
flacenc->eos = FALSE;
|
||||||
flacenc->tags = gst_tag_list_new_empty ();
|
flacenc->tags = gst_tag_list_new_empty ();
|
||||||
|
flacenc->toc = NULL;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -427,6 +430,9 @@ gst_flac_enc_stop (GstAudioEncoder * enc)
|
||||||
GST_DEBUG_OBJECT (enc, "stop");
|
GST_DEBUG_OBJECT (enc, "stop");
|
||||||
gst_tag_list_unref (flacenc->tags);
|
gst_tag_list_unref (flacenc->tags);
|
||||||
flacenc->tags = NULL;
|
flacenc->tags = NULL;
|
||||||
|
if (flacenc->toc)
|
||||||
|
gst_toc_unref (flacenc->toc);
|
||||||
|
flacenc->toc = NULL;
|
||||||
if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
|
if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
|
||||||
FLAC__STREAM_ENCODER_UNINITIALIZED) {
|
FLAC__STREAM_ENCODER_UNINITIALIZED) {
|
||||||
flacenc->stopped = TRUE;
|
flacenc->stopped = TRUE;
|
||||||
|
@ -441,6 +447,9 @@ gst_flac_enc_stop (GstAudioEncoder * enc)
|
||||||
if (flacenc->meta[2])
|
if (flacenc->meta[2])
|
||||||
FLAC__metadata_object_delete (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);
|
g_free (flacenc->meta);
|
||||||
flacenc->meta = NULL;
|
flacenc->meta = NULL;
|
||||||
}
|
}
|
||||||
|
@ -449,6 +458,7 @@ gst_flac_enc_stop (GstAudioEncoder * enc)
|
||||||
flacenc->headers = NULL;
|
flacenc->headers = NULL;
|
||||||
|
|
||||||
gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
|
gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
|
||||||
|
gst_toc_setter_reset (GST_TOC_SETTER (enc));
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -481,17 +491,94 @@ add_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
|
||||||
g_list_free (comments);
|
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
|
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;
|
const GstTagList *user_tags;
|
||||||
GstTagList *copy;
|
GstTagList *copy;
|
||||||
gint entries = 1;
|
gint entries = 1;
|
||||||
gint n_images, n_preview_images;
|
gint n_images, n_preview_images;
|
||||||
GstAudioInfo *info =
|
FLAC__StreamMetadata *cuesheet;
|
||||||
gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (flacenc));
|
|
||||||
|
|
||||||
g_return_if_fail (flacenc != NULL);
|
g_return_if_fail (flacenc != NULL);
|
||||||
|
|
||||||
user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (flacenc));
|
user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (flacenc));
|
||||||
if ((flacenc->tags == NULL) && (user_tags == NULL)) {
|
if ((flacenc->tags == NULL) && (user_tags == NULL)) {
|
||||||
return;
|
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);
|
n_preview_images = gst_tag_list_get_tag_size (copy, GST_TAG_PREVIEW_IMAGE);
|
||||||
|
|
||||||
flacenc->meta =
|
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] =
|
flacenc->meta[0] =
|
||||||
FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
||||||
gst_tag_list_foreach (copy, add_one_tag, flacenc);
|
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) {
|
if (n_images + n_preview_images > 0) {
|
||||||
GstSample *sample;
|
GstSample *sample;
|
||||||
GstBuffer *buffer;
|
GstBuffer *buffer;
|
||||||
|
@ -727,7 +828,7 @@ gst_flac_enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
|
||||||
FLAC__stream_encoder_set_total_samples_estimate (flacenc->encoder,
|
FLAC__stream_encoder_set_total_samples_estimate (flacenc->encoder,
|
||||||
MIN (total_samples, G_GUINT64_CONSTANT (0x0FFFFFFFFF)));
|
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;
|
/* callbacks clear to go now;
|
||||||
* write callbacks receives headers during init */
|
* write callbacks receives headers during init */
|
||||||
|
@ -1094,6 +1195,7 @@ gst_flac_enc_sink_event (GstAudioEncoder * enc, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstFlacEnc *flacenc;
|
GstFlacEnc *flacenc;
|
||||||
GstTagList *taglist;
|
GstTagList *taglist;
|
||||||
|
GstToc *toc;
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
|
|
||||||
flacenc = GST_FLAC_ENC (enc);
|
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);
|
ret = GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (enc, event);
|
||||||
break;
|
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:
|
default:
|
||||||
ret = GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (enc, event);
|
ret = GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (enc, event);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -57,6 +57,7 @@ struct _GstFlacEnc {
|
||||||
FLAC__StreamMetadata **meta;
|
FLAC__StreamMetadata **meta;
|
||||||
|
|
||||||
GstTagList * tags;
|
GstTagList * tags;
|
||||||
|
GstToc * toc;
|
||||||
|
|
||||||
gboolean eos;
|
gboolean eos;
|
||||||
/* queue headers until we have them all so we can add streamheaders to caps */
|
/* queue headers until we have them all so we can add streamheaders to caps */
|
||||||
|
|
Loading…
Reference in a new issue