[Rhythmbox-devel] FLAC stream info patch



Attached is a patch against monkey-media HEAD that supports reading
metadata from VorbisComment blocks in FLAC files.  It also implements a
few more fields that were previously marked FIXME such as sample rate
and channels.  It prefers VorbisComment fields to id3 tags where both
are present, since VorbisComment are somewhat more native. It works
correctly in my limited testing.

Please let me know if I need to make any modifications before it would
be accepted.

Regards,
Josh Haberman  (I hack mostly on Audacity and PortAudio)
? flac-info-patch
? flac-stream-info-patch
? src/stream-info-impl/.flac-stream-info-impl.c.swp
Index: src/stream-info-impl/flac-stream-info-impl.c
===================================================================
RCS file: /cvs/gnome/monkey-media/src/stream-info-impl/flac-stream-info-impl.c,v
retrieving revision 1.1
diff -u -r1.1 flac-stream-info-impl.c
--- src/stream-info-impl/flac-stream-info-impl.c	8 Jan 2003 21:57:08 -0000	1.1
+++ src/stream-info-impl/flac-stream-info-impl.c	27 May 2003 07:35:58 -0000
@@ -52,6 +52,8 @@
 					        const GValue *value);
 static char *FLAC_stream_info_impl_id3_tag_get_utf8 (struct id3_tag *tag,
 						    const char *field_name);
+static char*FLAC_stream_info_impl_vc_tag_get_utf8 (MonkeyMediaStreamInfo *info,
+						   const char *field_name);
 static int FLAC_stream_info_impl_get_n_values (MonkeyMediaStreamInfo *info,
 				              MonkeyMediaStreamInfoField field);
 
@@ -175,27 +177,37 @@
 	{
 	/* tags */
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_TITLE:
-		tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_TITLE);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "TITLE");
+		if (tmp == NULL)
+			tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_TITLE);
 		ret = (tmp != NULL);
 		g_free (tmp);
 		return ret;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_ARTIST:
-		tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_ARTIST);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "ARTIST");
+		if (tmp == NULL)
+			tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_ARTIST);
 		ret = (tmp != NULL);
 		g_free (tmp);
 		return ret;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_ALBUM:
-		tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_ALBUM);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "ALBUM");
+		if (tmp == NULL)
+			tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_ALBUM);
 		ret = (tmp != NULL);
 		g_free (tmp);
 		return ret;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_DATE:
-		tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_YEAR);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "DATE");
+		if (tmp == NULL)
+			tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_YEAR);
 		ret = (tmp != NULL);
 		g_free (tmp);
 		return ret;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_GENRE:
-		tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_GENRE);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "GENRE");
+		if (tmp == NULL)
+			tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_GENRE);
 		ret = (tmp != NULL);
 		g_free (tmp);
 		return ret;
@@ -205,6 +217,13 @@
 		g_free (tmp);
 		return ret;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_TRACK_NUMBER:
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "TRACKNUMBER");
+		if (tmp != NULL)
+		{
+			g_free (tmp);
+			return TRUE;
+		}
+		else
 		{
 			char **parts;
 			
@@ -249,15 +268,50 @@
 		}
 		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_LOCATION:
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "LOCATION");
+		ret = (tmp != NULL);
+		g_free (tmp);
+		return ret;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_DESCRIPTION:
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "DESCRIPTION");
+		ret = (tmp != NULL);
+		g_free (tmp);
+		return ret;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_VERSION:
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "VERSION");
+		ret = (tmp != NULL);
+		g_free (tmp);
+		return ret;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_ISRC:
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "ISRC");
+		ret = (tmp != NULL);
+		g_free (tmp);
+		return ret;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_ORGANIZATION:
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "ORGANIZATION");
+		ret = (tmp != NULL);
+		g_free (tmp);
+		return ret;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_COPYRIGHT:
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "COPYRIGHT");
+		ret = (tmp != NULL);
+		g_free (tmp);
+		return ret;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_CONTACT:
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "CONTACT");
+		ret = (tmp != NULL);
+		g_free (tmp);
+		return ret;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_LICENSE:
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "LICENSE");
+		ret = (tmp != NULL);
+		g_free (tmp);
+		return ret;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_PERFORMER:
-		return 0;
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "PERFORMER");
+		ret = (tmp != NULL);
+		g_free (tmp);
+		return ret;
 
 	/* generic bits */
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_FILE_SIZE:
@@ -273,6 +327,7 @@
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_QUALITY:
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_SAMPLE_RATE:
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_CHANNELS:
+	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_TRM_ID:
 		return 1;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_SERIAL_NUMBER:
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_VENDOR:
@@ -280,7 +335,6 @@
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_TRACK_GAIN:
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_ALBUM_PEAK:
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_TRACK_PEAK:
-	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_TRM_ID:
 		return 0;
 
 	/* video bits */
