Use new tagging stuff to read and write flac metadata. Only handles vorbiscomment tags, and not (older) id3v2 tags.
Original commit message from CVS: Use new tagging stuff to read and write flac metadata. Only handles vorbiscomment tags, and not (older) id3v2 tags.
This commit is contained in:
parent
f1d94660c5
commit
b169b0a68f
@ -32,6 +32,10 @@ plugin_init (GstPlugin *plugin)
|
|||||||
if (!gst_library_load ("gstbytestream"))
|
if (!gst_library_load ("gstbytestream"))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
/* we need the gsttags plugin for metadata querying */
|
||||||
|
if (!gst_plugin_load ("gsttags"))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
if (!gst_element_register (plugin, "flacenc", GST_RANK_NONE, GST_TYPE_FLACENC))
|
if (!gst_element_register (plugin, "flacenc", GST_RANK_NONE, GST_TYPE_FLACENC))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
@ -25,6 +25,9 @@
|
|||||||
|
|
||||||
/*#define DEBUG_ENABLED */
|
/*#define DEBUG_ENABLED */
|
||||||
#include "gstflacdec.h"
|
#include "gstflacdec.h"
|
||||||
|
#include <gst/gsttaginterface.h>
|
||||||
|
|
||||||
|
#include <gst/tags/gsttagediting.h>
|
||||||
|
|
||||||
#include "flac_compat.h"
|
#include "flac_compat.h"
|
||||||
|
|
||||||
@ -66,14 +69,6 @@ static gboolean gst_flacdec_src_query (GstPad *pad, GstQueryType type,
|
|||||||
static const GstEventMask*
|
static const GstEventMask*
|
||||||
gst_flacdec_get_src_event_masks (GstPad *pad);
|
gst_flacdec_get_src_event_masks (GstPad *pad);
|
||||||
static gboolean gst_flacdec_src_event (GstPad *pad, GstEvent *event);
|
static gboolean gst_flacdec_src_event (GstPad *pad, GstEvent *event);
|
||||||
static void gst_flacdec_get_property (GObject *object,
|
|
||||||
guint prop_id,
|
|
||||||
GValue *value,
|
|
||||||
GParamSpec *pspec);
|
|
||||||
static void gst_flacdec_set_property (GObject *object,
|
|
||||||
guint prop_id,
|
|
||||||
const GValue *value,
|
|
||||||
GParamSpec *pspec);
|
|
||||||
|
|
||||||
static FLAC__SeekableStreamDecoderReadStatus
|
static FLAC__SeekableStreamDecoderReadStatus
|
||||||
gst_flacdec_read (const FLAC__SeekableStreamDecoder *decoder,
|
gst_flacdec_read (const FLAC__SeekableStreamDecoder *decoder,
|
||||||
@ -187,13 +182,6 @@ gst_flacdec_class_init (FlacDecClass *klass)
|
|||||||
|
|
||||||
parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
|
parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class, ARG_METADATA,
|
|
||||||
g_param_spec_boxed ("metadata", "Metadata", "(logical) Stream metadata",
|
|
||||||
GST_TYPE_CAPS, G_PARAM_READABLE));
|
|
||||||
|
|
||||||
gobject_class->get_property = gst_flacdec_get_property;
|
|
||||||
gobject_class->set_property = gst_flacdec_set_property;
|
|
||||||
|
|
||||||
gstelement_class->change_state = gst_flacdec_change_state;
|
gstelement_class->change_state = gst_flacdec_change_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,7 +207,6 @@ gst_flacdec_init (FlacDec *flacdec)
|
|||||||
flacdec->init = TRUE;
|
flacdec->init = TRUE;
|
||||||
flacdec->eos = FALSE;
|
flacdec->eos = FALSE;
|
||||||
flacdec->seek_pending = FALSE;
|
flacdec->seek_pending = FALSE;
|
||||||
flacdec->metadata = NULL;
|
|
||||||
|
|
||||||
FLAC__seekable_stream_decoder_set_read_callback (flacdec->decoder, gst_flacdec_read);
|
FLAC__seekable_stream_decoder_set_read_callback (flacdec->decoder, gst_flacdec_read);
|
||||||
FLAC__seekable_stream_decoder_set_seek_callback (flacdec->decoder, gst_flacdec_seek);
|
FLAC__seekable_stream_decoder_set_seek_callback (flacdec->decoder, gst_flacdec_seek);
|
||||||
@ -246,20 +233,15 @@ gst_flacdec_init (FlacDec *flacdec)
|
|||||||
static gboolean
|
static gboolean
|
||||||
gst_flacdec_update_metadata (FlacDec *flacdec, const FLAC__StreamMetadata *metadata)
|
gst_flacdec_update_metadata (FlacDec *flacdec, const FLAC__StreamMetadata *metadata)
|
||||||
{
|
{
|
||||||
|
GstTagList *list;
|
||||||
guint32 number_of_comments, cursor, str_len;
|
guint32 number_of_comments, cursor, str_len;
|
||||||
gchar *p_value, *value, *name, *str_ptr;
|
gchar *p_value, *value, *name, *str_ptr;
|
||||||
GstProps *props = NULL;
|
|
||||||
GstPropsEntry *entry;
|
|
||||||
|
|
||||||
/* clear old one */
|
list = gst_tag_list_new ();
|
||||||
if (flacdec->metadata) {
|
if (list == NULL) {
|
||||||
gst_caps_unref (flacdec->metadata);
|
return FALSE;
|
||||||
flacdec->metadata = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create props to hold the key/value pairs */
|
|
||||||
props = gst_props_empty_new ();
|
|
||||||
|
|
||||||
number_of_comments = metadata->data.vorbis_comment.num_comments;
|
number_of_comments = metadata->data.vorbis_comment.num_comments;
|
||||||
value = NULL;
|
value = NULL;
|
||||||
GST_DEBUG ("%d tag(s) found", number_of_comments);
|
GST_DEBUG ("%d tag(s) found", number_of_comments);
|
||||||
@ -271,23 +253,20 @@ gst_flacdec_update_metadata (FlacDec *flacdec, const FLAC__StreamMetadata *metad
|
|||||||
if (p_value)
|
if (p_value)
|
||||||
{
|
{
|
||||||
name = g_strndup (str_ptr, p_value - str_ptr);
|
name = g_strndup (str_ptr, p_value - str_ptr);
|
||||||
value = g_strndup (p_value + 1, str_ptr + str_len - p_value);
|
value = g_strndup (p_value + 1, str_ptr + str_len - p_value - 1);
|
||||||
|
|
||||||
entry = gst_props_entry_new (name, GST_PROPS_STRING_TYPE, value);
|
|
||||||
gst_props_add_entry (props, (GstPropsEntry *) entry);
|
|
||||||
|
|
||||||
GST_DEBUG ("%s : %s", name, value);
|
GST_DEBUG ("%s : %s", name, value);
|
||||||
|
gst_vorbis_tag_add (list, name, value);
|
||||||
g_free (name);
|
g_free (name);
|
||||||
g_free (value);
|
g_free (value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flacdec->metadata = gst_caps_new ("vorbisfile_metadata",
|
|
||||||
"application/x-gst-metadata",
|
|
||||||
props);
|
|
||||||
g_object_notify (G_OBJECT (flacdec), "metadata");
|
|
||||||
|
|
||||||
|
gst_element_found_tags (GST_ELEMENT (flacdec), list);
|
||||||
|
if (GST_PAD_IS_USABLE (flacdec->srcpad)) {
|
||||||
|
gst_pad_push (flacdec->srcpad, GST_DATA (gst_event_new_tag (list)));
|
||||||
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -790,38 +769,3 @@ gst_flacdec_change_state (GstElement *element)
|
|||||||
|
|
||||||
return GST_STATE_SUCCESS;
|
return GST_STATE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gst_flacdec_set_property (GObject *object, guint prop_id,
|
|
||||||
const GValue *value, GParamSpec *pspec)
|
|
||||||
{
|
|
||||||
FlacDec *flacdec;
|
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_FLACDEC (object));
|
|
||||||
|
|
||||||
flacdec = GST_FLACDEC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
default:
|
|
||||||
g_warning ("Unknown property id\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_flacdec_get_property (GObject *object, guint prop_id,
|
|
||||||
GValue *value, GParamSpec *pspec)
|
|
||||||
{
|
|
||||||
FlacDec *flacdec;
|
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_FLACDEC(object));
|
|
||||||
|
|
||||||
flacdec = GST_FLACDEC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case ARG_METADATA:
|
|
||||||
g_value_set_boxed (value, flacdec->metadata);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_warning ("Unknown property id\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -45,7 +45,6 @@ struct _FlacDec {
|
|||||||
GstElement element;
|
GstElement element;
|
||||||
|
|
||||||
GstPad *sinkpad,*srcpad;
|
GstPad *sinkpad,*srcpad;
|
||||||
GstCaps *metadata;
|
|
||||||
GstByteStream *bs;
|
GstByteStream *bs;
|
||||||
|
|
||||||
FLAC__SeekableStreamDecoder *decoder;
|
FLAC__SeekableStreamDecoder *decoder;
|
||||||
|
@ -25,7 +25,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <gstflacenc.h>
|
#include <gstflacenc.h>
|
||||||
|
#include <gst/tags/gsttagediting.h>
|
||||||
|
#include <gst/gsttaginterface.h>
|
||||||
#include "flac_compat.h"
|
#include "flac_compat.h"
|
||||||
|
|
||||||
static GstPadTemplate *src_template, *sink_template;
|
static GstPadTemplate *src_template, *sink_template;
|
||||||
@ -108,7 +109,15 @@ flacenc_get_type (void)
|
|||||||
0,
|
0,
|
||||||
(GInstanceInitFunc)gst_flacenc_init,
|
(GInstanceInitFunc)gst_flacenc_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const GInterfaceInfo tag_setter_info = {
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
flacenc_type = g_type_register_static (GST_TYPE_ELEMENT, "FlacEnc", &flacenc_info, 0);
|
flacenc_type = g_type_register_static (GST_TYPE_ELEMENT, "FlacEnc", &flacenc_info, 0);
|
||||||
|
g_type_add_interface_static (flacenc_type, GST_TYPE_TAG_SETTER, &tag_setter_info);
|
||||||
}
|
}
|
||||||
return flacenc_type;
|
return flacenc_type;
|
||||||
}
|
}
|
||||||
@ -334,30 +343,12 @@ gst_flacenc_init (FlacEnc *flacenc)
|
|||||||
FLAC__seekable_stream_encoder_set_client_data (flacenc->encoder,
|
FLAC__seekable_stream_encoder_set_client_data (flacenc->encoder,
|
||||||
flacenc);
|
flacenc);
|
||||||
|
|
||||||
flacenc->metadata = GST_CAPS_NEW (
|
|
||||||
"flacenc_metadata",
|
|
||||||
"application/x-gst-metadata",
|
|
||||||
"DESCRIPTION", GST_PROPS_STRING ("Track encoded with GStreamer"),
|
|
||||||
"DATE", GST_PROPS_STRING (""),
|
|
||||||
"TRACKNUMBER", GST_PROPS_STRING (""),
|
|
||||||
"TITLE", GST_PROPS_STRING (""),
|
|
||||||
"ARTIST", GST_PROPS_STRING (""),
|
|
||||||
"ALBUM", GST_PROPS_STRING (""),
|
|
||||||
"GENRE", GST_PROPS_STRING (""),
|
|
||||||
"VERSION", GST_PROPS_STRING (""),
|
|
||||||
"COPYRIGHT", GST_PROPS_STRING (""),
|
|
||||||
"LICENSE", GST_PROPS_STRING (""),
|
|
||||||
"ORGANISATION", GST_PROPS_STRING (""),
|
|
||||||
"LOCATION", GST_PROPS_STRING (""),
|
|
||||||
"CONTACT", GST_PROPS_STRING (""),
|
|
||||||
"ISRC", GST_PROPS_STRING ("")
|
|
||||||
);
|
|
||||||
|
|
||||||
flacenc->negotiated = FALSE;
|
flacenc->negotiated = FALSE;
|
||||||
flacenc->first = TRUE;
|
flacenc->first = TRUE;
|
||||||
flacenc->first_buf = NULL;
|
flacenc->first_buf = NULL;
|
||||||
flacenc->data = NULL;
|
flacenc->data = NULL;
|
||||||
gst_flacenc_update_quality (flacenc, DEFAULT_QUALITY);
|
gst_flacenc_update_quality (flacenc, DEFAULT_QUALITY);
|
||||||
|
flacenc->tags = gst_tag_list_new ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -492,46 +483,51 @@ gst_flacenc_write_callback (const FLAC__SeekableStreamEncoder *encoder,
|
|||||||
return FLAC__STREAM_ENCODER_OK;
|
return FLAC__STREAM_ENCODER_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void add_one_tag (const GstTagList *list,
|
||||||
gst_flacenc_set_metadata (FlacEnc *flacenc, GstCaps *caps)
|
const gchar *tag,
|
||||||
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
guint indice;
|
GList *comments;
|
||||||
guint comments;
|
GList *it;
|
||||||
const gchar *meta_types[] = { "TITLE", "VERSION", "ALBUM", "TRACKNUMBER",
|
FlacEnc *flacenc = GST_FLACENC (user_data);
|
||||||
"ARTIST", "PERFORMER", "COPYRIGHT", "LICENSE",
|
|
||||||
"ORGANISATION", "DESCRIPTION", "GENRE", "DATE",
|
comments = gst_tag_to_vorbis_comments (list, tag);
|
||||||
"LOCATION", "CONTACT", "ISRC", NULL };
|
for (it = comments; it != NULL; it = it->next) {
|
||||||
|
FLAC__StreamMetadata_VorbisComment_Entry commment_entry;
|
||||||
|
commment_entry.length = GUINT32_TO_LE (strlen(it->data) + 1);
|
||||||
|
commment_entry.entry = it->data;
|
||||||
|
FLAC__metadata_object_vorbiscomment_insert_comment (flacenc->meta[0],
|
||||||
|
flacenc->meta[0]->data.vorbis_comment.num_comments,
|
||||||
|
commment_entry,
|
||||||
|
TRUE);
|
||||||
|
g_free (it->data);
|
||||||
|
}
|
||||||
|
g_list_free (comments);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_flacenc_set_metadata (FlacEnc *flacenc)
|
||||||
|
{
|
||||||
|
const GstTagList *user_tags;
|
||||||
|
GstTagList *copy;
|
||||||
|
|
||||||
g_return_if_fail (flacenc != NULL);
|
g_return_if_fail (flacenc != NULL);
|
||||||
|
user_tags = gst_tag_setter_get_list (GST_TAG_SETTER (flacenc));
|
||||||
|
if ((flacenc->tags == NULL) && (user_tags == NULL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
copy = gst_tag_list_merge (user_tags, flacenc->tags,
|
||||||
|
gst_tag_setter_get_merge_mode (GST_TAG_SETTER (flacenc)));
|
||||||
flacenc->meta = g_malloc (sizeof (FLAC__StreamMetadata **));
|
flacenc->meta = g_malloc (sizeof (FLAC__StreamMetadata **));
|
||||||
|
|
||||||
flacenc->meta[0] = FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
flacenc->meta[0] = FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
||||||
|
gst_tag_list_foreach ((GstTagList*)copy, add_one_tag, flacenc);
|
||||||
for ( indice = 0, comments=0; meta_types[indice] != NULL; indice++) {
|
|
||||||
if (gst_caps_has_property(caps, meta_types[indice])) {
|
|
||||||
const gchar *entry;
|
|
||||||
gchar *data;
|
|
||||||
FLAC__StreamMetadata_VorbisComment_Entry commment_entry;
|
|
||||||
|
|
||||||
gst_caps_get_string(caps, (gchar *)meta_types[indice], &entry);
|
|
||||||
|
|
||||||
if (!strcmp (entry, ""))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
data = g_strdup_printf("%s=%s", meta_types[indice], entry);
|
|
||||||
commment_entry.length = GUINT32_TO_LE (strlen(entry) + strlen(meta_types[indice]) + 1);
|
|
||||||
commment_entry.entry = g_convert (data, commment_entry.length, "UTF8", "ISO-8859-1", NULL, NULL, NULL);
|
|
||||||
|
|
||||||
FLAC__metadata_object_vorbiscomment_insert_comment (flacenc->meta[0], comments++, commment_entry, TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FLAC__seekable_stream_encoder_set_metadata(flacenc->encoder, flacenc->meta, 1);
|
FLAC__seekable_stream_encoder_set_metadata(flacenc->encoder, flacenc->meta, 1);
|
||||||
|
gst_tag_list_free (copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_flacenc_chain (GstPad *pad, GstData *_data)
|
gst_flacenc_chain (GstPad *pad, GstData *_data)
|
||||||
{
|
{
|
||||||
@ -553,10 +549,19 @@ gst_flacenc_chain (GstPad *pad, GstData *_data)
|
|||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_EOS:
|
case GST_EVENT_EOS:
|
||||||
FLAC__seekable_stream_encoder_finish(flacenc->encoder);
|
FLAC__seekable_stream_encoder_finish(flacenc->encoder);
|
||||||
|
break;
|
||||||
|
case GST_EVENT_TAG:
|
||||||
|
if (flacenc->tags) {
|
||||||
|
gst_tag_list_merge (flacenc->tags, gst_event_tag_get_list (event),
|
||||||
|
gst_tag_setter_get_merge_mode (GST_TAG_SETTER (flacenc)));
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
gst_pad_event_default (pad, event);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
gst_pad_event_default (pad, event);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,8 +580,7 @@ gst_flacenc_chain (GstPad *pad, GstData *_data)
|
|||||||
FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
|
FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
|
||||||
{
|
{
|
||||||
FLAC__SeekableStreamEncoderState state;
|
FLAC__SeekableStreamEncoderState state;
|
||||||
|
gst_flacenc_set_metadata (flacenc);
|
||||||
gst_flacenc_set_metadata (flacenc, flacenc->metadata);
|
|
||||||
state = FLAC__seekable_stream_encoder_init (flacenc->encoder);
|
state = FLAC__seekable_stream_encoder_init (flacenc->encoder);
|
||||||
if (state != FLAC__STREAM_ENCODER_OK) {
|
if (state != FLAC__STREAM_ENCODER_OK) {
|
||||||
gst_element_error (GST_ELEMENT (flacenc),
|
gst_element_error (GST_ELEMENT (flacenc),
|
||||||
|
@ -44,8 +44,6 @@ struct _FlacEnc {
|
|||||||
|
|
||||||
GstPad *sinkpad,*srcpad;
|
GstPad *sinkpad,*srcpad;
|
||||||
|
|
||||||
GstCaps *metadata;
|
|
||||||
|
|
||||||
gboolean first;
|
gboolean first;
|
||||||
GstBuffer *first_buf;
|
GstBuffer *first_buf;
|
||||||
gboolean eos;
|
gboolean eos;
|
||||||
@ -59,6 +57,8 @@ struct _FlacEnc {
|
|||||||
|
|
||||||
FLAC__SeekableStreamEncoder *encoder;
|
FLAC__SeekableStreamEncoder *encoder;
|
||||||
FLAC__StreamMetadata **meta;
|
FLAC__StreamMetadata **meta;
|
||||||
|
|
||||||
|
GstTagList * tags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _FlacEncClass {
|
struct _FlacEncClass {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user