[patch] new cdda module
- From: Martin Schön <martin_schoen gmx de>
- To: gnome-vfs-list gnome org
- Subject: [patch] new cdda module
- Date: Wed, 03 Aug 2005 02:56:23 +0200
Greetings, everyone.
Beeing rather unhappy with the current cdda module (and I have the
feeling I'm not alone with this) I wrote a complete replacement. This
one is gstreamer-based (is this a problem, concerning dependencies?) and
has the following features:
- extracts not only wave, but also mp3/ogg/flac files (if supported by
your gstreamer installation)
- metadata lookup via musicbrainz
- thread safe, usable with several drives at the same time
- temporary renaming of files
I know there's currently a freeze, so I don't expect it to go into the
next release, but I'd like to have some feedback on it. Is it worth
including, and is the gstreamer dependency a problem? Any comments on
the implementation? (And could someone verify my changes to the
configure.in/Makefile.am files? I'm not very familiar with this).
Bye
Martin
? modules/cdda-data.h
? modules/cdda-utils.c
? modules/cdda-utils.h
Index: configure.in
===================================================================
RCS file: /cvs/gnome/gnome-vfs/configure.in,v
retrieving revision 1.384
diff -u -p -r1.384 configure.in
--- configure.in 25 Jul 2005 21:20:20 -0000 1.384
+++ configure.in 3 Aug 2005 00:20:57 -0000
@@ -73,6 +73,7 @@ GCONF_REQUIRED=1.1.1
GLIB_REQUIRED=2.6.0
ORBIT_REQUIRED=2.9.0
XML_REQUIRED=2.6.0
+GSTREAMER_REQUIRED=0.8
AC_SUBST(BONOBO_ACTIVATION_REQUIRED)
AC_SUBST(BONOBO_REQUIRED)
@@ -81,6 +82,7 @@ AC_SUBST(GLIB_REQUIRED)
AC_SUBST(LIBIDL_REQUIRED)
AC_SUBST(ORBIT_REQUIRED)
AC_SUBST(XML_REQUIRED)
+AC_SUBST(GSTREAMER_REQUIRED)
PKG_CHECK_MODULES(MODULES_XML, glib-2.0 >= $GLIB_REQUIRED
gmodule-no-export-2.0 >= $GLIB_REQUIRED gthread-2.0 >= $GLIB_REQUIRED
libxml-2.0 >= $XML_REQUIRED)
AC_SUBST(MODULES_XML_CFLAGS)
@@ -110,6 +112,14 @@ PKG_CHECK_MODULES(TEST, bonobo-activatio
AC_SUBST(TEST_LIBS)
AC_SUBST(TEST_CFLAGS)
+PKG_CHECK_MODULES(MODULES_GST, glib-2.0 >= $GLIB_REQUIRED gmodule-2.0
>= $GLIB_REQUIRED gthread-2.0 >= $GLIB_REQUIRED gstreamer-0.8 >=
$GSTREAMER_REQUIRED)
+AC_SUBST(MODULES_GST_CFLAGS)
+AC_SUBST(MODULES_GST_LIBS)
+
+PKG_CHECK_MODULES(MODULES_MB, libmusicbrainz >= 2.0.0)
+AC_SUBST(MODULES_MB_CFLAGS)
+AC_SUBST(MODULES_MB_LIBS)
+
ORBIT_IDL="`$PKG_CONFIG --variable=orbit_idl ORBit-2.0`"
AC_SUBST(ORBIT_IDL)
Index: modules/Makefile.am
===================================================================
RCS file: /cvs/gnome/gnome-vfs/modules/Makefile.am,v
retrieving revision 1.112
diff -u -p -r1.112 Makefile.am
--- modules/Makefile.am 14 Apr 2005 18:48:29 -0000 1.112
+++ modules/Makefile.am 3 Aug 2005 00:21:01 -0000
@@ -6,6 +6,8 @@ INCLUDES = \
-I$(top_srcdir)/imported/neon \
$(MODULES_XML_GCONF_CFLAGS) \
$(MODULES_FILE_CFLAGS) \
+ $(MODULES_GST_CFLAGS) \
+ $(MODULES_MB_CLFLAGS) \
$(HOWL_CFLAGS) \
$(LIBEFS_CFLAGS) \
$(SAMBA_CFLAGS) \
@@ -86,12 +88,12 @@ modulesconf_DATA = default-modules.conf
libcdda_la_SOURCES = \
cdda-method.c \
- cdda-cddb.c \
- cdda-cddb.h \
- cdda-cdrom-extensions.h
+ cdda-utils.c \
+ cdda-utils.h \
+ cdda-data.h
libcdda_la_LDFLAGS = $(module_flags)
-libcdda_la_LIBADD = $(MODULES_LIBS)
$(CDDA_LIBS) ../libgnomevfs/libgnomevfs-2.la
+libcdda_la_LIBADD = $(MODULES_LIBS) $(MODULES_GST_LIBS)
$(MODULES_MB_LIBS) ../libgnomevfs/libgnomevfs-2.la
### `computer' method
Index: modules/cdda-method.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/modules/cdda-method.c,v
retrieving revision 1.24
diff -u -p -r1.24 cdda-method.c
--- modules/cdda-method.c 8 May 2005 13:40:13 -0000 1.24
+++ modules/cdda-method.c 3 Aug 2005 00:21:03 -0000
@@ -2,7 +2,7 @@
/* cdda-method.c
- Copyright (C) 2000, Eazel Inc.
+ Copyright (C) 2005, Martin Schoen
The Gnome Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License
as
@@ -18,881 +18,379 @@
License along with the Gnome Library; see the file COPYING.LIB. If
not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA.
-
- Author: Gene Z. Ragan <gzr eazel com>
*/
#include <config.h>
-#include "cdda-cddb.h"
-#include <errno.h>
-#include <gconf/gconf-client.h>
-#include <gconf/gconf.h>
-#include <libgnomevfs/gnome-vfs-cancellation.h>
-#include <libgnomevfs/gnome-vfs-context.h>
#include <libgnomevfs/gnome-vfs-method.h>
-#include <libgnomevfs/gnome-vfs-mime.h>
#include <libgnomevfs/gnome-vfs-module-shared.h>
#include <libgnomevfs/gnome-vfs-module.h>
-#include <libgnomevfs/gnome-vfs-utils.h>
-#include <pwd.h>
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <cdda_paranoia.h>
-
-typedef struct {
- GnomeVFSURI *uri;
- GnomeVFSFileInfo *file_info;
- cdrom_drive *drive;
- int access_count;
- unsigned int cddb_discid;
- gboolean use_cddb;
- DiscData disc_data;
-} CDDAContext;
-
-typedef struct {
- GnomeVFSURI *uri;
- gboolean inited;
- gboolean wrote_header;
- cdrom_paranoia *paranoia;
- long cursor;
- long first_sector, last_sector;
-} ReadHandle;
-
-CDDAContext *global_context = NULL;
-
-/* This is here to work around a broken header file.
- * cdda_interface.h has a statically defined array of
- * chars that is unused. This will break our build
- * due to our strict error checking.
- */
-char **broken_header_fix = strerror_tr;
+#include <musicbrainz/queries.h>
+#include "cdda-utils.h"
-static GnomeVFSResult do_open (GnomeVFSMethod
*method,
- GnomeVFSMethodHandle **method_handle,
- GnomeVFSURI *uri,
- GnomeVFSOpenMode mode,
- GnomeVFSContext *context);
-static gboolean do_is_local (GnomeVFSMethod
*method,
- const GnomeVFSURI *uri);
-static GnomeVFSResult do_open_directory (GnomeVFSMethod
*method,
- GnomeVFSMethodHandle **method_handle,
- GnomeVFSURI *uri,
- GnomeVFSFileInfoOptions options,
- GnomeVFSContext *context);
-static GnomeVFSResult do_close_directory (GnomeVFSMethod
*method,
- GnomeVFSMethodHandle *method_handle,
- GnomeVFSContext *context);
-static GnomeVFSResult do_read_directory (GnomeVFSMethod
*method,
- GnomeVFSMethodHandle
*method_handle,
- GnomeVFSFileInfo
*file_info,
- GnomeVFSContext *context);
-static int get_data_size (cdrom_drive *drive,
- int track);
-static gboolean is_file_is_on_disc (CDDAContext *context,
- const GnomeVFSURI *uri);
-static int write_wav_header (gpointer buffer,
- long bytes);
-
-
-static const char PROXY_HOST_KEY[] = "/system/http_proxy/host";
-static const char PROXY_PORT_KEY[] = "/system/http_proxy/port";
-static const char USE_PROXY_KEY[] =
"/system/http_proxy/use_http_proxy";
-
-static CDDAContext *
-cdda_context_new (cdrom_drive *drive, GnomeVFSURI *uri)
-{
- CDDAContext *context;
- GConfClient *gconf_client;
- char *proxy_host;
- gboolean use_proxy;
- ProxyServer proxy_server;
- CDDBServer cddb_server;
-
- context = g_new0 (CDDAContext, 1);
- context->drive = drive;
- context->file_info = gnome_vfs_file_info_new ();
- context->uri = gnome_vfs_uri_ref (uri);
- context->access_count = 0;
- context->cddb_discid = CDDBDiscid (drive);
+gboolean gst_supports_mp3, gst_supports_ogg, gst_supports_flac;
+GList *disclist;
- /* Look up CDDB info */
- gconf_client = gconf_client_get_default ();
-
- use_proxy = gconf_client_get_bool (gconf_client, USE_PROXY_KEY, NULL);
- if (use_proxy) {
- proxy_host = gconf_client_get_string (gconf_client, PROXY_HOST_KEY,
NULL);
-
- proxy_server.port = gconf_client_get_int (gconf_client,
PROXY_PORT_KEY, NULL);
-
- if (proxy_host != NULL) {
- strcpy (proxy_server.name, proxy_host);
- g_free (proxy_host);
- } else {
- use_proxy = FALSE;
- }
+static GnomeVFSResult
+do_open (GnomeVFSMethod *method,
+ GnomeVFSMethodHandle **method_handle,
+ GnomeVFSURI *uri,
+ GnomeVFSOpenMode mode,
+ GnomeVFSContext *context) {
+ FileHandle *handle;
+ GstPad *src;
+ GstEvent *event;
+ gchar *tmp;
- if (proxy_server.port == 0) {
- proxy_server.port = 8080;
- }
+ if (mode != GNOME_VFS_OPEN_READ) {
+ return GNOME_VFS_ERROR_NOT_SUPPORTED;
}
-
- strcpy (cddb_server.name, "freedb.freedb.org");
- strcpy (cddb_server.cgi_prog, "~cddb/cddb.cgi");
- cddb_server.port = 80;
- cddb_server.use_proxy = use_proxy;
- cddb_server.proxy = &proxy_server;
-
- context->use_cddb = CDDBLookupDisc (&cddb_server, drive,
&context->disc_data);
-
- return context;
-}
-
-static void
-cdda_context_free (CDDAContext *context)
-{
- if (context == NULL) {
- return;
+
+ handle = g_new0 (FileHandle, 1);
+ if ((handle->cdda = get_cdda_from_uri (uri)) == NULL) {
+ file_handle_free (handle);
+ return GNOME_VFS_ERROR_NOT_FOUND;
}
-
- cdda_close (context->drive);
- gnome_vfs_file_info_unref (context->file_info);
- gnome_vfs_uri_unref (context->uri);
- g_free (context);
- context = NULL;
-}
-
-static void
-cdda_set_file_info_for_root (CDDAContext *context, GnomeVFSURI *uri)
-{
- g_assert (context);
-
- /* We don't know the io_block size */
- context->file_info->io_block_size = 0;
- context->file_info->valid_fields -=
GNOME_VFS_FILE_INFO_FIELDS_IO_BLOCK_SIZE;
- context->file_info->name = gnome_vfs_uri_extract_short_path_name
(uri);
- /*context->file_info->name = g_strdup
(context->disc_data.data_title);*/
- context->file_info->type = GNOME_VFS_FILE_TYPE_DIRECTORY;
- context->file_info->mime_type = g_strdup ("x-directory/normal");
- context->file_info->atime = time (NULL);
- context->file_info->ctime = time (NULL);
- context->file_info->mtime = time (NULL);
- context->file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_TYPE |
- GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE |
- GNOME_VFS_FILE_INFO_FIELDS_ATIME |
- GNOME_VFS_FILE_INFO_FIELDS_MTIME |
- GNOME_VFS_FILE_INFO_FIELDS_CTIME;
-};
-
-static ReadHandle *
-read_handle_new (GnomeVFSURI *uri)
-{
- ReadHandle *result;
- result = g_new (ReadHandle, 1);
-
- result->uri = gnome_vfs_uri_ref (uri);
- result->inited = FALSE;
- result->wrote_header = FALSE;
- result->paranoia = NULL;
- result->cursor = 0;
- result->first_sector = 0;
- result->last_sector = 0;
+ /* lock the cdda structure and therefore the disc, so that only one
thread can extract data at a given time */
+ g_mutex_lock (handle->cdda->mutex);
- return result;
-}
-
-static void
-read_handle_destroy (ReadHandle *handle)
-{
- gnome_vfs_uri_unref (handle->uri);
-
- if (handle->paranoia == NULL) {
- paranoia_free (handle->paranoia);
+ handle->uri = gnome_vfs_uri_dup (uri);
+ if ((handle->tracknumber = get_tracknumber_from_uri (handle->uri)) ==
0) {
+ file_handle_free (handle);
+ return GNOME_VFS_ERROR_NOT_FOUND;
}
- g_free (handle);
-}
-
-static int
-get_track_index_from_uri (CDDAContext *context, GnomeVFSURI *uri) {
- char *base_name;
- int index;
- char *escaped_name;
-
- base_name = gnome_vfs_uri_extract_short_path_name (uri);
- escaped_name = gnome_vfs_unescape_string_for_display (base_name);
- g_free (base_name);
-
- /* Check and see if filename is in cddb data list */
- for (index = 0; index < context->drive->tracks; index++) {
- if (strcmp (escaped_name,
context->disc_data.data_track[index].track_name) == 0) {
- g_free (escaped_name);
- return index + 1;
- }
+ /* create the necessary pipeline */
+ if ((tmp = g_strrstr (gnome_vfs_uri_extract_short_name (uri), ".")) ==
NULL) {
+ file_handle_free (handle);
+ return GNOME_VFS_ERROR_NOT_FOUND;
}
-
- g_free (escaped_name);
- return -1;
-}
-
-static GnomeVFSResult
-do_open (GnomeVFSMethod *method, GnomeVFSMethodHandle **method_handle,
- GnomeVFSURI *uri, GnomeVFSOpenMode mode, GnomeVFSContext *context)
-{
- GnomeVFSResult result;
- ReadHandle *read_handle;
- GnomeVFSFileInfoOptions options;
- char *base_name;
- char *dirname, *schemedir, *sep;
- GnomeVFSURI *dir_uri;
-
- result = GNOME_VFS_ERROR_GENERIC;
- *method_handle = NULL;
-
- /*g_message ("cdda do_open: %s", gnome_vfs_uri_get_path (uri));*/
-
- /* Load in context for disc if we not yet done so. */
- if (global_context == NULL) {
- base_name = gnome_vfs_uri_extract_short_path_name (uri);
- if (base_name[0] == GNOME_VFS_URI_PATH_CHR) {
- g_free (base_name);
- return result;
- } else {
- g_free (base_name);
- }
-
- dirname = gnome_vfs_uri_extract_dirname (uri);
- schemedir = g_strdup_printf ("cdda://%s", dirname);
-
- /* Remove trailing '/' if there is one */
- sep = strrchr (schemedir, '/');
- if (sep != NULL) {
- schemedir [strlen (schemedir) - 1] = '\0';
- }
-
- dir_uri = gnome_vfs_uri_new (schemedir);
- options = 0;
- result = do_open_directory (method, method_handle, dir_uri, options,
NULL);
- gnome_vfs_uri_unref (dir_uri);
-
- if (result != GNOME_VFS_OK) {
- /*g_message ("cdda do_open: Unable to load context");*/
- return result;
+
+ if (g_ascii_strcasecmp (tmp, ".wav") == 0) {
+ if ((handle->filter = gst_element_factory_make (WAVE_ENCODER,
"wav_filter")) == NULL) {
+ file_handle_free (handle);
+ return GNOME_VFS_ERROR_GENERIC;
}
- }
-
- if (mode == GNOME_VFS_OPEN_READ) {
- /* Make sure file is present */
- if (is_file_is_on_disc (global_context, uri)) {
- result = GNOME_VFS_OK;
- read_handle = read_handle_new (uri);
-
- /* Set up cdparanoia */
- if (!read_handle->inited) {
- int track;
- int paranoia_mode;
- long offset, sec, off;
-
- track = get_track_index_from_uri (global_context, uri);
- if (track == -1) {
- return GNOME_VFS_ERROR_GENERIC;
- }
- if (!cdda_track_audiop (global_context->drive, track)) {
- /*g_message ("Error. Selected track is not an audio
track.");*/
- return GNOME_VFS_ERROR_GENERIC;
- }
-
- /* Calculate sector span and offset */
- sec = cdda_track_firstsector (global_context->drive, track);
- off = cdda_track_lastsector (global_context->drive, track) - sec +
1;
-
- read_handle->first_sector = 0;
- read_handle->last_sector = off - 1;
-
- offset = cdda_track_firstsector (global_context->drive, track);
- read_handle->first_sector += offset;
- read_handle->last_sector += offset;
-
- read_handle->paranoia = paranoia_init (global_context->drive);
- /*paranoia_mode = PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP;*/
- paranoia_mode = PARANOIA_MODE_DISABLE;
- paranoia_modeset (read_handle->paranoia, paranoia_mode);
- cdda_verbose_set (global_context->drive,
CDDA_MESSAGE_PRINTIT,CDDA_MESSAGE_FORGETIT);
-
- paranoia_seek (read_handle->paranoia, read_handle->cursor =
read_handle->first_sector, SEEK_SET);
-
- read_handle->inited = TRUE;
- }
-
- *method_handle = (GnomeVFSMethodHandle *) read_handle;
- }
- } else if (mode == GNOME_VFS_OPEN_WRITE) {
- result = GNOME_VFS_ERROR_READ_ONLY;
+ } else if (gst_supports_mp3 && g_ascii_strcasecmp (tmp, ".mp3") == 0)
{
+ if ((handle->filter = gst_element_factory_make (MP3_ENCODER,
"mp3_filter")) == NULL) {
+ file_handle_free (handle);
+ return GNOME_VFS_ERROR_GENERIC;
+ }
+ /* set to joint stereo, 192kbit/s variable bitrate */
+ gst_element_set (handle->filter, "mode", 1, NULL);
+ gst_element_set (handle->filter, "bitrate", 192, NULL);
+ gst_element_set (handle->filter, "vbr", 4, NULL);
+
+ } else if (gst_supports_ogg && g_ascii_strcasecmp (tmp, ".ogg") == 0)
{
+ if ((handle->filter = gst_element_factory_make (VORBIS_ENCODER,
"ogg_filter")) == NULL) {
+ file_handle_free (handle);
+ return GNOME_VFS_ERROR_GENERIC;
+ }
+ gst_element_set (handle->filter, "quality", 0.5, NULL);
+
+ } else if (gst_supports_flac && g_ascii_strcasecmp (tmp, ".flac") ==
0) {
+ if ((handle->filter = gst_element_factory_make (FLAC_ENCODER,
"flac_filter")) == NULL) {
+ file_handle_free (handle);
+ return GNOME_VFS_ERROR_GENERIC;
+ }
} else {
- result = GNOME_VFS_ERROR_INVALID_OPEN_MODE;
+ /* file with an unsupported extension */
+ return GNOME_VFS_ERROR_NOT_SUPPORTED;
}
-
- return result;
-}
-
-static GnomeVFSResult
-do_close (GnomeVFSMethod *method,
- GnomeVFSMethodHandle *method_handle,
- GnomeVFSContext *context)
-{
- ReadHandle *read_handle;
- /*g_message ("cdda do_close");*/
-
- g_return_val_if_fail (method_handle != NULL,
GNOME_VFS_ERROR_INTERNAL);
-
- read_handle = (ReadHandle *) method_handle;
- read_handle_destroy (read_handle);
-
- return GNOME_VFS_OK;
-}
-
-
-/* We have to pass in a callback to paranoia_read, even though we don't
use it */
-static void
-paranoia_callback (long inpos, int function) {
-}
-
-static GnomeVFSResult
-do_read (GnomeVFSMethod *method,
- GnomeVFSMethodHandle *method_handle,
- gpointer buffer,
- GnomeVFSFileSize num_bytes,
- GnomeVFSFileSize *bytes_read,
- GnomeVFSContext *context)
-{
- ReadHandle *read_handle;
- gint16 *readbuf;
- g_return_val_if_fail (method_handle != NULL,
GNOME_VFS_ERROR_INTERNAL);
-
- if (gnome_vfs_context_check_cancellation (context)) {
- return GNOME_VFS_ERROR_CANCELLED;
- }
-
- read_handle = (ReadHandle *) method_handle;
- if (read_handle == NULL) {
- return GNOME_VFS_ERROR_INTERNAL;
- }
-
- readbuf = NULL;
-
- if (!read_handle->wrote_header) {
- *bytes_read = write_wav_header (buffer, (read_handle->last_sector -
read_handle->first_sector + 1)
- * CD_FRAMESIZE_RAW);
- read_handle->wrote_header = TRUE;
- return GNOME_VFS_OK;
- }
-
-
- if (read_handle->cursor <= read_handle->last_sector) {
- readbuf = paranoia_read (read_handle->paranoia, paranoia_callback);
- } else {
- return GNOME_VFS_ERROR_EOF;
-
- }
-
- if (readbuf == NULL) {
- *bytes_read = 0;
+ handle->source = gst_element_factory_make ("cdparanoia", "source");
+ if ((handle->source = gst_element_factory_make ("cdparanoia",
"source")) == NULL) {
+ file_handle_free (handle);
return GNOME_VFS_ERROR_GENERIC;
}
-
- read_handle->cursor++;
-
- memcpy (buffer, readbuf, CD_FRAMESIZE_RAW);
- *bytes_read = CD_FRAMESIZE_RAW;
-
- return GNOME_VFS_OK;
-}
-
-#if 0
-static void
-display_toc (cdrom_drive *d)
-{
- long audiolen = 0;
- int i;
-
- printf ("\nTable of contents (audio tracks only):\n"
- "track length begin copy pre ch\n"
- "===========================================================\n");
-
- for (i = 1; i <= d->tracks; i++) {
- if (cdda_track_audiop (d, i)) {
- char buffer[256];
-
- long sec = cdda_track_firstsector (d, i);
- long off = cdda_track_lastsector (d, i) - sec + 1;
-
- sprintf(buffer,
- "%3d. %7ld [%02d:%02d.%02d] %7ld [%02d:%02d.%02d] %s %s %
s",
- i,
- off,(int)(off/(60*75)),(int)((off/75)%60),(int)(off%75),
- sec,(int)(sec/(60*75)),(int)((sec/75)%60),(int)(sec%75),
- cdda_track_copyp (d,i)?" OK":" no",
- cdda_track_preemp (d,i)?" yes":" no",
- cdda_track_channels (d,i)==2?" 2":" 4");
- printf ("%s\n", buffer);
- audiolen+=off;
- }
+ gst_element_set (handle->source, "device", handle->cdda->drive, NULL);
+ gst_element_set (handle->source, "paranoia-mode", 4, NULL);
+
+ if ((handle->sink = gst_element_factory_make ("fakesink", "sink"))
== NULL) {
+ file_handle_free (handle);
+ return GNOME_VFS_ERROR_GENERIC;
}
+ gst_element_set (handle->sink, "signal-handoffs", TRUE, NULL);
- {
- char buffer[256];
- sprintf (buffer, "TOTAL %7ld [%02d:%02d.%02d] (audio only)",
- audiolen, (int)(audiolen / (60 * 75)),(int)((audiolen / 75) %
60),
- (int)(audiolen % 75));
- printf ("%s\n", buffer);
- }
-
- printf ("\n");
-}
-#endif
-
-static cdrom_drive *
-open_cdda_device (GnomeVFSURI *uri)
-{
- const char *device_name;
- cdrom_drive *drive;
+ if ((handle->thread = gst_thread_new ("thread")) == NULL) {
+ file_handle_free (handle);
+ return GNOME_VFS_ERROR_GENERIC;
+ }
- device_name = gnome_vfs_uri_get_path (uri);
-
- drive = cdda_identify (device_name, FALSE, NULL);
- if (drive == NULL) {
- return NULL;
- }
-
- /* Turn off verbosity */
- cdda_verbose_set (drive, CDDA_MESSAGE_PRINTIT, CDDA_MESSAGE_FORGETIT);
-
- /* Open drive */
- switch (cdda_open (drive)) {
- case -2:
- case -3:
- case -4:
- case -5:
- g_message ("Unable to open disc. Is there an audio CD in the
drive?");
- return NULL;
-
- case -6:
- g_message ("CDDA method could not find a way to read audio from
this drive.");
- return NULL;
-
- case 0:
- break;
-
- default:
- g_message ("Unable to open disc.");
- return NULL;
+ gst_bin_add_many (GST_BIN (handle->thread), handle->source,
handle->filter, handle->sink, NULL);
+ if (!gst_element_link_many (handle->source, handle->filter,
handle->sink, NULL)) {
+ file_handle_free (handle);
+ return GNOME_VFS_ERROR_GENERIC;
}
-
- return drive;
-}
-
-static gboolean
-is_file_is_on_disc (CDDAContext *context, const GnomeVFSURI *uri)
-{
- int index;
- char *base_name;
- char *escaped_name;
- if (context == NULL) {
- return FALSE;
+ handle->queue = g_async_queue_new ();
+ g_signal_connect (handle->sink, "handoff", G_CALLBACK (cb_handoff),
handle->queue);
+ g_signal_connect (handle->thread, "eos", G_CALLBACK (cb_eos),
handle->queue);
+
+ gst_element_set_state (handle->thread, GST_STATE_PAUSED);
+
+ /* seek to track */
+ src = gst_element_get_pad (handle->source, "src");
+ event = gst_event_new_segment_seek (gst_format_get_by_nick ("track") |
GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH, (gint64)
(handle->tracknumber-1), (gint64) handle->tracknumber);
+ if (!gst_pad_send_event (src, event)) {
+ file_handle_free (handle);
+ return GNOME_VFS_ERROR_GENERIC;
}
-
- base_name = gnome_vfs_uri_extract_short_path_name (uri);
- escaped_name = gnome_vfs_unescape_string_for_display (base_name);
- g_free (base_name);
-
- for (index = 0; index < context->drive->tracks; index++) {
- if (strcmp (escaped_name,
context->disc_data.data_track[index].track_name) == 0) {
- g_free (escaped_name);
- return TRUE;
+
+ /* add tag information */
+ if (GST_IS_TAG_SETTER (handle->filter)) {
+ gst_tag_setter_add (GST_TAG_SETTER (handle->filter),
+ GST_TAG_MERGE_REPLACE,
+ GST_TAG_TITLE,
handle->cdda->disc.track[handle->tracknumber-1].name,
+ GST_TAG_ARTIST,
handle->cdda->disc.track[handle->tracknumber-1].artist,
+ GST_TAG_ALBUM, handle->cdda->disc.title,
+ /* GST_TAG_GENRE, cdda->disc.genre, */
+ GST_TAG_DURATION,
(handle->cdda->disc.track[handle->tracknumber-1].size /
BYTES_PER_SECOND) * 1000000000,
+ GST_TAG_TRACK_NUMBER, handle->tracknumber,
+ GST_TAG_TRACK_COUNT, handle->cdda->disc.tracks,
+ NULL);
+ if (handle->cdda->disc.year > 0) {
+ gst_tag_setter_add (GST_TAG_SETTER (handle->filter),
+ GST_TAG_MERGE_REPLACE,
+ GST_TAG_DATE, handle->cdda->disc.year,
+ NULL);
}
}
-
- g_free (escaped_name);
- return FALSE;
-}
-
-static GnomeVFSResult
-get_file_info_for_basename (CDDAContext *context, const char
*base_name)
-{
- int index;
-
- g_assert (context);
- if (!context->use_cddb) {
- return GNOME_VFS_ERROR_GENERIC;
- }
+ /* start encoding and fill the buffers in a separate thread, so we
don't have to iterate manually */
+ gst_element_set_state (handle->thread, GST_STATE_PLAYING);
- /* Check and see if filename is in cddb data list */
- for (index = 0; index < context->drive->tracks; index++) {
- if (strcmp (base_name,
context->disc_data.data_track[index].track_name) == 0) {
- /* Populate file info structure */
- context->file_info->io_block_size = CD_FRAMESIZE_RAW;
- context->file_info->name = g_strdup (base_name);
- context->file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
- context->file_info->mime_type = g_strdup ("audio/x-wav");
- context->file_info->atime = time (NULL);
- context->file_info->ctime = time (NULL);
- context->file_info->mtime = time (NULL);
- context->file_info->size = get_data_size (context->drive, index +
1);
- context->file_info->valid_fields = GNOME_VFS_FILE_INFO_FIELDS_TYPE
|
- GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE |
- GNOME_VFS_FILE_INFO_FIELDS_SIZE |
- GNOME_VFS_FILE_INFO_FIELDS_IO_BLOCK_SIZE |
- GNOME_VFS_FILE_INFO_FIELDS_ATIME |
- GNOME_VFS_FILE_INFO_FIELDS_MTIME |
- GNOME_VFS_FILE_INFO_FIELDS_CTIME;
+ *method_handle = (GnomeVFSMethodHandle *) handle;
+ return GNOME_VFS_OK;
+}
- return GNOME_VFS_OK;
- }
- }
- return GNOME_VFS_ERROR_GENERIC;
+static GnomeVFSResult
+do_close (GnomeVFSMethod *method,
+ GnomeVFSMethodHandle *method_handle,
+ GnomeVFSContext *context) {
+ FileHandle *handle;
+
+ handle = (FileHandle *) method_handle;
+ file_handle_free (handle);
+ return GNOME_VFS_OK;
}
-static GnomeVFSResult
-do_get_file_info (GnomeVFSMethod *method,
- GnomeVFSURI *uri,
- GnomeVFSFileInfo *file_info,
- GnomeVFSFileInfoOptions options,
- GnomeVFSContext *context)
-{
- cdrom_drive *drive;
- char *base_name;
- gboolean use_base, use_cache;
+static GnomeVFSResult
+do_read (GnomeVFSMethod *method,
+ GnomeVFSMethodHandle *method_handle,
+ gpointer buffer,
+ GnomeVFSFileSize num_bytes,
+ GnomeVFSFileSize *bytes_read,
+ GnomeVFSContext *context) {
GnomeVFSResult result;
- char *escaped_name;
-
- /*g_message ("do_get_file_info: %s", gnome_vfs_uri_get_path (uri));*/
+ FileHandle *handle;
- use_base = FALSE;
- use_cache = FALSE;
-
- result = GNOME_VFS_OK;
+ handle = (FileHandle *) method_handle;
- /* Get basename */
- base_name = gnome_vfs_uri_extract_short_path_name (uri);
- escaped_name = gnome_vfs_unescape_string_for_display (base_name);
- g_free (base_name);
-
- /* Extract path and attempt to open */
- drive = open_cdda_device (uri);
- if (drive == NULL) {
- /* OK. We failed to open. Let's try the parent... */
- gchar *dirname, *schemedir, *sep;
- GnomeVFSURI *dir_uri;
-
- dirname = gnome_vfs_uri_extract_dirname (uri);
- schemedir = g_strdup_printf ("cdda://%s", dirname);
-
- /* Remove trailing '/' if there is one */
- sep = strrchr (schemedir, '/');
- if (sep != NULL) {
- schemedir [strlen (schemedir) - 1] = '\0';
- }
-
- dir_uri = gnome_vfs_uri_new (schemedir);
- drive = open_cdda_device (dir_uri);
-
- g_free (dirname);
- g_free (schemedir);
- gnome_vfs_uri_unref (dir_uri);
-
- if (drive == NULL) {
- g_free (escaped_name);
- return GNOME_VFS_ERROR_GENERIC;
- }
-
- use_base = TRUE;
- }
-
- /* Check and see if we already have opened and stashed this drive */
- if (!use_base) {
- if (global_context != NULL) {
-#ifdef __linux__
- if (strcmp (drive->cdda_device_name,
global_context->drive->cdda_device_name) == 0) {
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) ||
defined(__DragonFly__)
- if (strcmp (drive->dev->device_path,
global_context->drive->dev->device_path) == 0) {
-#endif
- use_cache = TRUE;
- cdda_close (drive);
- gnome_vfs_file_info_copy (file_info, global_context->file_info);
- } else {
- /* We have a new drive. */
- cdda_context_free (global_context);
- global_context = cdda_context_new (drive, uri);
- cdda_set_file_info_for_root (global_context, uri);
- gnome_vfs_file_info_copy (file_info, global_context->file_info);
- }
- } else {
- /* Create a new context */
- global_context = cdda_context_new (drive, uri);
- cdda_set_file_info_for_root (global_context, uri);
- gnome_vfs_file_info_copy (file_info, global_context->file_info);
- }
+ handle->buffer = (GstBuffer *) g_async_queue_pop (handle->queue);
+ if (GST_BUFFER_SIZE (handle->buffer) == 0) {
+ result = GNOME_VFS_ERROR_EOF;
} else {
- cdda_context_free (global_context);
- global_context = cdda_context_new (drive, uri);
- result = get_file_info_for_basename (global_context, escaped_name);
- if (result == GNOME_VFS_OK) {
- gnome_vfs_file_info_copy (file_info, global_context->file_info);
- } else {
- cdda_context_free (global_context);
- global_context = NULL;
- }
+ *bytes_read = GST_BUFFER_SIZE (handle->buffer);
+ memcpy (buffer, GST_BUFFER_DATA (handle->buffer), *bytes_read);
+ result = GNOME_VFS_OK;
}
-
- g_free (escaped_name);
+ gst_buffer_default_free (handle->buffer);
return result;
}
static GnomeVFSResult
-do_open_directory (GnomeVFSMethod *method, GnomeVFSMethodHandle
**method_handle,
- GnomeVFSURI *uri, GnomeVFSFileInfoOptions options,
- GnomeVFSContext *context)
-{
- cdrom_drive *drive;
- gboolean use_base, use_cache;
- char *base_name;
- char *escaped_name;
-
- g_print ("do_open_directory () in uri: %s\n", gnome_vfs_uri_get_path
(uri));
-
- use_base = FALSE;
- use_cache = FALSE;
-
- /* Get basename */
- base_name = gnome_vfs_uri_extract_short_path_name (uri);
- escaped_name = gnome_vfs_unescape_string_for_display (base_name);
- g_free (base_name);
-
- /* Make sure we can open URI */
- drive = open_cdda_device (uri);
- if (drive == NULL) {
- /* OK. We failed to open. Let's try the parent... */
- gchar *dirname, *schemedir, *sep;
- GnomeVFSURI *dir_uri;
-
- dirname = gnome_vfs_uri_extract_dirname (uri);
- schemedir = g_strdup_printf ("cdda://%s", dirname);
-
- /* Remove trailing '/' if there is one */
- sep = strrchr (schemedir, '/');
- if (sep != NULL) {
- schemedir [strlen (schemedir) - 1] = '\0';
- }
-
- dir_uri = gnome_vfs_uri_new (schemedir);
- drive = open_cdda_device (dir_uri);
-
- g_free (dirname);
- g_free (schemedir);
- gnome_vfs_uri_unref (dir_uri);
-
- if (drive == NULL) {
- g_free (escaped_name);
- return GNOME_VFS_ERROR_GENERIC;
- }
- use_base = TRUE;
- }
-
- if (!use_base) {
- /* Check for cache */
- if (global_context != NULL) {
-#ifdef __linux__
- if (strcmp (drive->cdda_device_name,
global_context->drive->cdda_device_name) != 0) {
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) ||
defined(__DragonFly__)
- if (strcmp (drive->dev->device_path,
global_context->drive->dev->device_path) != 0) {
-#endif
- /* Clear old cache */
- cdda_context_free (global_context);
- global_context = cdda_context_new (drive, uri);
- cdda_set_file_info_for_root (global_context, uri);
- } else {
- /* g_message ("Using cache"); */
- cdda_close (drive);
- }
- } else {
- /* Allocate new context */
- global_context = cdda_context_new (drive, uri);
- cdda_set_file_info_for_root (global_context, uri);
- }
- } else {
- /* This is a file. Blast cache.*/
- /* g_message ("Use base: %s", escaped_name); */
- cdda_context_free (global_context);
- global_context = NULL;
- *method_handle = NULL;
- cdda_close (drive);
- g_free (escaped_name);
- return GNOME_VFS_ERROR_GENERIC;
+do_open_directory (GnomeVFSMethod *method,
+ GnomeVFSMethodHandle **method_handle,
+ GnomeVFSURI *uri,
+ GnomeVFSFileInfoOptions options,
+ GnomeVFSContext *context) {
+ FileHandle *handle;
+
+ handle = g_new0 (FileHandle, 1);
+ if ((handle->cdda = get_cdda_from_uri (uri)) == NULL) {
+ g_free (handle);
+ return GNOME_VFS_ERROR_INTERNAL;
}
-
- *method_handle = (GnomeVFSMethodHandle *) global_context;
- g_free (escaped_name);
-
+ handle->uri = gnome_vfs_uri_dup (uri);
+ handle->tracknumber = 0;
+ *method_handle = (GnomeVFSMethodHandle *) handle;
return GNOME_VFS_OK;
}
static GnomeVFSResult
do_close_directory (GnomeVFSMethod *method,
- GnomeVFSMethodHandle *method_handle,
- GnomeVFSContext *context)
-{
- CDDAContext *cdda_context = (CDDAContext *)method_handle;
-
- /*g_message ("cdda do_close_directory");*/
-
- if (cdda_context == NULL) {
- /*g_message ("cdda do_close_directory: NULL cdda context");*/
- return GNOME_VFS_ERROR_GENERIC;
- }
+ GnomeVFSMethodHandle *method_handle,
+ GnomeVFSContext *context) {
+ FileHandle *handle;
- cdda_context->access_count = 0;
-
+ handle = (FileHandle *) method_handle;
+ gnome_vfs_uri_unref (handle->uri);
+ g_free (handle);
return GNOME_VFS_OK;
}
-
-static int
-get_data_size (cdrom_drive *drive, int track)
-{
- int minutes, seconds, total_seconds, size;
-
- size = 0;
-
- if (cdda_track_audiop (drive, track)) {
- long sec = cdda_track_firstsector (drive, track);
- long off = cdda_track_lastsector (drive, track) - sec + 1;
-
- minutes = off / (60 * 75);
- seconds = (off / 75) % 60;
-
- total_seconds = (minutes * 60) + seconds;
- size = ((total_seconds * 44) * 2 * 2) * 1024;
- }
-
- /*g_message ("get_data_size: %d", size);*/
+
+static GnomeVFSResult
+do_read_directory (GnomeVFSMethod *method,
+ GnomeVFSMethodHandle *method_handle,
+ GnomeVFSFileInfo *file_info,
+ GnomeVFSContext *context) {
+ FileHandle *handle;
+ gchar *dirname, *name;
+ GnomeVFSResult result;
- return size;
-}
-
-#if 0
-static int
-get_data_size_from_uri (GnomeVFSURI *uri, CDDAContext *context)
-{
- int minutes, seconds, total_seconds, size, index;
- const char *base_name;
+ handle = (FileHandle *) method_handle;
- size = -1;
+ handle->tracknumber++;
+ dirname = gnome_vfs_uri_extract_short_name (handle->uri);
- if (context == NULL) {
- return size;
+ if (handle->tracknumber <= handle->cdda->disc.tracks) {
+ if (g_ascii_strcasecmp (gnome_vfs_uri_get_path(handle->uri),
handle->cdda->drive) == 0) {
+ name = g_strdup_printf ("%.2d - %s.wav", handle->tracknumber,
handle->cdda->disc.track[handle->tracknumber-1].name);
+ } else if (gst_supports_mp3 && g_ascii_strcasecmp (dirname, "MP3") ==
0) {
+ name = g_strdup_printf ("%.2d - %s.mp3", handle->tracknumber,
handle->cdda->disc.track[handle->tracknumber-1].name);
+ } else if (gst_supports_ogg && g_ascii_strcasecmp (dirname, "Ogg
Vorbis") == 0) {
+ name = g_strdup_printf ("%.2d - %s.ogg", handle->tracknumber,
handle->cdda->disc.track[handle->tracknumber-1].name);
+ } else if (gst_supports_flac && g_ascii_strcasecmp (dirname, "Flac")
== 0) {
+ name = g_strdup_printf ("%.2d - %s.flac", handle->tracknumber,
handle->cdda->disc.track[handle->tracknumber-1].name);
+ } else {
+ return GNOME_VFS_ERROR_NOT_FOUND;
+ }
+ /* Tracks+3 because there are 3 folders in the root directory.
Otherwise the last 3 tracks are not shown.
+ * This is only valid for the root directory.
+ */
+ } else if (handle->tracknumber <= handle->cdda->disc.tracks+3) {
+ if (g_ascii_strcasecmp (gnome_vfs_uri_get_path(handle->uri),
handle->cdda->drive) == 0) {
+ switch ((handle->tracknumber)-(handle->cdda->disc.tracks)) {
+ case 1:
+ if (gst_supports_mp3) {
+ name = g_strdup ("MP3");
+ break;
+ } else {
+ handle->tracknumber++;
+ }
+ case 2:
+ if (gst_supports_ogg) {
+ name = g_strdup ("Ogg Vorbis");
+ break;
+ } else {
+ handle->tracknumber++;
+ }
+ case 3:
+ if (gst_supports_flac) {
+ name = g_strdup ("Flac");
+ } else {
+ handle->tracknumber++;
+ }
+ break;
+ default:
+ return GNOME_VFS_ERROR_GENERIC;
+ }
+ } else {
+ return GNOME_VFS_ERROR_EOF;
+ }
+ } else {
+ return GNOME_VFS_ERROR_EOF;
}
-
- base_name = gnome_vfs_uri_extract_short_path_name (uri);
- /* Check and see if filename is in cddb data list */
- for (index = 0; index < context->drive->tracks; index++) {
- if (strcmp (base_name,
context->disc_data.data_track[index].track_name) == 0) {
- if (cdda_track_audiop (context->drive, index+1)) {
- long sec = cdda_track_firstsector (context->drive, index+1);
- long off = cdda_track_lastsector (context->drive, index+1) - sec +
1;
-
- minutes = off / (60 * 75);
- seconds = (off / 75) % 60;
+ g_free (dirname);
- total_seconds = (minutes * 60) + seconds;
- size = ((total_seconds * 44) * 2 * 2) * 1024;
- }
- g_free (base_name);
- return size;
- }
- }
- g_free (base_name);
- return size;
+ return get_file_info (name, handle->tracknumber, handle->cdda,
file_info);
}
-#endif
-
-static GnomeVFSResult
-do_read_directory (GnomeVFSMethod *method,
- GnomeVFSMethodHandle *method_handle,
- GnomeVFSFileInfo *file_info,
- GnomeVFSContext *context)
-{
-
- CDDAContext *cdda_context = (CDDAContext *) method_handle;
- /*g_message ("cdda do_read_directory");*/
-
- if (cdda_context == NULL) {
- g_warning ("do_read_directory: NULL context");
- return GNOME_VFS_ERROR_GENERIC;
- }
+static GnomeVFSResult
+do_get_file_info (GnomeVFSMethod *method,
+ GnomeVFSURI *uri,
+ GnomeVFSFileInfo *file_info,
+ GnomeVFSFileInfoOptions options,
+ GnomeVFSContext *context) {
+ CDDA *cdda;
+ gchar *name;
+ gushort tracknumber;
+
+ if ((cdda = get_cdda_from_uri (uri)) == NULL) {
+ if ((cdda = cdda_new (uri)) == NULL) {
+ return GNOME_VFS_ERROR_INTERNAL;
+ }
+ }
+ name = gnome_vfs_uri_extract_short_name (uri);
+ tracknumber = get_tracknumber_from_uri (uri);
+ return get_file_info (name, tracknumber, cdda, file_info);
+}
- if (cdda_context->access_count >= cdda_context->drive->tracks) {
- /*g_message ("do_read_directory: over access count");*/
- return GNOME_VFS_ERROR_EOF;
- }
+static GnomeVFSResult
+do_get_file_info_from_handle (GnomeVFSMethod *method,
+ GnomeVFSMethodHandle *method_handle,
+ GnomeVFSFileInfo *file_info,
+ GnomeVFSFileInfoOptions options,
+ GnomeVFSContext *context) {
+ FileHandle *handle;
- cdda_context->access_count++;
+ handle = (FileHandle *) method_handle;
+ return do_get_file_info (method, handle->uri, file_info, options,
context);
+}
- /* Populate file info */
- file_info->io_block_size = CD_FRAMESIZE_RAW;
- file_info->size = get_data_size (cdda_context->drive,
cdda_context->access_count);
- file_info->atime = time (NULL);
- file_info->ctime = time (NULL);
- file_info->mtime = time (NULL);
- if (cdda_context->use_cddb) {
- file_info->name = g_strdup
(cdda_context->disc_data.data_track[cdda_context->access_count-1].track_name);
+static gboolean
+do_is_local (GnomeVFSMethod *method,
+ const GnomeVFSURI *uri) {
+ gchar *dir;
+
+ dir = gnome_vfs_uri_extract_short_name (uri);
+ if (g_ascii_strcasecmp (dir, "MP3") == 0 || g_ascii_strcasecmp (dir,
"Ogg Vorbis") == 0 || g_ascii_strcasecmp (dir, "Flac") == 0) {
+ /* The compressed files are local, of course, but we pretend they
aren't, so nautilus won't try to thumbnail them. */
+ g_free (dir);
+ return FALSE;
} else {
- file_info->name = g_strdup_printf ("Untitled %d",
cdda_context->access_count);
+ /* Wave-files in the root directory may be thumbnailed. */
+ g_free (dir);
+ return TRUE;
}
- file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
- file_info->mime_type = g_strdup ("audio/x-wav");
- file_info->valid_fields = GNOME_VFS_FILE_INFO_FIELDS_TYPE |
- GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE |
- GNOME_VFS_FILE_INFO_FIELDS_SIZE |
- GNOME_VFS_FILE_INFO_FIELDS_IO_BLOCK_SIZE |
- GNOME_VFS_FILE_INFO_FIELDS_ATIME |
- GNOME_VFS_FILE_INFO_FIELDS_MTIME |
- GNOME_VFS_FILE_INFO_FIELDS_CTIME;
-
- return GNOME_VFS_OK;
}
static GnomeVFSResult
do_check_same_fs (GnomeVFSMethod *method,
- GnomeVFSURI *a,
- GnomeVFSURI *b,
- gboolean *same_fs_return,
- GnomeVFSContext *context)
-{
- *same_fs_return = TRUE;
-
+ GnomeVFSURI *a,
+ GnomeVFSURI *b,
+ gboolean *same_fs_return,
+ GnomeVFSContext *context) {
+ *same_fs_return = FALSE;
return GNOME_VFS_OK;
}
-static gboolean
-do_is_local (GnomeVFSMethod *method, const GnomeVFSURI *uri)
-{
- return TRUE;
-}
+/* You can rename a file on the cd (not permanent of course, but nice
if you want to give them certain names BEFORE copying).
+ * Be aware that this is track-based, so renaming a wave file in the
root dir will also rename its counterparts in the subdirs.
+ */
+static GnomeVFSResult
+do_set_file_info (GnomeVFSMethod *method,
+ GnomeVFSURI *a,
+ const GnomeVFSFileInfo *info,
+ GnomeVFSSetFileInfoMask mask,
+ GnomeVFSContext *context) {
+ CDDA *cdda;
+ gushort tracknumber;
+ gchar *ext;
+
+ if ((cdda = get_cdda_from_uri (a)) == NULL) {
+ return GNOME_VFS_ERROR_INTERNAL;
+ }
+ if (mask == GNOME_VFS_SET_FILE_INFO_NAME) {
+ ext = g_strrstr (info->name, ".");
+ tracknumber = get_tracknumber_from_uri (a);
+ g_free (cdda->disc.track[tracknumber-1].name);
+ g_mutex_lock (cdda->mutex);
+ cdda->disc.track[tracknumber-1].name = g_strndup (info->name,
ext-(info->name));
+ g_mutex_unlock (cdda->mutex);
+ return GNOME_VFS_OK;
+ } else {
+ return GNOME_VFS_ERROR_NOT_PERMITTED;
+ }
+}
static GnomeVFSMethod method = {
sizeof (GnomeVFSMethod),
@@ -908,136 +406,53 @@ static GnomeVFSMethod method = {
do_close_directory,
do_read_directory,
do_get_file_info,
- NULL,
+ do_get_file_info_from_handle,
do_is_local,
NULL, /* make directory */
NULL, /* remove directory */
NULL, /* rename */
NULL, /* unlink */
do_check_same_fs,
- NULL, /* do_set_file_info */
+ do_set_file_info, /* do_set_file_info */
NULL, /* do_truncate */
NULL, /* do_find_directory */
- NULL /* do_create_symbolic_link */
+ NULL, /* do_create_symbolic_link */
+ NULL, /* do_monitor_add */
+ NULL, /* do_monitor_cancel */
+ NULL, /* do_file_control */
+ NULL /* do_forget_cache */
};
-#if 0
-static void
-put_num (long num, int f, int endianness, int bytes)
-{
- int i;
- unsigned char c;
-
- if (!endianness) {
- i = 0;
- } else {
- i = bytes - 1;
- }
-
- while (bytes--){
- c = (num >> (i << 3)) & 0xff;
- if (write (f, &c, 1) == -1) {
- perror ("Could not write to output.");
- exit (1);
- }
-
- if (endianness) {
- i--;
- } else {
- i++;
- }
- }
-}
-#endif
-
-
-/* Write WAV header information into memory buffer */
-#if 0
-static int
-write_wav_header (gpointer buffer, long bytes)
-{
- char *ptr;
-
- memset (buffer, 0, CD_FRAMESIZE_RAW);
-
- ptr = buffer;
-
- *ptr = "RIFF"; ptr += 4;
- *ptr = bytes + 44 - 8; ptr += 4;
- *ptr = "WAVEfmt "; ptr += 8;
- *ptr = 16; ptr += 4;
- *ptr = 1; ptr += 2;
- *ptr = 2; ptr += 2;
- *ptr = 44100; ptr += 4;
- *ptr = 44100 * 2 * 2; ptr += 4;
- *ptr = 4; ptr += 2;
- *ptr = 16; ptr += 2;
- *ptr = "data"; ptr += 4;
- *ptr = bytes; ptr += 4;
-
- return 44;
-}
-#endif
-
-static int
-write_wav_header (gpointer buffer, long bytes)
-{
- char *ptr;
- int var;
-
- memset (buffer, 0, CD_FRAMESIZE_RAW);
-
- ptr = buffer;
-
- memcpy (ptr, "RIFF", 4); ptr += 4;
-
- var = bytes + 44 - 8;
- memcpy (ptr, &var, 4); ptr += 4;
-
- memcpy (ptr, "WAVEfmt ", 8); ptr += 8;
-
- var = 16;
- memcpy (ptr, &var, 4); ptr += 4;
-
- var = 1;
- memcpy (ptr, &var, 2); ptr += 2;
-
- var = 2;
- memcpy (ptr, &var, 2); ptr += 2;
-
- var = 44100;
- memcpy (ptr, &var, 4); ptr += 4;
-
- var = 44100 * 2 * 2;
- memcpy (ptr, &var, 4); ptr += 4;
-
- var = 4;
- memcpy (ptr, &var, 2); ptr += 2;
-
- var = 16;
- memcpy (ptr, &var, 2); ptr += 2;
-
- memcpy (ptr, "data", 4); ptr += 4;
-
- memcpy (ptr, &bytes, 4); ptr += 4;
-
- return 44;
-}
-
GnomeVFSMethod *
vfs_module_init (const char *method_name,
- const char *args)
-{
+ const char *args) {
char *argv[] = { "gnome-vfs-cdda-module", NULL };
if (!gconf_is_initialized ()) {
gconf_init (1, argv, NULL);
}
+
+ gst_init (NULL, NULL);
+
+ /* check if compressed formats are supported by gstreamer */
+ /* at least wave encoding MUST be supported */
+ if (gst_element_factory_find (WAVE_ENCODER) == NULL) {
+ return NULL;
+ }
+ gst_supports_mp3 = (gst_element_factory_find (MP3_ENCODER) != NULL);
+ gst_supports_ogg = (gst_element_factory_find (VORBIS_ENCODER) !=
NULL);
+ gst_supports_flac = (gst_element_factory_find (FLAC_ENCODER) != NULL);
+
+#ifdef DEBUG
+ gst_debug_set_active (TRUE);
+ gst_debug_set_default_threshold (GST_LEVEL_DEBUG);
+#endif
return &method;
}
void
-vfs_module_shutdown (GnomeVFSMethod *method)
-{
+vfs_module_shutdown (GnomeVFSMethod *method) {
+ g_list_foreach (disclist, &cdda_free, NULL);
+ g_list_free (disclist);
}
The following additional files will also be required:
cdda-data.h:
----------------
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*-
*/
/* cdda-data.h
Copyright (C) 2005, Martin Schoen
The Gnome Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License
as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The Gnome Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the Gnome Library; see the file COPYING.LIB. If
not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA.
*/
#include <glib.h>
#include <libgnomevfs/gnome-vfs-uri.h>
#include <gst/gst.h>
#define PROXY_HOST_KEY "/system/http_proxy/host"
#define PROXY_PORT_KEY "/system/http_proxy/port"
#define USE_PROXY_KEY "/system/http_proxy/use_http_proxy"
#define CD_FRAMESIZE_RAW 2352 /* bytes per frame, raw mode */
#define BYTES_PER_SECOND 176400 /* (44100 samples per second) * (2
Bytes per sample) * (2 channels) */
#define MB_BUFFER_SIZE 256
#define WAVE_ENCODER "wavenc"
#define MP3_ENCODER "lame"
#define VORBIS_ENCODER "vorbisenc"
#define FLAC_ENCODER "flacenc"
typedef struct _track_data {
gchar *name;
gchar *artist;
guint64 size;
} TrackData;
typedef struct _disc_data {
gchar *id;
gchar *title;
guint genre;
guint year;
guint64 tracks;
TrackData track[99];
} DiscData;
typedef struct {
GnomeVFSURI *uri;
gchar *drive;
DiscData disc;
GMutex *mutex;
GTime last_used;
} CDDA;
typedef struct {
GnomeVFSURI *uri;
CDDA *cdda;
gushort tracknumber;
GstElement *thread, *source, *filter, *sink;
GstBuffer *buffer;
GAsyncQueue *queue;
} FileHandle;
cdda-utils.h:
----------------
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*-
*/
/* cdda-utils.h
Copyright (C) 2005, Martin Schoen
The Gnome Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License
as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The Gnome Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the Gnome Library; see the file COPYING.LIB. If
not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA.
*/
#include <libgnomevfs/gnome-vfs-file-info.h>
#include <libgnomevfs/gnome-vfs-utils.h>
#include <musicbrainz/mb_c.h>
#include "cdda-data.h"
void cb_handoff (GstElement *fakesrc, GstBuffer *buffer, GstPad *pad,
gpointer user_data);
void cb_eos (GstElement *thread, gpointer data);
gboolean query_musicbrainz (musicbrainz_t *mb, CDDA *cdda);
CDDA* cdda_new (GnomeVFSURI *uri);
void cdda_free (gpointer data, gpointer user_data);
CDDA* get_cdda_from_uri (GnomeVFSURI *uri);
gushort get_tracknumber_from_uri (GnomeVFSURI *uri);
GnomeVFSResult get_file_info (gchar *name, gushort tracknumber, CDDA
*cdda, GnomeVFSFileInfo *file_info);
cdda-utils.c:
----------------
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*-
*/
/* cdda-utils.c
Copyright (C) 2005, Martin Schoen
The Gnome Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License
as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The Gnome Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the Gnome Library; see the file COPYING.LIB. If
not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA.
*/
#include <gconf/gconf-client.h>
#include <gconf/gconf.h>
#include "cdda-utils.h"
extern gboolean gst_supports_mp3, gst_supports_ogg, gst_supports_flac;
extern GList *disclist;
void
cb_handoff (GstElement *fakesrc,
GstBuffer *buffer,
GstPad *pad,
gpointer user_data) {
gint64 size;
gpointer current;
GstBuffer *tmp;
gst_buffer_ref(buffer);
GAsyncQueue *queue = (GAsyncQueue *) user_data;
g_async_queue_ref (queue);
/* to make sure do_read gets no more than the expected number of bytes
*/
size = GST_BUFFER_SIZE (buffer);
if (size > CD_FRAMESIZE_RAW) {
current = GST_BUFFER_DATA (buffer);
while (size > 0)
{
tmp = gst_buffer_new ();
if (size > CD_FRAMESIZE_RAW) {
tmp->data = g_memdup (current, CD_FRAMESIZE_RAW);
tmp->size = CD_FRAMESIZE_RAW;
} else {
tmp->data = g_memdup (current, size);
tmp->size = size;
}
g_async_queue_push (queue, tmp);
size -= CD_FRAMESIZE_RAW;
current += CD_FRAMESIZE_RAW;
}
} else {
g_async_queue_push (queue, buffer);
}
g_async_queue_unref (queue);
}
/* signals end of stream by sending an empty buffer to the queue */
void
cb_eos (GstElement *thread,
gpointer data) {
GAsyncQueue *queue = (GAsyncQueue *) data;
g_async_queue_ref (queue);
g_async_queue_push (queue, gst_buffer_new_and_alloc (0));
g_async_queue_unref (queue);
}
gboolean
query_musicbrainz (musicbrainz_t *mb,
CDDA *cdda) {
GConfClient *gconf_client;
char *proxy_host;
guint proxy_port;
/* check if we need to use a proxy */
gconf_client = gconf_client_get_default ();
if (gconf_client_get_bool (gconf_client, USE_PROXY_KEY, NULL)) {
proxy_host = gconf_client_get_string (gconf_client, PROXY_HOST_KEY,
NULL);
proxy_port = gconf_client_get_int (gconf_client, PROXY_PORT_KEY,
NULL);
if (proxy_host != NULL) {
if (proxy_port == 0) {
proxy_port = 8080;
}
mb_SetProxy (*mb, proxy_host, proxy_port);
}
}
g_object_unref (gconf_client);
#ifdef DEBUG
mb_SetDebug (*mb, 1);
#endif
mb_UseUTF8 (*mb, TRUE);
mb_SetDevice (*mb, cdda->drive);
return (mb_Query (*mb, MBQ_GetCDInfo) && mb_GetResultInt(*mb,
MBE_GetNumAlbums) >= 1);
}
void
file_handle_free (FileHandle *handle) {
g_mutex_free (handle->cdda->mutex);
gnome_vfs_uri_unref (handle->uri);
gst_object_unref (GST_OBJECT (handle->thread));
gst_object_unref (GST_OBJECT (handle->source));
gst_object_unref (GST_OBJECT (handle->filter));
gst_object_unref (GST_OBJECT (handle->sink));
g_free (handle->buffer);
g_free (handle->queue);
}
CDDA*
cdda_new (GnomeVFSURI *uri) {
CDDA *cdda, *rem;
musicbrainz_t mb;
gushort size, index;
const gchar *current_dir, *tmp;
cdda = g_new0 (CDDA, 1);
cdda->uri = gnome_vfs_uri_dup (uri);
cdda->last_used = time (NULL);
/* keep list of cdda structures at an acceptable size */
size = g_list_length (disclist);
while (size >= 10) {
rem = (CDDA *) g_list_nth_data (disclist, 0);
for (index = 1; index < size; index++) {
cdda = (CDDA *) g_list_nth_data (disclist, index);
if (cdda->last_used < rem->last_used) {
rem = cdda;
}
}
disclist = g_list_remove (disclist, rem);
}
cdda = g_new0 (CDDA, 1);
cdda->uri = gnome_vfs_uri_dup (uri);
/* get cdda device name from uri */
cdda->drive = g_strdup (gnome_vfs_uri_get_path (cdda->uri));
while (!g_file_test (cdda->drive, G_FILE_TEST_EXISTS)) {
current_dir = g_strrstr (cdda->drive, GNOME_VFS_URI_PATH_STR);
tmp = cdda->drive;
cdda->drive = g_strndup (tmp, current_dir-tmp);
}
cdda->mutex = g_mutex_new ();
/* try to get cd info from musicbrainz */
mb = mb_New ();
if (query_musicbrainz (&mb, cdda)) {
gchar data[MB_BUFFER_SIZE];
guint duration;
/* FIXME: failure & error checking */
if (!mb_Select1(mb, MBS_SelectAlbum, 1)) {
cdda_free (cdda, NULL);
return NULL;
}
if (!mb_GetResultData (mb, MBE_AlbumGetAlbumName, data,
MB_BUFFER_SIZE)) {
cdda->disc.title = g_strdup (data);
} else {
cdda->disc.title = g_strdup ("Unknown Title");
}
if (mb_GetResultInt(mb, MBE_AlbumGetNumReleaseDates) >= 1) {
mb_Select1(mb, MBS_SelectReleaseDate, 1);
mb_GetResultData(mb, MBE_ReleaseGetDate, data, MB_BUFFER_SIZE);
cdda->disc.year = atoi (data);
mb_Select(mb, MBS_Back);
} else {
cdda->disc.year = 0;
}
cdda->disc.genre = 0;
cdda->disc.tracks = mb_GetResultInt (mb, MBE_AlbumGetNumTracks);
if (cdda->disc.tracks == 0) {
cdda_free (cdda, NULL);
return NULL;
}
for (index = 0; index < cdda->disc.tracks; index++) {
if (mb_GetResultData1 (mb, MBE_AlbumGetTrackName, data,
MB_BUFFER_SIZE, index+1)) {
cdda->disc.track[index].name = g_strdup (data);
} else {
cdda->disc.track[index].name = g_strdup_printf ("Track %.2d", index
+1);
}
if (mb_GetResultData1 (mb, MBE_AlbumGetArtistName, data,
MB_BUFFER_SIZE, index+1)) {
cdda->disc.track[index].artist = g_strdup (data);
} else {
cdda->disc.track[index].artist = g_strdup ("");
}
duration = mb_GetResultInt1 (mb, MBE_AlbumGetTrackDuration, index+1);
cdda->disc.track[index].size = (duration / 1000) * BYTES_PER_SECOND;
}
} else { /* musicbrainz lookup failed, we put in some defaults */
if (!mb_Query (mb, MBQ_GetCDTOC)) {
cdda_free (cdda, NULL);
return NULL;
}
cdda->disc.title = g_strdup ("Unknown Title");
cdda->disc.genre = 0;
cdda->disc.year = 0;
cdda->disc.tracks = mb_GetResultInt (mb, MBE_TOCGetLastTrack);
for (index = 0; index < cdda->disc.tracks; index++) {
cdda->disc.track[index].name = g_strdup_printf ("Track %.2d", index
+1);
cdda->disc.track[index].artist = g_strdup ("Unknown Artist");
cdda->disc.track[index].size = mb_GetResultInt1 (mb,
MBE_TOCGetTrackNumSectors, index+2) * CD_FRAMESIZE_RAW;
}
}
mb_Delete (mb);
disclist = g_list_append (disclist, cdda);
return cdda;
}
void
cdda_free (gpointer data,
gpointer user_data) {
CDDA *cdda = (CDDA *) data;
gnome_vfs_uri_unref (cdda->uri);
g_mutex_free (cdda->mutex);
g_free (cdda->drive);
disclist = g_list_remove (disclist, cdda);
}
CDDA*
get_cdda_from_uri (GnomeVFSURI *uri) {
CDDA *cdda;
gchar *str_uri;
guint length, index;
str_uri = gnome_vfs_uri_to_string (uri,
GNOME_VFS_URI_HIDE_TOPLEVEL_METHOD);
length = g_list_length (disclist);
for (index = 0; index < length; index++) {
cdda = (CDDA *) g_list_nth_data (disclist, index);
if (g_ascii_strncasecmp (str_uri, cdda->drive, strlen (cdda->drive))
== 0) {
cdda->last_used = time (NULL);
return cdda;
}
}
return NULL;
}
gushort
get_tracknumber_from_uri (GnomeVFSURI *uri) {
CDDA *cdda;
gushort index;
gchar *escaped_name, *name, *ext, *trackname;
g_return_val_if_fail ((cdda = get_cdda_from_uri (uri)) != NULL, 0);
escaped_name =gnome_vfs_uri_extract_short_name (uri);
name = gnome_vfs_unescape_string_for_display (escaped_name);
ext = g_strrstr (name, ".");
if (ext == NULL) {
g_free (escaped_name);
g_free (name);
return 0;
}
trackname = g_strndup (name, ext - name);
g_free (escaped_name);
g_free (name);
for (index = 0; index < cdda->disc.tracks; index++) {
if (g_ascii_strcasecmp (trackname, g_strdup_printf ("%.2d - %s", index
+1, cdda->disc.track[index].name)) == 0) {
g_free (trackname);
return index+1;
}
}
g_free (trackname);
return 0;
}
GnomeVFSResult
get_file_info (gchar *name,
gushort tracknumber,
CDDA *cdda,
GnomeVFSFileInfo *file_info) {
gchar *ext, *dev;
file_info->atime = time (NULL);
file_info->ctime = time (NULL);
file_info->mtime = time (NULL);
file_info->permissions = GNOME_VFS_PERM_USER_READ |
GNOME_VFS_PERM_GROUP_READ;
file_info->valid_fields = GNOME_VFS_FILE_INFO_FIELDS_TYPE |
GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE |
GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS |
GNOME_VFS_FILE_INFO_FIELDS_ATIME |
GNOME_VFS_FILE_INFO_FIELDS_MTIME |
GNOME_VFS_FILE_INFO_FIELDS_CTIME;
file_info->name = name;
ext = g_strrstr (name, ".");
dev = g_strrstr (cdda->drive, GNOME_VFS_URI_PATH_STR);
dev++;
if (ext != NULL) { /* is file */
/* This is always set this way, so we can rely on a common buffer size
when reading */
file_info->io_block_size = CD_FRAMESIZE_RAW;
file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_IO_BLOCK_SIZE |
GNOME_VFS_FILE_INFO_FIELDS_SIZE;
if (g_ascii_strcasecmp (ext, ".wav") == 0) {
file_info->mime_type = g_strdup ("audio/x-wav");
file_info->size = cdda->disc.track[tracknumber-1].size;
} else if (gst_supports_mp3 && g_ascii_strcasecmp (ext, ".mp3") == 0)
{
file_info->mime_type = g_strdup ("audio/mpeg");
/* We just assume that mp3/ogg files have 1/10 of the original size.
This may or may not be true,
* depending on the file. The real size is known only after encoding
(due to vbr usage in mp3/vorbis),
* but it is needed for the progress dialog to work, so we make a
good guess about the size.
* The same is true for flac files, but with 1/2 of the original
size. (Is this right?)
*/
file_info->size = cdda->disc.track[tracknumber-1].size / 10;
} else if (gst_supports_ogg && g_ascii_strcasecmp (ext, ".ogg") == 0)
{
file_info->mime_type = g_strdup ("application/ogg");
file_info->size = cdda->disc.track[tracknumber-1].size / 10;
} else if (gst_supports_flac && g_ascii_strcasecmp (ext, ".flac") ==
0) {
file_info->mime_type = g_strdup ("audio/x-flac");
file_info->size = cdda->disc.track[tracknumber-1].size / 2;
} else {
return GNOME_VFS_ERROR_NOT_FOUND;
}
} else if (g_ascii_strcasecmp (dev, name) == 0
|| g_ascii_strcasecmp (name, "MP3") == 0
|| g_ascii_strcasecmp (name, "Ogg Vorbis") == 0
|| g_ascii_strcasecmp (name, "Flac") == 0) { /* is directory */
file_info->type = GNOME_VFS_FILE_TYPE_DIRECTORY;
file_info->permissions |= GNOME_VFS_PERM_USER_EXEC |
GNOME_VFS_PERM_GROUP_EXEC ;
file_info->mime_type = g_strdup ("x-directory/normal");
} else {
return GNOME_VFS_ERROR_NOT_FOUND;
}
return GNOME_VFS_OK;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]