@@ -300,6 +354,7 @@
 				GValue *value)
 {
 	FLACStreamInfoImpl *impl;
+	FLAC__StreamMetadata streaminfo;
 	char *tmp;
 	
 	g_return_val_if_fail (IS_FLAC_STREAM_INFO_IMPL (info), FALSE);
@@ -315,31 +370,41 @@
 	/* tags */
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_TITLE:
 		g_value_init (value, G_TYPE_STRING);
-		tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_TITLE);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "TITLE");
+		if (tmp == NULL)
+			tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_TITLE);
 		g_value_set_string (value, tmp);
 		g_free (tmp);
 		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_ARTIST:
 		g_value_init (value, G_TYPE_STRING);
-		tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_ARTIST);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "ARTIST");
+		if (tmp == NULL)
+			tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_ARTIST);
 		g_value_set_string (value, tmp);
 		g_free (tmp);
 		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_ALBUM:
 		g_value_init (value, G_TYPE_STRING);
-		tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_ALBUM);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "ALBUM");
+		if (tmp == NULL)
+			tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_ALBUM);
 		g_value_set_string (value, tmp);
 		g_free (tmp);
 		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_DATE:
 		g_value_init (value, G_TYPE_STRING);
-		tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_YEAR);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "DATE");
+		if (tmp == NULL)
+			tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_YEAR);
 		g_value_set_string (value, tmp);
 		g_free (tmp);
 		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_GENRE:
 		g_value_init (value, G_TYPE_STRING);
-		tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_GENRE);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "GENRE");
+		if (tmp == NULL)
+			tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_GENRE);
 		g_value_set_string (value, tmp);
 		g_free (tmp);
 		break;
@@ -350,11 +415,18 @@
 		g_free (tmp);
 		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_TRACK_NUMBER:
+		g_value_init (value, G_TYPE_INT);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "TRACKNUMBER");
+		if (tmp != NULL)
+		{
+			g_value_set_int (value, atoi(tmp));
+			g_free (tmp);
+		}
+		else
 		{
 			char **parts;
 			int num = -1;
 			
-			g_value_init (value, G_TYPE_INT);
 
 			tmp = FLAC_stream_info_impl_id3_tag_get_utf8 (impl->priv->tag, ID3_FRAME_TRACK);
 			if (tmp == NULL)
@@ -402,16 +474,58 @@
 		}
 		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_LOCATION:
