3
* arch-tag: Implementation of Ogg Vorbis metadata retrieval
5
* Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
6
* Marco Pesenti Gritti <marco@it.gnome.org>
7
* Bastien Nocera <hadess@hadess.net>
8
* Seth Nickell <snickell@stanford.edu>
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
#include <libgnomevfs/gnome-vfs.h>
27
#include <libgnomevfs/gnome-vfs-mime-utils.h>
28
#include <libgnomevfs/gnome-vfs-utils.h>
32
#include <vorbis/codec.h>
33
#include <vorbis/vorbisfile.h>
35
#include "ogg-helper.h"
37
#include "monkey-media-stream-info.h"
38
#include "monkey-media-private.h"
40
#include "vorbis-stream-info-impl.h"
42
static ov_callbacks file_info_callbacks =
46
ogg_helper_close_dummy,
50
static void vorbis_stream_info_impl_class_init (VorbisStreamInfoImplClass *klass);
51
static void vorbis_stream_info_impl_init (VorbisStreamInfoImpl *ma);
52
static void vorbis_stream_info_impl_finalize (GObject *object);
53
static void vorbis_stream_info_impl_open_stream (MonkeyMediaStreamInfo *info);
54
static gboolean vorbis_stream_info_impl_get_value (MonkeyMediaStreamInfo *info,
55
MonkeyMediaStreamInfoField field,
58
static gboolean vorbis_stream_info_impl_set_value (MonkeyMediaStreamInfo *info,
59
MonkeyMediaStreamInfoField field,
62
static int vorbis_stream_info_impl_get_n_values (MonkeyMediaStreamInfo *info,
63
MonkeyMediaStreamInfoField field);
65
struct VorbisStreamInfoImplPrivate
67
vorbis_comment *comment;
70
GnomeVFSHandle *handle;
73
static GObjectClass *parent_class = NULL;
76
vorbis_stream_info_impl_get_type (void)
78
static GType vorbis_stream_info_impl_type = 0;
80
if (vorbis_stream_info_impl_type == 0)
82
static const GTypeInfo our_info =
84
sizeof (VorbisStreamInfoImplClass),
87
(GClassInitFunc) vorbis_stream_info_impl_class_init,
90
sizeof (VorbisStreamInfoImpl),
92
(GInstanceInitFunc) vorbis_stream_info_impl_init
95
vorbis_stream_info_impl_type = g_type_register_static (MONKEY_MEDIA_TYPE_STREAM_INFO,
96
"VorbisStreamInfoImpl",
100
return vorbis_stream_info_impl_type;
104
vorbis_stream_info_impl_class_init (VorbisStreamInfoImplClass *klass)
106
GObjectClass *object_class = G_OBJECT_CLASS (klass);
107
MonkeyMediaStreamInfoClass *info_class = MONKEY_MEDIA_STREAM_INFO_CLASS (klass);
109
parent_class = g_type_class_peek_parent (klass);
111
object_class->finalize = vorbis_stream_info_impl_finalize;
113
info_class->open_stream = vorbis_stream_info_impl_open_stream;
114
info_class->get_n_values = vorbis_stream_info_impl_get_n_values;
115
info_class->get_value = vorbis_stream_info_impl_get_value;
116
info_class->set_value = vorbis_stream_info_impl_set_value;
120
vorbis_stream_info_impl_init (VorbisStreamInfoImpl *impl)
122
impl->priv = g_new0 (VorbisStreamInfoImplPrivate, 1);
126
vorbis_stream_info_impl_finalize (GObject *object)
128
VorbisStreamInfoImpl *impl;
130
g_return_if_fail (object != NULL);
131
g_return_if_fail (IS_VORBIS_STREAM_INFO_IMPL (object));
133
impl = VORBIS_STREAM_INFO_IMPL (object);
135
g_return_if_fail (impl->priv != NULL);
137
if (&impl->priv->vf != NULL)
138
ov_clear (&impl->priv->vf);
139
if (impl->priv->handle != NULL)
140
ogg_helper_close (impl->priv->handle);
144
G_OBJECT_CLASS (parent_class)->finalize (object);
148
vorbis_stream_info_impl_open_stream (MonkeyMediaStreamInfo *info)
150
VorbisStreamInfoImpl *impl = VORBIS_STREAM_INFO_IMPL (info);
156
g_object_get (G_OBJECT (info),
161
res = gnome_vfs_open (&impl->priv->handle, uri, GNOME_VFS_OPEN_READ);
163
if (res != GNOME_VFS_OK)
165
error = g_error_new (MONKEY_MEDIA_STREAM_INFO_ERROR,
166
MONKEY_MEDIA_STREAM_INFO_ERROR_OPEN_FAILED,
167
_("Failed to open file for reading"));
168
g_object_set (G_OBJECT (info), "error", error, NULL);
172
/* Try the different SEEK types that might fail */
173
if ((gnome_vfs_seek (impl->priv->handle, GNOME_VFS_SEEK_END, 0) != GNOME_VFS_OK) ||
174
(gnome_vfs_seek (impl->priv->handle, GNOME_VFS_SEEK_START, 0) != GNOME_VFS_OK))
176
gnome_vfs_close (impl->priv->handle);
177
impl->priv->handle = NULL;
178
error = g_error_new (MONKEY_MEDIA_STREAM_INFO_ERROR,
179
MONKEY_MEDIA_STREAM_INFO_ERROR_SEEK_FAILED,
180
_("Failed to seek file"));
181
g_object_set (G_OBJECT (info), "error", error, NULL);
185
rc = ov_open_callbacks (impl->priv->handle, &impl->priv->vf, NULL, 0,
186
file_info_callbacks);
189
/* see ogg-helper.c for details */
190
ogg_helper_close (impl->priv->handle);
191
impl->priv->handle = NULL;
192
error = g_error_new (MONKEY_MEDIA_STREAM_INFO_ERROR,
193
MONKEY_MEDIA_STREAM_INFO_ERROR_OPEN_FAILED,
194
_("Failed to open file as Ogg Vorbis"));
195
g_object_set (G_OBJECT (info), "error", error, NULL);
199
impl->priv->comment = ov_comment (&impl->priv->vf, -1);
200
impl->priv->info = ov_info (&impl->priv->vf, -1);
204
vorbis_stream_info_impl_get_n_values (MonkeyMediaStreamInfo *info,
205
MonkeyMediaStreamInfoField field)
207
VorbisStreamInfoImpl *impl;
209
g_return_val_if_fail (IS_VORBIS_STREAM_INFO_IMPL (info), 0);
211
impl = VORBIS_STREAM_INFO_IMPL (info);
216
case MONKEY_MEDIA_STREAM_INFO_FIELD_TITLE:
217
return vorbis_comment_query_count (impl->priv->comment, "title");
218
case MONKEY_MEDIA_STREAM_INFO_FIELD_ARTIST:
219
return vorbis_comment_query_count (impl->priv->comment, "artist");
220
case MONKEY_MEDIA_STREAM_INFO_FIELD_ALBUM:
221
return vorbis_comment_query_count (impl->priv->comment, "album");
222
case MONKEY_MEDIA_STREAM_INFO_FIELD_DATE:
223
return vorbis_comment_query_count (impl->priv->comment, "date");
224
case MONKEY_MEDIA_STREAM_INFO_FIELD_GENRE:
225
return vorbis_comment_query_count (impl->priv->comment, "genre");
226
case MONKEY_MEDIA_STREAM_INFO_FIELD_COMMENT:
227
return vorbis_comment_query_count (impl->priv->comment, "comment") +
228
vorbis_comment_query_count (impl->priv->comment, "");
229
case MONKEY_MEDIA_STREAM_INFO_FIELD_TRACK_NUMBER:
232
gboolean ret = FALSE;
234
tmp = vorbis_comment_query (impl->priv->comment, "tracknumber", 0);
238
parts = g_strsplit (tmp, "/", -1);
240
if (parts[0] != NULL)
248
case MONKEY_MEDIA_STREAM_INFO_FIELD_MAX_TRACK_NUMBER:
251
gboolean ret = FALSE;
253
tmp = vorbis_comment_query (impl->priv->comment, "tracktotal", 0);
257
tmp = vorbis_comment_query (impl->priv->comment, "tracknumber", 0);
261
parts = g_strsplit (tmp, "/", -1);
263
if (parts[0] != NULL && parts[1] != NULL)
271
case MONKEY_MEDIA_STREAM_INFO_FIELD_LOCATION:
272
return vorbis_comment_query_count (impl->priv->comment, "location");
273
case MONKEY_MEDIA_STREAM_INFO_FIELD_DESCRIPTION:
274
return vorbis_comment_query_count (impl->priv->comment, "description");
275
case MONKEY_MEDIA_STREAM_INFO_FIELD_VERSION:
276
return vorbis_comment_query_count (impl->priv->comment, "version");
277
case MONKEY_MEDIA_STREAM_INFO_FIELD_ISRC:
278
return vorbis_comment_query_count (impl->priv->comment, "isrc");
279
case MONKEY_MEDIA_STREAM_INFO_FIELD_ORGANIZATION:
280
return vorbis_comment_query_count (impl->priv->comment, "organization");
281
case MONKEY_MEDIA_STREAM_INFO_FIELD_COPYRIGHT:
282
return vorbis_comment_query_count (impl->priv->comment, "copyright");
283
case MONKEY_MEDIA_STREAM_INFO_FIELD_CONTACT:
284
return vorbis_comment_query_count (impl->priv->comment, "contact");
285
case MONKEY_MEDIA_STREAM_INFO_FIELD_LICENSE:
286
return vorbis_comment_query_count (impl->priv->comment, "license");
287
case MONKEY_MEDIA_STREAM_INFO_FIELD_PERFORMER:
288
return vorbis_comment_query_count (impl->priv->comment, "performer");
291
case MONKEY_MEDIA_STREAM_INFO_FIELD_FILE_SIZE:
292
case MONKEY_MEDIA_STREAM_INFO_FIELD_DURATION:
296
case MONKEY_MEDIA_STREAM_INFO_FIELD_HAS_AUDIO:
297
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_CODEC_INFO:
298
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_BIT_RATE:
299
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_AVERAGE_BIT_RATE:
300
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_VARIABLE_BIT_RATE:
301
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_QUALITY:
302
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_SAMPLE_RATE:
303
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_CHANNELS:
305
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_TRM_ID:
307
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_SERIAL_NUMBER:
308
return (ov_serialnumber (&impl->priv->vf, -1) > 0);
309
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_VENDOR:
310
return (impl->priv->comment->vendor != NULL);
311
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_ALBUM_GAIN:
315
tmp = vorbis_comment_query (impl->priv->comment, "replaygain_album_gain", 0);
317
tmp = vorbis_comment_query (impl->priv->comment, "rg_audiophile", 0);
319
return (tmp != NULL);
322
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_TRACK_GAIN:
326
tmp = vorbis_comment_query (impl->priv->comment, "replaygain_track_gain", 0);
328
tmp = vorbis_comment_query (impl->priv->comment, "rg_radio", 0);
330
return (tmp != NULL);
333
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_ALBUM_PEAK:
337
tmp = vorbis_comment_query (impl->priv->comment, "replaygain_album_peak", 0);
339
tmp = vorbis_comment_query (impl->priv->comment, "rg_peak", 0);
341
return (tmp != NULL);
344
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_TRACK_PEAK:
348
tmp = vorbis_comment_query (impl->priv->comment, "replaygain_track_peak", 0);
350
tmp = vorbis_comment_query (impl->priv->comment, "rg_peak", 0);
352
return (tmp != NULL);
357
case MONKEY_MEDIA_STREAM_INFO_FIELD_HAS_VIDEO:
367
vorbis_stream_info_impl_get_strvalue_utf8 (VorbisStreamInfoImpl *impl,
368
int index, char *entry, GValue *value)
373
strval = g_strdup (vorbis_comment_query (impl->priv->comment, entry, index));
375
if (!g_utf8_validate (strval, -1, NULL))
379
g_warning ("Invalid UTF-8 in %s field in vorbis file\n", entry);
381
tem = g_locale_to_utf8 (strval, -1, &read, &written, NULL);
390
g_value_init (value, G_TYPE_STRING);
391
g_value_set_string_take_ownership (value, strval);
397
vorbis_stream_info_impl_get_value (MonkeyMediaStreamInfo *info,
398
MonkeyMediaStreamInfoField field,
402
VorbisStreamInfoImpl *impl;
404
g_return_val_if_fail (IS_VORBIS_STREAM_INFO_IMPL (info), FALSE);
405
g_return_val_if_fail (value != NULL, FALSE);
407
impl = VORBIS_STREAM_INFO_IMPL (info);
409
if (vorbis_stream_info_impl_get_n_values (info, field) <= 0)
415
case MONKEY_MEDIA_STREAM_INFO_FIELD_TITLE:
416
return vorbis_stream_info_impl_get_strvalue_utf8 (impl, index, "title", value);
417
case MONKEY_MEDIA_STREAM_INFO_FIELD_ARTIST:
418
return vorbis_stream_info_impl_get_strvalue_utf8 (impl, index, "artist", value);
419
case MONKEY_MEDIA_STREAM_INFO_FIELD_ALBUM:
420
return vorbis_stream_info_impl_get_strvalue_utf8 (impl, index, "album", value);
421
case MONKEY_MEDIA_STREAM_INFO_FIELD_DATE:
422
return vorbis_stream_info_impl_get_strvalue_utf8 (impl, index, "date", value);
423
case MONKEY_MEDIA_STREAM_INFO_FIELD_GENRE:
424
return vorbis_stream_info_impl_get_strvalue_utf8 (impl, index, "genre", value);
425
case MONKEY_MEDIA_STREAM_INFO_FIELD_COMMENT:
429
g_value_init (value, G_TYPE_STRING);
431
count = vorbis_comment_query_count (impl->priv->comment, "comment");
433
g_value_set_string (value, vorbis_comment_query (impl->priv->comment, "comment", index));
435
g_value_set_string (value, vorbis_comment_query (impl->priv->comment, "", index - count));
436
if (!g_utf8_validate (g_value_get_string (value), -1, NULL))
438
g_warning ("Invalid UTF-8 in comment field in vorbis file\n");
439
g_value_unset (value);
444
case MONKEY_MEDIA_STREAM_INFO_FIELD_TRACK_NUMBER:
449
g_value_init (value, G_TYPE_INT);
451
tmp = vorbis_comment_query (impl->priv->comment, "tracknumber", 0);
454
g_value_set_int (value, -1);
458
parts = g_strsplit (tmp, "/", -1);
460
if (parts[0] != NULL)
461
num = atoi (parts[0]);
463
g_value_set_int (value, num);
468
case MONKEY_MEDIA_STREAM_INFO_FIELD_MAX_TRACK_NUMBER:
473
g_value_init (value, G_TYPE_INT);
475
tmp = vorbis_comment_query (impl->priv->comment, "tracktotal", 0);
477
g_value_set_int (value, atoi (tmp));
481
tmp = vorbis_comment_query (impl->priv->comment, "tracknumber", 0);
483
char **parts = g_strsplit (tmp, "/", -1);
485
if (parts[0] != NULL && parts[1] != NULL) {
486
num = atoi (parts[1]);
487
g_value_set_int (value, num);
489
g_value_set_int (value, -1);
495
case MONKEY_MEDIA_STREAM_INFO_FIELD_LOCATION:
496
return vorbis_stream_info_impl_get_strvalue_utf8 (impl, index, "location", value);
497
case MONKEY_MEDIA_STREAM_INFO_FIELD_DESCRIPTION:
498
return vorbis_stream_info_impl_get_strvalue_utf8 (impl, index, "description", value);
499
case MONKEY_MEDIA_STREAM_INFO_FIELD_VERSION:
500
return vorbis_stream_info_impl_get_strvalue_utf8 (impl, index, "version", value);
501
case MONKEY_MEDIA_STREAM_INFO_FIELD_ISRC:
502
return vorbis_stream_info_impl_get_strvalue_utf8 (impl, index, "isrc", value);
503
case MONKEY_MEDIA_STREAM_INFO_FIELD_ORGANIZATION:
504
return vorbis_stream_info_impl_get_strvalue_utf8 (impl, index, "organization", value);
505
case MONKEY_MEDIA_STREAM_INFO_FIELD_COPYRIGHT:
506
return vorbis_stream_info_impl_get_strvalue_utf8 (impl, index, "copyright", value);
507
case MONKEY_MEDIA_STREAM_INFO_FIELD_CONTACT:
508
return vorbis_stream_info_impl_get_strvalue_utf8 (impl, index, "contact", value);
509
case MONKEY_MEDIA_STREAM_INFO_FIELD_LICENSE:
510
return vorbis_stream_info_impl_get_strvalue_utf8 (impl, index, "license", value);
511
case MONKEY_MEDIA_STREAM_INFO_FIELD_PERFORMER:
512
return vorbis_stream_info_impl_get_strvalue_utf8 (impl, index, "performer", value);
515
case MONKEY_MEDIA_STREAM_INFO_FIELD_FILE_SIZE:
520
g_value_init (value, G_TYPE_LONG);
522
i = gnome_vfs_file_info_new ();
523
res = gnome_vfs_get_file_info_from_handle
524
(impl->priv->handle, i,
525
GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
526
if (res == GNOME_VFS_OK)
527
g_value_set_long (value, i->size);
529
g_value_set_long (value, 0);
531
gnome_vfs_file_info_unref (i);
534
case MONKEY_MEDIA_STREAM_INFO_FIELD_DURATION:
535
g_value_init (value, G_TYPE_LONG);
536
g_value_set_long (value, ov_time_total (&impl->priv->vf, -1));
540
case MONKEY_MEDIA_STREAM_INFO_FIELD_HAS_AUDIO:
541
g_value_init (value, G_TYPE_BOOLEAN);
542
g_value_set_boolean (value, TRUE);
544
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_CODEC_INFO:
545
g_value_init (value, G_TYPE_STRING);
546
g_value_set_string (value, _("Ogg Vorbis"));
548
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_BIT_RATE:
549
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_AVERAGE_BIT_RATE:
550
g_value_init (value, G_TYPE_INT);
551
g_value_set_int (value, (int) (impl->priv->info->bitrate_nominal / 1000));
553
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_VARIABLE_BIT_RATE:
554
g_value_init (value, G_TYPE_BOOLEAN);
555
g_value_set_boolean (value, TRUE);
557
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_TRM_ID:
559
g_value_init (value, G_TYPE_STRING);
560
g_value_set_string (value, NULL);
562
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_SAMPLE_RATE:
563
g_value_init (value, G_TYPE_LONG);
564
g_value_set_long (value, impl->priv->info->rate);
566
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_CHANNELS:
567
g_value_init (value, G_TYPE_INT);
568
g_value_set_int (value, impl->priv->info->channels);
570
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_SERIAL_NUMBER:
571
g_value_init (value, G_TYPE_LONG);
572
g_value_set_long (value, ov_serialnumber (&impl->priv->vf, -1));
574
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_VENDOR:
575
g_value_init (value, G_TYPE_STRING);
576
g_value_set_string (value, impl->priv->comment->vendor);
577
if (!g_utf8_validate (g_value_get_string (value), -1, NULL))
579
g_warning ("Invalid UTF-8 in audio vendor field in vorbis file\n");
580
g_value_unset (value);
584
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_ALBUM_GAIN:
588
tmp = vorbis_comment_query (impl->priv->comment, "replaygain_album_gain", 0);
590
tmp = vorbis_comment_query (impl->priv->comment, "rg_audiophile", 0);
592
g_value_init (value, G_TYPE_DOUBLE);
593
g_value_set_double (value, tmp != NULL ? atof (tmp) : 0.0);
596
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_TRACK_GAIN:
600
tmp = vorbis_comment_query (impl->priv->comment, "replaygain_track_gain", 0);
602
tmp = vorbis_comment_query (impl->priv->comment, "rg_radio", 0);
604
g_value_init (value, G_TYPE_DOUBLE);
605
g_value_set_double (value, tmp != NULL ? atof (tmp) : 0.0);
608
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_ALBUM_PEAK:
612
tmp = vorbis_comment_query (impl->priv->comment, "replaygain_album_peak", 0);
614
tmp = vorbis_comment_query (impl->priv->comment, "rg_peak", 0);
616
g_value_init (value, G_TYPE_DOUBLE);
617
g_value_set_double (value, tmp != NULL ? atof (tmp) : 0.0);
620
case MONKEY_MEDIA_STREAM_INFO_FIELD_AUDIO_TRACK_PEAK:
624
tmp = vorbis_comment_query (impl->priv->comment, "replaygain_track_peak", 0);
626
tmp = vorbis_comment_query (impl->priv->comment, "rg_peak", 0);
628
g_value_init (value, G_TYPE_DOUBLE);
629
g_value_set_double (value, tmp != NULL ? atof (tmp) : 0.0);
634
case MONKEY_MEDIA_STREAM_INFO_FIELD_HAS_VIDEO:
635
g_value_init (value, G_TYPE_BOOLEAN);
636
g_value_set_boolean (value, FALSE);
641
g_value_init (value, G_TYPE_NONE);
649
vorbis_stream_info_impl_set_value (MonkeyMediaStreamInfo *info,
650
MonkeyMediaStreamInfoField field,