+		g_value_init (value, G_TYPE_STRING);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "LOCATION");
+		g_value_set_string (value, tmp);
+		g_free (tmp);
+		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_DESCRIPTION:
+		g_value_init (value, G_TYPE_STRING);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "DESCRIPTION");
+		g_value_set_string (value, tmp);
+		g_free (tmp);
+		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_VERSION:
+		g_value_init (value, G_TYPE_STRING);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "VERSION");
+		g_value_set_string (value, tmp);
+		g_free (tmp);
+		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_ISRC:
+		g_value_init (value, G_TYPE_STRING);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "ISRC");
+		g_value_set_string (value, tmp);
+		g_free (tmp);
+		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_ORGANIZATION:
+		g_value_init (value, G_TYPE_STRING);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "ORGANIZATION");
+		g_value_set_string (value, tmp);
+		g_free (tmp);
+		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_COPYRIGHT:
+		g_value_init (value, G_TYPE_STRING);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "COPYRIGHT");
+		g_value_set_string (value, tmp);
+		g_free (tmp);
+		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_CONTACT:
+		g_value_init (value, G_TYPE_STRING);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "CONTACT");
+		g_value_set_string (value, tmp);
+		g_free (tmp);
+		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_LICENSE:
+		g_value_init (value, G_TYPE_STRING);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "LICENSE");
+		g_value_set_string (value, tmp);
+		g_free (tmp);
+		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_PERFORMER:
 		g_value_init (value, G_TYPE_STRING);
-		g_value_set_string (value, "");
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "PERFORMER");
+		g_value_set_string (value, tmp);
+		g_free (tmp);
 		break;
 
 	/* generic bits */
@@ -475,34 +589,79 @@
 		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_BIT_RATE:
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_AVERAGE_BIT_RATE:
-		/* FIXME */
-		g_value_init (value, G_TYPE_INT);
-		g_value_set_int (value, id3_vfs_bitrate (impl->priv->file));
+		{
+			char *uri, *canonical_uri, *local_path;
+			g_value_init (value, G_TYPE_INT);
+			g_object_get (G_OBJECT (info), "location", &uri, NULL);
+			canonical_uri = gnome_vfs_make_uri_canonical (uri);
+			local_path = gnome_vfs_get_local_path_from_uri (canonical_uri);
+			if (FLAC__metadata_get_streaminfo (local_path, &streaminfo) == true)
+			{
+				GnomeVFSFileInfo *i;
+				GnomeVFSResult res;
+				long size;
+				float bitrate;
+
+				i = gnome_vfs_file_info_new ();
+				res = gnome_vfs_get_file_info (uri, i,
+							       GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
+				if (res == GNOME_VFS_OK)
+					size = i->size;
+				else
+					size = 0;
+
+				gnome_vfs_file_info_unref (i);
+
+				bitrate = (float)size * 8 / 1024 /     /* kilobits */
+					(streaminfo.data.stream_info.total_samples /  /* seconds */
+					 streaminfo.data.stream_info.sample_rate);
+				g_value_set_int (value, (int)bitrate);
+			}
+			else
+				g_value_set_int (value, 0);
+			break;
+		}
 		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_QUALITY:
 		g_value_init (value, MONKEY_MEDIA_TYPE_AUDIO_QUALITY);
-		g_value_set_enum (value, monkey_media_audio_quality_from_bit_rate (id3_vfs_bitrate (impl->priv->file)));
+		g_value_set_enum (value, MONKEY_MEDIA_AUDIO_QUALITY_LOSSLESS);
 		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_TRM_ID:
-		/* FIXME */
 		g_value_init (value, G_TYPE_STRING);
+		tmp = FLAC_stream_info_impl_vc_tag_get_utf8 (info, "MUSICBRAINZ_TRMID");
 		g_value_set_string (value, NULL);
+		g_free (tmp);
 		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_VARIABLE_BIT_RATE:
-		/* FIXME */ 
 		g_value_init (value, G_TYPE_BOOLEAN);
-		g_value_set_boolean (value, id3_vfs_vbr (impl->priv->file));
+		g_value_set_boolean (value, true);
 		break;
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_SAMPLE_RATE:
-		/* FIXME */
-		g_value_init (value, G_TYPE_LONG);
-		g_value_set_long (value, id3_vfs_samplerate (impl->priv->file));
-		break;
+		{
+			char *uri, *canonical_uri, *local_path;
+			g_value_init (value, G_TYPE_LONG);
+			g_object_get (G_OBJECT (info), "location", &uri, NULL);
+			canonical_uri = gnome_vfs_make_uri_canonical (uri);
+			local_path = gnome_vfs_get_local_path_from_uri (canonical_uri);
+			if (FLAC__metadata_get_streaminfo (local_path, &streaminfo) == true)
+				g_value_set_long (value, streaminfo.data.stream_info.sample_rate);
+			else
+				g_value_set_long (value, 0);
+			break;
+		}
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_CHANNELS:
-		/* FIXME */
-		g_value_init (value, G_TYPE_INT);
-		g_value_set_int (value, id3_vfs_channels (impl->priv->file));
-		break;
+		{
+			char *uri, *canonical_uri, *local_path;
+			g_value_init (value, G_TYPE_INT);
+			g_object_get (G_OBJECT (info), "location", &uri, NULL);
+			canonical_uri = gnome_vfs_make_uri_canonical (uri);
+			local_path = gnome_vfs_get_local_path_from_uri (canonical_uri);
+			if (FLAC__metadata_get_streaminfo (local_path, &streaminfo) == true)
+				g_value_set_int (value, streaminfo.data.stream_info.channels);
+			else
+				g_value_set_int (value, 0);
+			break;
+		}
 	case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_SERIAL_NUMBER:
 		g_value_init (value, G_TYPE_LONG);
 		g_value_set_long (value, 0);
@@ -572,4 +731,68 @@
 	}
 
 	return utf8;
+}
+
+
+/* if more than one entry matches this tag name, returns only the first */
+static char*
+FLAC_stream_info_impl_vc_tag_get_utf8 (MonkeyMediaStreamInfo *info, const char *field_name)
+{
+
+	FLAC__Metadata_SimpleIterator *md_iter = FLAC__metadata_simple_iterator_new ();
+	char *uri, *canonical_uri, *local_path;
+	int c;
+
+	g_object_get (G_OBJECT (info), "location", &uri, NULL);
+	canonical_uri = gnome_vfs_make_uri_canonical (uri);
+	local_path = gnome_vfs_get_local_path_from_uri (canonical_uri);
+
+	if (local_path == NULL)
+		return NULL;
+
+	if (FLAC__metadata_simple_iterator_init (md_iter, local_path, true, true) != true)
+		return NULL;
+
+	g_free (canonical_uri);
+
+	do {
+		if (FLAC__metadata_simple_iterator_get_block_type (md_iter) == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+		{
+			FLAC__StreamMetadata *md_block = FLAC__metadata_simple_iterator_get_block (md_iter);
+			FLAC__StreamMetadata_VorbisComment vc_block = md_block->data.vorbis_comment;
+			for (c = 0; c < vc_block.num_comments; c++)
+			{
+				FLAC__StreamMetadata_VorbisComment_Entry entry = vc_block.comments[c];
+				char *null_terminated_comment = malloc (entry.length + 1);
+				gchar** parts;
+				int equal_sign_loc;
+
+				memcpy (null_terminated_comment, entry.entry, entry.length);
+				null_terminated_comment[entry.length] = '\0';
+				parts = g_strsplit (null_terminated_comment, "=", 2);
+
+				if (parts[0] == NULL || parts[1] == NULL)
+					continue;
+
+				if (g_ascii_strcasecmp(parts[0], field_name) == 0)
+				{
+					gchar *return_string = g_strdup (parts[1]);
+
+					g_strfreev(parts);
+					free (null_terminated_comment);
+					FLAC__metadata_object_delete (md_block);
+					FLAC__metadata_simple_iterator_delete (md_iter);
+
+					return return_string;
+				}
+				g_strfreev(parts);
+				free (null_terminated_comment);
+			}
+			FLAC__metadata_object_delete (md_block);
+		}
+	} while (FLAC__metadata_simple_iterator_next (md_iter) == true);
+
+	FLAC__metadata_simple_iterator_delete (md_iter);
+
+	return NULL;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]