changeset 19272:e53b30cd047f

renamed cddX stream interface to stream_cddX for consistency
author ben
date Mon, 31 Jul 2006 17:48:50 +0000
parents 64d82a45a05d
children 11ec1cb3a7ea
files stream/Makefile stream/cdda.c stream/cddb.c stream/stream_cdda.c stream/stream_cddb.c
diffstat 5 files changed, 1271 insertions(+), 1271 deletions(-) [+]
line wrap: on
line diff
--- a/stream/Makefile	Mon Jul 31 17:39:17 2006 +0000
+++ b/stream/Makefile	Mon Jul 31 17:48:50 2006 +0000
@@ -17,9 +17,9 @@
         cue_read.c \
 
 ifeq ($(CDDA),yes)
-SRCS += cdda.c
+SRCS += stream_cdda.c
   ifeq ($(MPLAYER_NETWORK),yes)
-  SRCS += cddb.c
+  SRCS += stream_cddb.c
   endif
 endif
 
--- a/stream/cdda.c	Mon Jul 31 17:39:17 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,391 +0,0 @@
-#include "config.h"
-
-#include "stream.h"
-#include "m_option.h"
-#include "m_struct.h"
-#include "bswap.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "demuxer.h"
-
-#include "cdd.h"
-
-#include "mp_msg.h"
-#include "help_mp.h"
-
-#ifndef CD_FRAMESIZE_RAW
-#define CD_FRAMESIZE_RAW CDIO_CD_FRAMESIZE_RAW
-#endif
-
-
-extern char *cdrom_device;
-
-static struct cdda_params {
-  int speed;
-  int paranoia_mode;
-  char* generic_dev;
-  int sector_size;
-  int search_overlap;
-  int toc_bias;
-  int toc_offset;
-  int no_skip;
-  char* device;
-  m_span_t span;
-} cdda_dflts = {
-  -1,
-  0,
-  NULL,
-  0,
-  -1,
-  0,
-  0,
-  0,
-  NULL,
-  { 0, 0 }
-};
-
-#define ST_OFF(f) M_ST_OFF(struct cdda_params,f)
-m_option_t cdda_params_fields[] = {
-  { "speed", ST_OFF(speed), CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL },
-  { "paranoia", ST_OFF(paranoia_mode), CONF_TYPE_INT,M_OPT_RANGE, 0, 2, NULL },
-  { "generic-dev", ST_OFF(generic_dev), CONF_TYPE_STRING, 0, 0, 0, NULL },
-  { "sector-size", ST_OFF(sector_size), CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL },
-  { "overlap", ST_OFF(search_overlap), CONF_TYPE_INT, M_OPT_RANGE,0,75, NULL },
-  { "toc-bias", ST_OFF(toc_bias), CONF_TYPE_INT, 0, 0, 0, NULL },
-  { "toc-offset", ST_OFF(toc_offset), CONF_TYPE_INT, 0, 0, 0, NULL },
-  { "noskip", ST_OFF(no_skip), CONF_TYPE_FLAG, 0 , 0, 1, NULL },
-  { "skip", ST_OFF(no_skip), CONF_TYPE_FLAG, 0 , 1, 0, NULL },
-  { "device", ST_OFF(device), CONF_TYPE_STRING, 0, 0, 0, NULL },
-  { "span",  ST_OFF(span), CONF_TYPE_OBJ_PARAMS, 0, 0, 0, &m_span_params_def },
-  /// For url parsing
-  { "hostname", ST_OFF(span), CONF_TYPE_OBJ_PARAMS, 0, 0, 0, &m_span_params_def },
-  { "port", ST_OFF(speed), CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL },
-  { "filename", ST_OFF(device), CONF_TYPE_STRING, 0, 0, 0, NULL },
-  {NULL, NULL, 0, 0, 0, 0, NULL}
-};
-static struct m_struct_st stream_opts = {
-  "cdda",
-  sizeof(struct cdda_params),
-  &cdda_dflts,
-  cdda_params_fields
-};
-
-/// We keep these options but now they set the defaults
-m_option_t cdda_opts[] = {
-  { "speed", &cdda_dflts.speed, CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL },
-  { "paranoia", &cdda_dflts.paranoia_mode, CONF_TYPE_INT,M_OPT_RANGE, 0, 2, NULL },
-  { "generic-dev", &cdda_dflts.generic_dev, CONF_TYPE_STRING, 0, 0, 0, NULL },
-  { "sector-size", &cdda_dflts.sector_size, CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL },
-  { "overlap", &cdda_dflts.search_overlap, CONF_TYPE_INT, M_OPT_RANGE,0,75, NULL },
-  { "toc-bias", &cdda_dflts.toc_bias, CONF_TYPE_INT, 0, 0, 0, NULL },
-  { "toc-offset", &cdda_dflts.toc_offset, CONF_TYPE_INT, 0, 0, 0, NULL },
-  { "noskip", &cdda_dflts.no_skip, CONF_TYPE_FLAG, 0 , 0, 1, NULL },
-  { "skip", &cdda_dflts.no_skip, CONF_TYPE_FLAG, 0 , 1, 0, NULL },
-  { "device", &cdda_dflts.device, CONF_TYPE_STRING, 0, 0, 0, NULL },
-  { "span", &cdda_dflts.span, CONF_TYPE_OBJ_PARAMS, 0, 0, 0, &m_span_params_def },
-  {NULL, NULL, 0, 0, 0, 0, NULL}
-};
-
-extern int cdd_identify(const char *dev);
-extern int cddb_resolve(const char *dev, char **xmcd_file);
-extern cd_info_t* cddb_parse_xmcd(char *xmcd_file);
-
-static int seek(stream_t* s,off_t pos);
-static int fill_buffer(stream_t* s, char* buffer, int max_len);
-static void close_cdda(stream_t* s);
-
-static int open_cdda(stream_t *st,int m, void* opts, int* file_format) {
-  struct cdda_params* p = (struct cdda_params*)opts;
-  int mode = p->paranoia_mode;
-  int offset = p->toc_offset;
-#ifndef HAVE_LIBCDIO
-  cdrom_drive* cdd = NULL;
-#else
-  cdrom_drive_t* cdd = NULL;
-#endif
-  cdda_priv* priv;
-  cd_info_t *cd_info,*cddb_info = NULL;
-  unsigned int audiolen=0;
-  int last_track;
-  int i;
-  char *xmcd_file = NULL;
-
-  if(m != STREAM_READ) {
-    m_struct_free(&stream_opts,opts);
-    return STREAM_UNSUPORTED;
-  }
-
-  if(!p->device) {
-    if (cdrom_device)
-      p->device = strdup(cdrom_device);
-    else
-      p->device = strdup(DEFAULT_CDROM_DEVICE);
-  }
-
-#ifdef MPLAYER_NETWORK
-  // cdd_identify returns -1 if it cannot read the TOC,
-  // in which case there is no point in calling cddb_resolve
-  if(cdd_identify(p->device) >= 0 && strncmp(st->url,"cddb",4) == 0) {
-    i = cddb_resolve(p->device, &xmcd_file);
-    if(i == 0) {
-      cddb_info = cddb_parse_xmcd(xmcd_file);
-      free(xmcd_file);
-    }
-  }
-#endif
-  
-#ifndef HAVE_LIBCDIO
-  if(p->generic_dev)
-    cdd = cdda_identify_scsi(p->generic_dev,p->device,0,NULL);
-  else
-#endif
-#if defined(__NetBSD__)
-    cdd = cdda_identify_scsi(p->device,p->device,0,NULL);
-#else
-    cdd = cdda_identify(p->device,0,NULL);
-#endif
-
-  if(!cdd) {
-    mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_MPDEMUX_CDDA_CantOpenCDDADevice);
-    m_struct_free(&stream_opts,opts);
-    free(cddb_info);
-    return STREAM_ERROR;
-  }
-
-  cdda_verbose_set(cdd, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);
-
-  if(p->sector_size) {
-    cdd->nsectors = p->sector_size;
-#ifndef HAVE_LIBCDIO
-    cdd->bigbuff = p->sector_size * CD_FRAMESIZE_RAW;
-#endif
-  }
-
-  if(cdda_open(cdd) != 0) {
-    mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_MPDEMUX_CDDA_CantOpenDisc);
-    cdda_close(cdd);
-    m_struct_free(&stream_opts,opts);
-    free(cddb_info);
-    return STREAM_ERROR;
-  }
-
-  cd_info = cd_info_new();
-  mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_MPDEMUX_CDDA_AudioCDFoundWithNTracks,cdda_tracks(cdd));
-  for(i=0;i<cdd->tracks;i++) {
-	  char track_name[80];
-	  long sec=cdda_track_firstsector(cdd,i+1);
-	  long off=cdda_track_lastsector(cdd,i+1)-sec+1;
-
-	  sprintf(track_name, "Track %d", i+1);
-	  cd_info_add_track(cd_info, track_name, i+1, (unsigned int)(off/(60*75)), (unsigned int)((off/75)%60), (unsigned int)(off%75), sec, off );
-	  audiolen += off;
-  }
-  cd_info->min  = (unsigned int)(audiolen/(60*75));
-  cd_info->sec  = (unsigned int)((audiolen/75)%60);
-  cd_info->msec = (unsigned int)(audiolen%75);
-
-  priv = malloc(sizeof(cdda_priv));
-  memset(priv, 0, sizeof(cdda_priv));
-  priv->cd = cdd;
-  priv->cd_info = cd_info;
-
-  if(p->toc_bias)
-    offset -= cdda_track_firstsector(cdd,1);
-
-  if(offset) {
-    int i;
-    for(i = 0 ; i < cdd->tracks + 1 ; i++)
-      cdd->disc_toc[i].dwStartSector += offset;
-  }
-
-  if(p->speed)
-    cdda_speed_set(cdd,p->speed);
-
-  last_track = cdda_tracks(cdd);
-  if (p->span.start > last_track) p->span.start = last_track;
-  if (p->span.end < p->span.start) p->span.end = p->span.start;
-  if (p->span.end > last_track) p->span.end = last_track;
-  if(p->span.start)
-    priv->start_sector = cdda_track_firstsector(cdd,p->span.start);
-  else
-    priv->start_sector = cdda_disc_firstsector(cdd);
-
-  if(p->span.end) {
-    priv->end_sector = cdda_track_lastsector(cdd,p->span.end);
-  } else
-    priv->end_sector = cdda_disc_lastsector(cdd);
-
-  priv->cdp = paranoia_init(cdd);
-  if(priv->cdp == NULL) {
-    cdda_close(cdd);
-    free(priv);
-    cd_info_free(cd_info);
-    m_struct_free(&stream_opts,opts);
-    free(cddb_info);
-    return STREAM_ERROR;
-  }
-
-  if(mode == 0)
-    mode = PARANOIA_MODE_DISABLE;
-  else if(mode == 1)
-    mode = PARANOIA_MODE_OVERLAP;
-  else
-    mode = PARANOIA_MODE_FULL;
-  
-  if(p->no_skip)
-    mode |= PARANOIA_MODE_NEVERSKIP;
-#ifndef HAVE_LIBCDIO
-  paranoia_modeset(cdd, mode);
-
-  if(p->search_overlap >= 0)
-    paranoia_overlapset(cdd,p->search_overlap);
-#else
-  paranoia_modeset(priv->cdp, mode);
-
-  if(p->search_overlap >= 0)
-    paranoia_overlapset(priv->cdp,p->search_overlap);
-#endif
-
-  paranoia_seek(priv->cdp,priv->start_sector,SEEK_SET);
-  priv->sector = priv->start_sector;
-
-#ifdef MPLAYER_NETWORK
-  if(cddb_info) {
-    cd_info_free(cd_info);
-    priv->cd_info = cddb_info;
-    cd_info_debug( cddb_info );
-  }
-#endif
-
-  st->priv = priv;
-  st->start_pos = priv->start_sector*CD_FRAMESIZE_RAW;
-  st->end_pos = priv->end_sector*CD_FRAMESIZE_RAW;
-  st->type = STREAMTYPE_CDDA;
-  st->sector_size = CD_FRAMESIZE_RAW;
-
-  st->fill_buffer = fill_buffer;
-  st->seek = seek;
-  st->close = close_cdda;
-
-  *file_format = DEMUXER_TYPE_RAWAUDIO;
-
-  m_struct_free(&stream_opts,opts);
-
-  return STREAM_OK;
-}
-
-#ifndef HAVE_LIBCDIO
-static void cdparanoia_callback(long inpos, int function) {
-#else
-static void cdparanoia_callback(long int inpos, paranoia_cb_mode_t function) {
-#endif
-}
-
-static int fill_buffer(stream_t* s, char* buffer, int max_len) {
-  cdda_priv* p = (cdda_priv*)s->priv;
-  cd_track_t *cd_track;
-  int16_t * buf;
-  int i;
-  
-  buf = paranoia_read(p->cdp,cdparanoia_callback);
-
-#ifdef WORDS_BIGENDIAN 
-  for(i=0;i<CD_FRAMESIZE_RAW/2;i++)
-          buf[i]=le2me_16(buf[i]);
-#endif
-
-  p->sector++;
-  s->pos = p->sector*CD_FRAMESIZE_RAW;
-  memcpy(buffer,buf,CD_FRAMESIZE_RAW);
-
-  if((p->sector < p->start_sector) || (p->sector >= p->end_sector)) {
-    s->eof = 1;
-    return 0;
-  }
-
-  for(i=0;i<p->cd->tracks;i++){
-	  if(p->cd->disc_toc[i].dwStartSector==p->sector-1) {
-		  cd_track = cd_info_get_track(p->cd_info, i+1);
-//printf("Track %d, sector=%d\n", i, p->sector-1);
-		  if( cd_track!=NULL ) {
-			mp_msg(MSGT_SEEK, MSGL_INFO, "\n%s\n", cd_track->name); 
-			mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CDDA_TRACK=%d\n", cd_track->track_nb);
-		  }
-		  break;
-	  }
-  }
-
-  
-  return CD_FRAMESIZE_RAW;
-}
-
-static int seek(stream_t* s,off_t newpos) {
-  cdda_priv* p = (cdda_priv*)s->priv;
-  cd_track_t *cd_track;
-  int sec;
-  int current_track=0, seeked_track=0;
-  int i;
-  
-  s->pos = newpos;
-  if(s->pos < 0) {
-    s->eof = 1;
-    return 0;
-  }
-
-  sec = s->pos/CD_FRAMESIZE_RAW;
-//printf("pos: %d, sec: %d ## %d\n", (int)s->pos, (int)sec, CD_FRAMESIZE_RAW);
-//printf("sector: %d  new: %d\n", p->sector, sec );
- 
-  for(i=0;i<p->cd->tracks;i++){
-//        printf("trk #%d: %d .. %d\n",i,p->cd->disc_toc[i].dwStartSector,p->cd->disc_toc[i+1].dwStartSector);
-	if( p->sector>=p->cd->disc_toc[i].dwStartSector && p->sector<p->cd->disc_toc[i+1].dwStartSector ) {
-		current_track = i;
-	}
-	if( sec>=p->cd->disc_toc[i].dwStartSector && sec<p->cd->disc_toc[i+1].dwStartSector ) {
-		seeked_track = i;
-	}
-  }
-//printf("current: %d, seeked: %d\n", current_track, seeked_track);
-	if( current_track!=seeked_track ) {
-//printf("Track %d, sector=%d\n", seeked_track, sec);
-		  cd_track = cd_info_get_track(p->cd_info, seeked_track+1);
-		  if( cd_track!=NULL ) {
-			  mp_msg(MSGT_SEEK, MSGL_INFO, "\n%s\n", cd_track->name);
-			  mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CDDA_TRACK=%d\n", cd_track->track_nb);
-		  }
-
-	}
-#if 0
-  if(sec < p->start_sector)
-    sec = p->start_sector;
-  else if(sec > p->end_sector)
-    sec = p->end_sector;
-#endif
-
-  p->sector = sec;
-//  s->pos = sec*CD_FRAMESIZE_RAW;
-
-//printf("seek: %d, sec: %d\n", (int)s->pos, sec);
-  paranoia_seek(p->cdp,sec,SEEK_SET);
-  return 1;
-}
-
-static void close_cdda(stream_t* s) {
-  cdda_priv* p = (cdda_priv*)s->priv;
-  paranoia_free(p->cdp);
-  cdda_close(p->cd);
-  cd_info_free(p->cd_info);
-  free(p);
-}
-
-stream_info_t stream_info_cdda = {
-  "CDDA",
-  "cdda",
-  "Albeu",
-  "",
-  open_cdda,
-  { "cdda", "cddb", NULL },
-  &stream_opts,
-  1 // Urls are an option string
-};
--- a/stream/cddb.c	Mon Jul 31 17:39:17 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,878 +0,0 @@
-/*
- * CDDB HTTP protocol 
- * by Bertrand Baudet <bertrand_baudet@yahoo.com>
- * (C) 2002, MPlayer team.
- *
- * Implementation follow the freedb.howto1.06.txt specification
- * from http://freedb.freedb.org
- * 
- * discid computation by Jeremy D. Zawodny
- *	 Copyright (c) 1998-2000 Jeremy D. Zawodny <Jeremy@Zawodny.com>
- *	 Code release under GPL
- *
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#ifdef WIN32
-#ifdef __MINGW32__
-#define mkdir(a,b) mkdir(a)
-#endif
-#include <windows.h>
-#ifdef HAVE_WINSOCK2
-#include <winsock2.h>
-#endif
-#else
-#include <netdb.h>
-#include <sys/ioctl.h>
-#endif
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "mp_msg.h"
-#include "help_mp.h"
-
-#if defined(__linux__)
-	#include <linux/cdrom.h>
-#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
-	#include <sys/cdio.h>
-#elif defined(WIN32)
-        #include <ddk/ntddcdrm.h>
-#elif (__bsdi__)
-        #include <dvd.h>
-#endif
-
-#include "cdd.h"
-#include "version.h"
-#include "stream.h"
-#include "network.h"
-
-#define DEFAULT_FREEDB_SERVER	"freedb.freedb.org"
-#define DEFAULT_CACHE_DIR	"/.cddb/"
-
-stream_t* open_cdda(char *dev, char *track);
-
-static cd_toc_t cdtoc[100];
-static int cdtoc_last_track;
-
-#if defined(__linux__) || defined(__bsdi__)
-int 
-read_toc(const char *dev) {
-	int drive;
-	struct cdrom_tochdr tochdr;
-	struct cdrom_tocentry tocentry;
-	int i;
-
-	drive = open(dev, O_RDONLY | O_NONBLOCK);
-	if( drive<0 ) {
-		return drive;
-	}
-	
-	ioctl(drive, CDROMREADTOCHDR, &tochdr);
-	for (i = tochdr.cdth_trk0; i <= tochdr.cdth_trk1; i++) {
-		tocentry.cdte_track = i;
-		tocentry.cdte_format = CDROM_MSF;
-		ioctl(drive, CDROMREADTOCENTRY, &tocentry);
-		cdtoc[i-1].min = tocentry.cdte_addr.msf.minute;
-		cdtoc[i-1].sec = tocentry.cdte_addr.msf.second;
-		cdtoc[i-1].frame = tocentry.cdte_addr.msf.frame;
-		cdtoc[i-1].frame += cdtoc[i-1].min*60*75;
-		cdtoc[i-1].frame += cdtoc[i-1].sec*75;
-	}
-	tocentry.cdte_track = 0xAA;
-	tocentry.cdte_format = CDROM_MSF;
-	ioctl(drive, CDROMREADTOCENTRY, &tocentry);
-	cdtoc[tochdr.cdth_trk1].min = tocentry.cdte_addr.msf.minute;
-	cdtoc[tochdr.cdth_trk1].sec = tocentry.cdte_addr.msf.second;
-	cdtoc[tochdr.cdth_trk1].frame = tocentry.cdte_addr.msf.frame;
-	cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].min*60*75;
-	cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].sec*75;
-	close(drive);
-	return tochdr.cdth_trk1;
-}
-
-#elif defined(WIN32)
-int
-read_toc(const char *dev) {
-        HANDLE drive;
-        DWORD r;
-        CDROM_TOC toc;
-        char device[10];
-        int i;
-
-        sprintf(device, "\\\\.\\%s", dev);
-        drive = CreateFile(device, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
-
-        if(!DeviceIoControl(drive, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(CDROM_TOC), &r, 0)) {
-                mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToReadTOC);
-                return 0;
-        }
-
-        for (i = toc.FirstTrack; i <= toc.LastTrack; i++) {
-                toc.FirstTrack = i;
-		cdtoc[i-1].min = toc.TrackData[i - 1].Address[1];
-		cdtoc[i-1].sec = toc.TrackData[i - 1].Address[2];
-		cdtoc[i-1].frame = toc.TrackData[i - 1].Address[3];
-		cdtoc[i-1].frame += cdtoc[i-1].min*60*75;
-		cdtoc[i-1].frame += cdtoc[i-1].sec*75;
-        }
-        toc.FirstTrack = 0xAA;
-        cdtoc[toc.LastTrack].min = toc.TrackData[toc.LastTrack].Address[1];
-        cdtoc[toc.LastTrack].sec = toc.TrackData[toc.LastTrack].Address[2];
-        cdtoc[toc.LastTrack].frame = toc.TrackData[toc.LastTrack].Address[3];
-        cdtoc[toc.LastTrack].frame += cdtoc[toc.LastTrack].min*60*75;
-        cdtoc[toc.LastTrack].frame += cdtoc[toc.LastTrack].sec*75;
-        CloseHandle(drive);
-        return toc.LastTrack;
-}
-
-#elif defined(__FreeBSD__) || defined(__DragonFly__)
-int 
-read_toc(const char *dev) {
-	int drive;
-	struct ioc_toc_header tochdr;
-	struct ioc_read_toc_single_entry tocentry;
-	int i;
-
-	drive = open(dev, O_RDONLY | O_NONBLOCK);
-	if( drive<0 ) {
-		return drive;
-	}
-
-	ioctl(drive, CDIOREADTOCHEADER, &tochdr);
-	for (i = tochdr.starting_track; i <= tochdr.ending_track; i++) {
-		tocentry.track = i;
-		tocentry.address_format = CD_MSF_FORMAT;
-		ioctl(drive, CDIOREADTOCENTRY, &tocentry);
-		cdtoc[i-1].min = tocentry.entry.addr.msf.minute;
-		cdtoc[i-1].sec = tocentry.entry.addr.msf.second;
-		cdtoc[i-1].frame = tocentry.entry.addr.msf.frame;
-		cdtoc[i-1].frame += cdtoc[i-1].min*60*75;
-		cdtoc[i-1].frame += cdtoc[i-1].sec*75;
-	}
-	tocentry.track = 0xAA;
-	tocentry.address_format = CD_MSF_FORMAT;
-	ioctl(drive, CDIOREADTOCENTRY, &tocentry);
-	cdtoc[tochdr.ending_track].min = tocentry.entry.addr.msf.minute;
-	cdtoc[tochdr.ending_track].sec = tocentry.entry.addr.msf.second;
-	cdtoc[tochdr.ending_track].frame = tocentry.entry.addr.msf.frame;
-	cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].min*60*75;
-	cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].sec*75;
-	close(drive);
-	return tochdr.ending_track;
-}
-
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
-int
-read_toc(const char *dev) {
-	int drive;
-	struct ioc_toc_header tochdr;
-	struct ioc_read_toc_entry tocentry;
-	int i;
-	struct cd_toc_entry toc_buffer;
-
-	drive = open(dev, O_RDONLY | O_NONBLOCK);
-	if( drive<0 ) {
-		return drive;
-	}
-
-	ioctl(drive, CDIOREADTOCHEADER, &tochdr);
-	for (i = tochdr.starting_track; i <= tochdr.ending_track; i++) {
-		tocentry.starting_track = i;
-		tocentry.address_format = CD_MSF_FORMAT;
-		tocentry.data = &toc_buffer;
-		tocentry.data_len = sizeof(toc_buffer);
-		ioctl(drive, CDIOREADTOCENTRYS, &tocentry);
-		cdtoc[i-1].min = toc_buffer.addr.msf.minute;
-		cdtoc[i-1].sec = toc_buffer.addr.msf.second;
-		cdtoc[i-1].frame = toc_buffer.addr.msf.frame;
-		cdtoc[i-1].frame += cdtoc[i-1].min*60*75;
-		cdtoc[i-1].frame += cdtoc[i-1].sec*75;
-	}
-	tocentry.starting_track = 0xAA;
-	tocentry.address_format = CD_MSF_FORMAT;
-	ioctl(drive, CDIOREADTOCENTRYS, &tocentry);
-	cdtoc[tochdr.ending_track].min = toc_buffer.addr.msf.minute;
-	cdtoc[tochdr.ending_track].sec = toc_buffer.addr.msf.second;
-	cdtoc[tochdr.ending_track].frame = toc_buffer.addr.msf.frame;
-	cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].min*60*75;
-	cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].sec*75;
-	close(drive);
-	return tochdr.ending_track;
-}
-#endif
-
-/** 
-\brief Reads TOC from CD in the given device and prints the number of tracks
-       and the length of each track in minute:second:frame format.
-\param *dev the device to analyse
-\return if the command line -identify is given, returns the last track of
-        the TOC or -1 if the TOC can't be read,
-        otherwise just returns 0 and let cddb_resolve the TOC
-*/
-int cdd_identify(const char *dev)
-{
-	cdtoc_last_track = 0;
-	if (mp_msg_test(MSGT_IDENTIFY, MSGL_INFO))
-	{
-		int i, min, sec, frame;
-		cdtoc_last_track = read_toc(dev);
-		if (cdtoc_last_track < 0) {
-			mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToOpenDevice, dev);
-			return -1;
-		}
-		mp_msg(MSGT_GLOBAL, MSGL_INFO, "ID_CDDA_TRACKS=%d\n", cdtoc_last_track);
-		for (i = 1; i <= cdtoc_last_track; i++)
-		{
-			frame = cdtoc[i].frame - cdtoc[i-1].frame;
-			sec = frame / 75;
-			frame -= sec * 75;
-			min = sec / 60;
-			sec -= min * 60;
-			mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CDDA_TRACK_%d_MSF=%02d:%02d:%02d\n", i, min, sec, frame);
-		}
-	}
-	return cdtoc_last_track;
-}
-
-unsigned int 
-cddb_sum(int n) {
-	unsigned int ret;
-
-	ret = 0;
-	while (n > 0) {
-		ret += (n % 10);
-		n /= 10;
-	}
-	return ret;
-}
-
-unsigned long 
-cddb_discid(int tot_trks) {
-	unsigned int i, t = 0, n = 0;
-
-	i = 0;
-	while (i < (unsigned int)tot_trks) {
-		n = n + cddb_sum((cdtoc[i].min * 60) + cdtoc[i].sec);
-		i++;
-	}
-	t = ((cdtoc[tot_trks].min * 60) + cdtoc[tot_trks].sec) -
-		((cdtoc[0].min * 60) + cdtoc[0].sec);
-	return ((n % 0xff) << 24 | t << 8 | tot_trks);
-}
-
-
-
-int
-cddb_http_request(char *command, int (*reply_parser)(HTTP_header_t*,cddb_data_t*), cddb_data_t *cddb_data) {
-	char request[4096];
-	int fd, ret = 0;
-	URL_t *url;
-	HTTP_header_t *http_hdr;
-	
-	if( reply_parser==NULL || command==NULL || cddb_data==NULL ) return -1;
-	
-	sprintf( request, "http://%s/~cddb/cddb.cgi?cmd=%s%s&proto=%d", cddb_data->freedb_server, command, cddb_data->cddb_hello, cddb_data->freedb_proto_level );
-	mp_msg(MSGT_OPEN, MSGL_INFO,"Request[%s]\n", request );
-
-	url = url_new(request);
-	if( url==NULL ) {
-		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_NotAValidURL);
-		return -1;
-	}
-	
-	fd = http_send_request(url,0);
-	if( fd<0 ) {
-		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToSendHTTPRequest);
-		return -1;
-	}
-
-	http_hdr = http_read_response( fd );
-	if( http_hdr==NULL ) {
-		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToReadHTTPResponse);
-		return -1;
-	}
-
-	http_debug_hdr(http_hdr);
-	mp_msg(MSGT_OPEN, MSGL_INFO,"body=[%s]\n", http_hdr->body );
-
-	switch(http_hdr->status_code) {
-		case 200:
-			ret = reply_parser(http_hdr, cddb_data);
-			break;
-		case 400:
-			mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_HTTPErrorNOTFOUND);
-			break;
-		default:
-			mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_HTTPErrorUnknown);
-	}
-
-	http_free( http_hdr );
-	url_free( url );
-	
-	return ret;
-}
-
-int
-cddb_read_cache(cddb_data_t *cddb_data) {
-	char file_name[100];
-	struct stat stats;
-	int file_fd, ret;
-	size_t file_size;
-
-	if( cddb_data==NULL || cddb_data->cache_dir==NULL ) return -1;
-	
-	sprintf( file_name, "%s%08lx", cddb_data->cache_dir, cddb_data->disc_id);
-	
-	file_fd = open(file_name, O_RDONLY
-#ifdef WIN32
-	| O_BINARY
-#endif
-	);
-	if( file_fd<0 ) {
-		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_NoCacheFound);
-		return -1;
-	}
-
-	ret = fstat( file_fd, &stats );
-	if( ret<0 ) {
-		perror("fstat");
-		file_size = 4096;
-	} else {
-		file_size = stats.st_size;
-	}
-	
-	cddb_data->xmcd_file = malloc(file_size);
-	if( cddb_data->xmcd_file==NULL ) {
-		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MemAllocFailed);
-		close(file_fd);
-		return -1;
-	}
-	cddb_data->xmcd_file_size = read(file_fd, cddb_data->xmcd_file, file_size);
-	if( cddb_data->xmcd_file_size!=file_size ) {
-		mp_msg(MSGT_DEMUX, MSGL_WARN, MSGTR_MPDEMUX_CDDB_NotAllXMCDFileHasBeenRead);
-		close(file_fd);
-		return -1;
-	}
-	
-	close(file_fd);
-	
-	return 0;
-}
-
-int
-cddb_write_cache(cddb_data_t *cddb_data) {
-	// We have the file, save it for cache.
-	struct stat file_stat;
-	char file_name[100];
-	int file_fd, ret;
-	int wrote=0;
-
-	if( cddb_data==NULL || cddb_data->cache_dir==NULL ) return -1;
-
-	// Check if the CDDB cache dir exist
-	ret = stat( cddb_data->cache_dir, &file_stat );
-	if( ret<0 ) {
-		// Directory not present, create it.
-		ret = mkdir( cddb_data->cache_dir, 0755 );
-#ifdef __MINGW32__
-		if( ret<0 && errno != EEXIST ) {
-#else
-		if( ret<0 ) {
-#endif
-			perror("mkdir");
-			mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToCreateDirectory, cddb_data->cache_dir);
-			return -1;
-		}
-	}
-	
-	sprintf( file_name, "%s%08lx", cddb_data->cache_dir, cddb_data->disc_id );
-	
-	file_fd = creat(file_name, S_IREAD|S_IWRITE);
-	if( file_fd<0 ) {
-		perror("create");
-		return -1;
-	}
-	
-	wrote = write(file_fd, cddb_data->xmcd_file, cddb_data->xmcd_file_size);
-	if( wrote<0 ) {
-		perror("write");
-		close(file_fd);
-		return -1;
-	}
-	if( (unsigned int)wrote!=cddb_data->xmcd_file_size ) {
-		mp_msg(MSGT_DEMUX, MSGL_WARN, MSGTR_MPDEMUX_CDDB_NotAllXMCDFileHasBeenWritten);
-		close(file_fd);
-		return -1;
-	}
-	
-	close(file_fd);
-
-	return 0;
-}
-
-int
-cddb_read_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
-	unsigned long disc_id;
-	char category[100];
-	char *ptr=NULL, *ptr2=NULL;
-	int ret, status;
-
-	if( http_hdr==NULL || cddb_data==NULL ) return -1;
-	
-	ret = sscanf( http_hdr->body, "%d ", &status);
-	if( ret!=1 ) {
-		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);
-		return -1;
-	}
-
-	switch(status) {
-		case 210:
-			ret = sscanf( http_hdr->body, "%d %s %08lx", &status, category, &disc_id);
-			if( ret!=3 ) {
-				mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);
-				return -1;
-			}
-			// Check if it's a xmcd database file
-			ptr = strstr(http_hdr->body, "# xmcd");
-			if( ptr==NULL ) {
-				mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_InvalidXMCDDatabaseReturned);
-				return -1;
-			}
-			// Ok found the beginning of the file
-			// look for the end
-			ptr2 = strstr(ptr, "\r\n.\r\n");
-			if( ptr2==NULL ) {
-				ptr2 = strstr(ptr, "\n.\n");
-				if( ptr2==NULL ) {
-					mp_msg(MSGT_DEMUX, MSGL_FIXME, "Unable to find '.'\n");
-					ptr2=ptr+strlen(ptr); //return -1;
-				}
-			}
-			// Ok found the end
-			// do a sanity check
-			if( http_hdr->body_size<(unsigned int)(ptr2-ptr) ) {
-				mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_UnexpectedFIXME);
-				return -1;
-			}
-			cddb_data->xmcd_file = ptr;
-			cddb_data->xmcd_file_size = ptr2-ptr+2;
-			cddb_data->xmcd_file[cddb_data->xmcd_file_size] = '\0';
-			// Avoid the http_free function to free the xmcd file...save a mempcy...
-			http_hdr->body = NULL;
-			http_hdr->body_size = 0;
-			return cddb_write_cache(cddb_data);
-		default:
-			mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_UnhandledCode);
-	}
-	return 0;
-}
-
-int
-cddb_request_titles(cddb_data_t *cddb_data) {
-	char command[1024];
-	sprintf( command, "cddb+read+%s+%08lx", cddb_data->category, cddb_data->disc_id);
-	return cddb_http_request(command, cddb_read_parse, cddb_data); 
-}
-
-int
-cddb_parse_matches_list(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
-	char album_title[100];
-	char *ptr = NULL;
-	int ret;
-	
-	ptr = strstr(http_hdr->body, "\n");
-	if( ptr==NULL ) {
-		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_UnableToFindEOL);
-		return -1;
-	}
-	ptr++;
-	// We have a list of exact/inexact matches, so which one do we use?
-	// So let's take the first one.
-	ret = sscanf(ptr, "%s %08lx %s", cddb_data->category, &(cddb_data->disc_id), album_title);
-	if( ret!=3 ) {
-		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);
-		return -1;
-	}
-	ptr = strstr(http_hdr->body, album_title);
-	if( ptr!=NULL ) {
-		char *ptr2;
-		int len;
-		ptr2 = strstr(ptr, "\n");
-		if( ptr2==NULL ) {
-			len = (http_hdr->body_size)-(ptr-(http_hdr->body));
-		} else {
-			len = ptr2-ptr+1;
-		}
-		strncpy(album_title, ptr, len);
-		album_title[len-2]='\0';
-	}
-	mp_msg(MSGT_DEMUX, MSGL_STATUS, MSGTR_MPDEMUX_CDDB_ParseOKFoundAlbumTitle, album_title);
-	return 0;
-}
-
-int
-cddb_query_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
-	char album_title[100];
-	char *ptr = NULL;
-	int ret, status;
-	
-	ret = sscanf( http_hdr->body, "%d ", &status);
-	if( ret!=1 ) {
-		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);
-		return -1;
-	}
-
-	switch(status) {
-		case 200:
-			// Found exact match
-			ret = sscanf(http_hdr->body, "%d %s %08lx %s", &status, cddb_data->category, &(cddb_data->disc_id), album_title);
-			if( ret!=4 ) {
-				mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);
-				return -1;
-			}
-			ptr = strstr(http_hdr->body, album_title);
-			if( ptr!=NULL ) {
-				char *ptr2;
-				int len;
-				ptr2 = strstr(ptr, "\n");
-				if( ptr2==NULL ) {
-					len = (http_hdr->body_size)-(ptr-(http_hdr->body));
-				} else {
-					len = ptr2-ptr+1;
-				}
-				strncpy(album_title, ptr, len);
-				album_title[len-2]='\0';
-			}
-			mp_msg(MSGT_DEMUX, MSGL_STATUS, MSGTR_MPDEMUX_CDDB_ParseOKFoundAlbumTitle, album_title);
-			return cddb_request_titles(cddb_data);
-		case 202:
-			// No match found
-			mp_msg(MSGT_DEMUX, MSGL_WARN, MSGTR_MPDEMUX_CDDB_AlbumNotFound);
-			break;
-		case 210:
-			// Found exact matches, list follows
-			cddb_parse_matches_list(http_hdr, cddb_data);
-			return cddb_request_titles(cddb_data);
-/*
-body=[210 Found exact matches, list follows (until terminating `.')
-misc c711930d Santana / Supernatural
-rock c711930d Santana / Supernatural
-blues c711930d Santana / Supernatural
-.]
-*/	
-		case 211:
-			// Found inexact matches, list follows
-			cddb_parse_matches_list(http_hdr, cddb_data);
-			return cddb_request_titles(cddb_data);
-		case 500:
-			mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_ServerReturnsCommandSyntaxErr);
-			break;
-		default:
-			mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_UnhandledCode);	
-	}
-	return -1;
-}
-
-int
-cddb_proto_level_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
-	int max;
-	int ret, status;
-	char *ptr;
-	
-	ret = sscanf( http_hdr->body, "%d ", &status);
-	if( ret!=1 ) {
-		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);	
-		return -1;
-	}
-
-	switch(status) {
-		case 210:
-			ptr = strstr(http_hdr->body, "max proto:");
-			if( ptr==NULL ) {
-				mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);
-				return -1;
-			}
-			ret = sscanf(ptr, "max proto: %d", &max);
-			if( ret!=1 ) {
-				mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);
-				return -1;
-			}
-			cddb_data->freedb_proto_level = max;
-			return 0;
-		default:
-			mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_UnhandledCode);	
-	}
-	return -1;
-}
-
-int
-cddb_get_proto_level(cddb_data_t *cddb_data) {
-	return cddb_http_request("stat", cddb_proto_level_parse, cddb_data);
-}
-
-int
-cddb_freedb_sites_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
-	int ret, status;
-
-	ret = sscanf( http_hdr->body, "%d ", &status);
-	if( ret!=1 ) {
-		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);
-		return -1;
-	}
-
-	switch(status) {
-		case 210:
-			// TODO: Parse the sites
-			ret = cddb_data->anonymous;	// For gcc complaining about unused parameter.
-			return 0;
-		case 401:
-			mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_NoSitesInfoAvailable);
-			break;
-		default:
-			mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_UnhandledCode);
-	}
-	return -1;
-}
-
-int
-cddb_get_freedb_sites(cddb_data_t *cddb_data) {
-	return cddb_http_request("sites", cddb_freedb_sites_parse, cddb_data);
-}
-
-void
-cddb_create_hello(cddb_data_t *cddb_data) {
-	char host_name[51];
-	char *user_name;
-	
-	if( cddb_data->anonymous ) {	// Default is anonymous
-		/* Note from Eduardo Pérez Ureta <eperez@it.uc3m.es> : 
-		 * We don't send current user/host name in hello to prevent spam.
-		 * Software that sends this is considered spyware
-		 * that most people don't like.
-		 */
-		user_name = "anonymous";
-		strcpy(host_name, "localhost");
-	} else {
-		if( gethostname(host_name, 50)<0 ) {
-			strcpy(host_name, "localhost");
-		}
-		user_name = getenv("LOGNAME");
-	}
-	sprintf( cddb_data->cddb_hello, "&hello=%s+%s+%s+%s", user_name, host_name, "MPlayer", VERSION );
-}
-
-int 
-cddb_retrieve(cddb_data_t *cddb_data) {
-	char offsets[1024], command[1024];
-	char *ptr;
-	unsigned int i, time_len;
-	int ret;
-
-	ptr = offsets;
-	for( i=0; i<cddb_data->tracks ; i++ ) {
-		ptr += sprintf(ptr, "%d+", cdtoc[i].frame );
-		if (ptr-offsets > sizeof offsets - 40) break;
-	}
-	ptr[0]=0;
-	time_len = (cdtoc[cddb_data->tracks].frame)/75;
-	
-	cddb_data->freedb_server = DEFAULT_FREEDB_SERVER;
-	cddb_data->freedb_proto_level = 1;
-	cddb_data->xmcd_file = NULL;
-
-	cddb_create_hello(cddb_data);
-	if( cddb_get_proto_level(cddb_data)<0 ) {
-		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToGetProtocolLevel);
-		return -1;
-	}
-
-	//cddb_get_freedb_sites(&cddb_data);
-
-	sprintf(command, "cddb+query+%08lx+%d+%s%d", cddb_data->disc_id, cddb_data->tracks, offsets, time_len );
-	ret = cddb_http_request(command, cddb_query_parse, cddb_data);
-	if( ret<0 ) return -1;
-
-	if( cddb_data->cache_dir!=NULL ) {
-		free(cddb_data->cache_dir);
-	}
-	return 0;
-}
-
-int
-cddb_resolve(const char *dev, char **xmcd_file) {
-	char cddb_cache_dir[] = DEFAULT_CACHE_DIR;
-	char *home_dir = NULL;
-	cddb_data_t cddb_data;
-
-	if (cdtoc_last_track <= 0)
-	{
-	    cdtoc_last_track = read_toc(dev);
-	    if (cdtoc_last_track < 0) {
-		mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToOpenDevice, dev);
-		return -1;
-	    }
-	}
-	cddb_data.tracks = cdtoc_last_track;
-	cddb_data.disc_id = cddb_discid(cddb_data.tracks);
-	cddb_data.anonymous = 1;	// Don't send user info by default
-
-	// Check if there is a CD in the drive
-	// FIXME: That's not really a good way to check
-	if( cddb_data.disc_id==0 ) {
-		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_NoCDInDrive);
-		return -1;
-	}
-	
-	home_dir = getenv("HOME");
-#ifdef __MINGW32__
-	if( home_dir==NULL ) home_dir = getenv("USERPROFILE");
-	if( home_dir==NULL ) home_dir = getenv("HOMEPATH");
-	// Last resort, store the cddb cache in the mplayer directory
-	if( home_dir==NULL ) home_dir = (char *)get_path("");
-#endif
-	if( home_dir==NULL ) {
-		cddb_data.cache_dir = NULL;
-	} else {
-		cddb_data.cache_dir = malloc(strlen(home_dir)+strlen(cddb_cache_dir)+1);
-		if( cddb_data.cache_dir==NULL ) {
-			mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MemAllocFailed);
-			return -1;
-		}
-		sprintf(cddb_data.cache_dir, "%s%s", home_dir, cddb_cache_dir );
-	}
-
-	// Check for a cached file
-	if( cddb_read_cache(&cddb_data)<0 ) {
-		// No Cache found
-		if( cddb_retrieve(&cddb_data)<0 ) {
-			return -1;
-		}
-	}
-
-	if( cddb_data.xmcd_file!=NULL ) {
-//		printf("%s\n", cddb_data.xmcd_file );
-		*xmcd_file = cddb_data.xmcd_file;
-		return 0;
-	}
-	
-	return -1;
-}
-
-/*******************************************************************************************************************
- *
- * xmcd parser
- *
- *******************************************************************************************************************/
-char*
-xmcd_parse_dtitle(cd_info_t *cd_info, char *line) {
-	char *ptr, *album;
-	ptr = strstr(line, "DTITLE=");
-	if( ptr!=NULL ) {
-		ptr += 7;
-		album = strstr(ptr, "/");
-		if( album==NULL ) return NULL;
-		cd_info->album = malloc(strlen(album+2)+1);
-		if( cd_info->album==NULL ) {
-			return NULL;
-		}
-		strcpy( cd_info->album, album+2 );
-		album--;
-		album[0] = '\0';
-		cd_info->artist = malloc(strlen(ptr)+1);
-		if( cd_info->artist==NULL ) {
-			return NULL;
-		}
-		strcpy( cd_info->artist, ptr );
-	}
-	return ptr;
-}
-
-char*
-xmcd_parse_dgenre(cd_info_t *cd_info, char *line) {
-	char *ptr;
-	ptr = strstr(line, "DGENRE=");
-	if( ptr!=NULL ) {
-		ptr += 7;
-		cd_info->genre = malloc(strlen(ptr)+1);
-		if( cd_info->genre==NULL ) {
-			return NULL;
-		}
-		strcpy( cd_info->genre, ptr );
-	}
-	return ptr;
-}
-
-char*
-xmcd_parse_ttitle(cd_info_t *cd_info, char *line) {
-	unsigned int track_nb;
-	unsigned long sec, off;
-	char *ptr;
-	ptr = strstr(line, "TTITLE");
-	if( ptr!=NULL ) {
-		ptr += 6;
-		// Here we point to the track number
-		track_nb = atoi(ptr);
-		ptr = strstr(ptr, "=");
-		if( ptr==NULL ) return NULL;
-		ptr++;
-		
-		sec = cdtoc[track_nb].frame;
-		off = cdtoc[track_nb+1].frame-sec+1;
-
-		cd_info_add_track( cd_info, ptr, track_nb+1, (unsigned int)(off/(60*75)), (unsigned int)((off/75)%60), (unsigned int)(off%75), sec, off );
-	}
-	return ptr;
-}
-
-cd_info_t*
-cddb_parse_xmcd(char *xmcd_file) {
-	cd_info_t *cd_info = NULL;
-	int length, pos = 0;
-	char *ptr, *ptr2;
-	unsigned int audiolen;
-	if( xmcd_file==NULL ) return NULL;
-	
-	cd_info = cd_info_new();
-	if( cd_info==NULL ) {
-		return NULL;
-	}
-	
-	length = strlen(xmcd_file);
-	ptr = xmcd_file;
-	while( ptr!=NULL && pos<length ) {
-		// Read a line
-		ptr2 = ptr;
-		while( ptr2[0]!='\0' && ptr2[0]!='\r' && ptr2[0]!='\n' ) ptr2++;
-		if( ptr2[0]=='\0' ) {
-			break;
-		}
-		ptr2[0] = '\0';
-		// Ignore comments
-		if( ptr[0]!='#' ) {
-			// Search for the album title
-			if( xmcd_parse_dtitle(cd_info, ptr) );
-			// Search for the genre
-			else if( xmcd_parse_dgenre(cd_info, ptr) );
-			// Search for a track title
-			else if( xmcd_parse_ttitle(cd_info, ptr) ) audiolen++;	// <-- audiolen++ to shut up gcc warning
-		}
-		if( ptr2[1]=='\n' ) ptr2++;
-		pos = (ptr2+1)-ptr;
-		ptr = ptr2+1;
-	}
-
-	audiolen = cdtoc[cd_info->nb_tracks].frame-cdtoc[0].frame;	
-	cd_info->min  = (unsigned int)(audiolen/(60*75));
-	cd_info->sec  = (unsigned int)((audiolen/75)%60);
-	cd_info->msec = (unsigned int)(audiolen%75);
-	
-	return cd_info;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stream/stream_cdda.c	Mon Jul 31 17:48:50 2006 +0000
@@ -0,0 +1,391 @@
+#include "config.h"
+
+#include "stream.h"
+#include "m_option.h"
+#include "m_struct.h"
+#include "bswap.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "demuxer.h"
+
+#include "cdd.h"
+
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#ifndef CD_FRAMESIZE_RAW
+#define CD_FRAMESIZE_RAW CDIO_CD_FRAMESIZE_RAW
+#endif
+
+
+extern char *cdrom_device;
+
+static struct cdda_params {
+  int speed;
+  int paranoia_mode;
+  char* generic_dev;
+  int sector_size;
+  int search_overlap;
+  int toc_bias;
+  int toc_offset;
+  int no_skip;
+  char* device;
+  m_span_t span;
+} cdda_dflts = {
+  -1,
+  0,
+  NULL,
+  0,
+  -1,
+  0,
+  0,
+  0,
+  NULL,
+  { 0, 0 }
+};
+
+#define ST_OFF(f) M_ST_OFF(struct cdda_params,f)
+m_option_t cdda_params_fields[] = {
+  { "speed", ST_OFF(speed), CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL },
+  { "paranoia", ST_OFF(paranoia_mode), CONF_TYPE_INT,M_OPT_RANGE, 0, 2, NULL },
+  { "generic-dev", ST_OFF(generic_dev), CONF_TYPE_STRING, 0, 0, 0, NULL },
+  { "sector-size", ST_OFF(sector_size), CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL },
+  { "overlap", ST_OFF(search_overlap), CONF_TYPE_INT, M_OPT_RANGE,0,75, NULL },
+  { "toc-bias", ST_OFF(toc_bias), CONF_TYPE_INT, 0, 0, 0, NULL },
+  { "toc-offset", ST_OFF(toc_offset), CONF_TYPE_INT, 0, 0, 0, NULL },
+  { "noskip", ST_OFF(no_skip), CONF_TYPE_FLAG, 0 , 0, 1, NULL },
+  { "skip", ST_OFF(no_skip), CONF_TYPE_FLAG, 0 , 1, 0, NULL },
+  { "device", ST_OFF(device), CONF_TYPE_STRING, 0, 0, 0, NULL },
+  { "span",  ST_OFF(span), CONF_TYPE_OBJ_PARAMS, 0, 0, 0, &m_span_params_def },
+  /// For url parsing
+  { "hostname", ST_OFF(span), CONF_TYPE_OBJ_PARAMS, 0, 0, 0, &m_span_params_def },
+  { "port", ST_OFF(speed), CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL },
+  { "filename", ST_OFF(device), CONF_TYPE_STRING, 0, 0, 0, NULL },
+  {NULL, NULL, 0, 0, 0, 0, NULL}
+};
+static struct m_struct_st stream_opts = {
+  "cdda",
+  sizeof(struct cdda_params),
+  &cdda_dflts,
+  cdda_params_fields
+};
+
+/// We keep these options but now they set the defaults
+m_option_t cdda_opts[] = {
+  { "speed", &cdda_dflts.speed, CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL },
+  { "paranoia", &cdda_dflts.paranoia_mode, CONF_TYPE_INT,M_OPT_RANGE, 0, 2, NULL },
+  { "generic-dev", &cdda_dflts.generic_dev, CONF_TYPE_STRING, 0, 0, 0, NULL },
+  { "sector-size", &cdda_dflts.sector_size, CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL },
+  { "overlap", &cdda_dflts.search_overlap, CONF_TYPE_INT, M_OPT_RANGE,0,75, NULL },
+  { "toc-bias", &cdda_dflts.toc_bias, CONF_TYPE_INT, 0, 0, 0, NULL },
+  { "toc-offset", &cdda_dflts.toc_offset, CONF_TYPE_INT, 0, 0, 0, NULL },
+  { "noskip", &cdda_dflts.no_skip, CONF_TYPE_FLAG, 0 , 0, 1, NULL },
+  { "skip", &cdda_dflts.no_skip, CONF_TYPE_FLAG, 0 , 1, 0, NULL },
+  { "device", &cdda_dflts.device, CONF_TYPE_STRING, 0, 0, 0, NULL },
+  { "span", &cdda_dflts.span, CONF_TYPE_OBJ_PARAMS, 0, 0, 0, &m_span_params_def },
+  {NULL, NULL, 0, 0, 0, 0, NULL}
+};
+
+extern int cdd_identify(const char *dev);
+extern int cddb_resolve(const char *dev, char **xmcd_file);
+extern cd_info_t* cddb_parse_xmcd(char *xmcd_file);
+
+static int seek(stream_t* s,off_t pos);
+static int fill_buffer(stream_t* s, char* buffer, int max_len);
+static void close_cdda(stream_t* s);
+
+static int open_cdda(stream_t *st,int m, void* opts, int* file_format) {
+  struct cdda_params* p = (struct cdda_params*)opts;
+  int mode = p->paranoia_mode;
+  int offset = p->toc_offset;
+#ifndef HAVE_LIBCDIO
+  cdrom_drive* cdd = NULL;
+#else
+  cdrom_drive_t* cdd = NULL;
+#endif
+  cdda_priv* priv;
+  cd_info_t *cd_info,*cddb_info = NULL;
+  unsigned int audiolen=0;
+  int last_track;
+  int i;
+  char *xmcd_file = NULL;
+
+  if(m != STREAM_READ) {
+    m_struct_free(&stream_opts,opts);
+    return STREAM_UNSUPORTED;
+  }
+
+  if(!p->device) {
+    if (cdrom_device)
+      p->device = strdup(cdrom_device);
+    else
+      p->device = strdup(DEFAULT_CDROM_DEVICE);
+  }
+
+#ifdef MPLAYER_NETWORK
+  // cdd_identify returns -1 if it cannot read the TOC,
+  // in which case there is no point in calling cddb_resolve
+  if(cdd_identify(p->device) >= 0 && strncmp(st->url,"cddb",4) == 0) {
+    i = cddb_resolve(p->device, &xmcd_file);
+    if(i == 0) {
+      cddb_info = cddb_parse_xmcd(xmcd_file);
+      free(xmcd_file);
+    }
+  }
+#endif
+  
+#ifndef HAVE_LIBCDIO
+  if(p->generic_dev)
+    cdd = cdda_identify_scsi(p->generic_dev,p->device,0,NULL);
+  else
+#endif
+#if defined(__NetBSD__)
+    cdd = cdda_identify_scsi(p->device,p->device,0,NULL);
+#else
+    cdd = cdda_identify(p->device,0,NULL);
+#endif
+
+  if(!cdd) {
+    mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_MPDEMUX_CDDA_CantOpenCDDADevice);
+    m_struct_free(&stream_opts,opts);
+    free(cddb_info);
+    return STREAM_ERROR;
+  }
+
+  cdda_verbose_set(cdd, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);
+
+  if(p->sector_size) {
+    cdd->nsectors = p->sector_size;
+#ifndef HAVE_LIBCDIO
+    cdd->bigbuff = p->sector_size * CD_FRAMESIZE_RAW;
+#endif
+  }
+
+  if(cdda_open(cdd) != 0) {
+    mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_MPDEMUX_CDDA_CantOpenDisc);
+    cdda_close(cdd);
+    m_struct_free(&stream_opts,opts);
+    free(cddb_info);
+    return STREAM_ERROR;
+  }
+
+  cd_info = cd_info_new();
+  mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_MPDEMUX_CDDA_AudioCDFoundWithNTracks,cdda_tracks(cdd));
+  for(i=0;i<cdd->tracks;i++) {
+	  char track_name[80];
+	  long sec=cdda_track_firstsector(cdd,i+1);
+	  long off=cdda_track_lastsector(cdd,i+1)-sec+1;
+
+	  sprintf(track_name, "Track %d", i+1);
+	  cd_info_add_track(cd_info, track_name, i+1, (unsigned int)(off/(60*75)), (unsigned int)((off/75)%60), (unsigned int)(off%75), sec, off );
+	  audiolen += off;
+  }
+  cd_info->min  = (unsigned int)(audiolen/(60*75));
+  cd_info->sec  = (unsigned int)((audiolen/75)%60);
+  cd_info->msec = (unsigned int)(audiolen%75);
+
+  priv = malloc(sizeof(cdda_priv));
+  memset(priv, 0, sizeof(cdda_priv));
+  priv->cd = cdd;
+  priv->cd_info = cd_info;
+
+  if(p->toc_bias)
+    offset -= cdda_track_firstsector(cdd,1);
+
+  if(offset) {
+    int i;
+    for(i = 0 ; i < cdd->tracks + 1 ; i++)
+      cdd->disc_toc[i].dwStartSector += offset;
+  }
+
+  if(p->speed)
+    cdda_speed_set(cdd,p->speed);
+
+  last_track = cdda_tracks(cdd);
+  if (p->span.start > last_track) p->span.start = last_track;
+  if (p->span.end < p->span.start) p->span.end = p->span.start;
+  if (p->span.end > last_track) p->span.end = last_track;
+  if(p->span.start)
+    priv->start_sector = cdda_track_firstsector(cdd,p->span.start);
+  else
+    priv->start_sector = cdda_disc_firstsector(cdd);
+
+  if(p->span.end) {
+    priv->end_sector = cdda_track_lastsector(cdd,p->span.end);
+  } else
+    priv->end_sector = cdda_disc_lastsector(cdd);
+
+  priv->cdp = paranoia_init(cdd);
+  if(priv->cdp == NULL) {
+    cdda_close(cdd);
+    free(priv);
+    cd_info_free(cd_info);
+    m_struct_free(&stream_opts,opts);
+    free(cddb_info);
+    return STREAM_ERROR;
+  }
+
+  if(mode == 0)
+    mode = PARANOIA_MODE_DISABLE;
+  else if(mode == 1)
+    mode = PARANOIA_MODE_OVERLAP;
+  else
+    mode = PARANOIA_MODE_FULL;
+  
+  if(p->no_skip)
+    mode |= PARANOIA_MODE_NEVERSKIP;
+#ifndef HAVE_LIBCDIO
+  paranoia_modeset(cdd, mode);
+
+  if(p->search_overlap >= 0)
+    paranoia_overlapset(cdd,p->search_overlap);
+#else
+  paranoia_modeset(priv->cdp, mode);
+
+  if(p->search_overlap >= 0)
+    paranoia_overlapset(priv->cdp,p->search_overlap);
+#endif
+
+  paranoia_seek(priv->cdp,priv->start_sector,SEEK_SET);
+  priv->sector = priv->start_sector;
+
+#ifdef MPLAYER_NETWORK
+  if(cddb_info) {
+    cd_info_free(cd_info);
+    priv->cd_info = cddb_info;
+    cd_info_debug( cddb_info );
+  }
+#endif
+
+  st->priv = priv;
+  st->start_pos = priv->start_sector*CD_FRAMESIZE_RAW;
+  st->end_pos = priv->end_sector*CD_FRAMESIZE_RAW;
+  st->type = STREAMTYPE_CDDA;
+  st->sector_size = CD_FRAMESIZE_RAW;
+
+  st->fill_buffer = fill_buffer;
+  st->seek = seek;
+  st->close = close_cdda;
+
+  *file_format = DEMUXER_TYPE_RAWAUDIO;
+
+  m_struct_free(&stream_opts,opts);
+
+  return STREAM_OK;
+}
+
+#ifndef HAVE_LIBCDIO
+static void cdparanoia_callback(long inpos, int function) {
+#else
+static void cdparanoia_callback(long int inpos, paranoia_cb_mode_t function) {
+#endif
+}
+
+static int fill_buffer(stream_t* s, char* buffer, int max_len) {
+  cdda_priv* p = (cdda_priv*)s->priv;
+  cd_track_t *cd_track;
+  int16_t * buf;
+  int i;
+  
+  buf = paranoia_read(p->cdp,cdparanoia_callback);
+
+#ifdef WORDS_BIGENDIAN 
+  for(i=0;i<CD_FRAMESIZE_RAW/2;i++)
+          buf[i]=le2me_16(buf[i]);
+#endif
+
+  p->sector++;
+  s->pos = p->sector*CD_FRAMESIZE_RAW;
+  memcpy(buffer,buf,CD_FRAMESIZE_RAW);
+
+  if((p->sector < p->start_sector) || (p->sector >= p->end_sector)) {
+    s->eof = 1;
+    return 0;
+  }
+
+  for(i=0;i<p->cd->tracks;i++){
+	  if(p->cd->disc_toc[i].dwStartSector==p->sector-1) {
+		  cd_track = cd_info_get_track(p->cd_info, i+1);
+//printf("Track %d, sector=%d\n", i, p->sector-1);
+		  if( cd_track!=NULL ) {
+			mp_msg(MSGT_SEEK, MSGL_INFO, "\n%s\n", cd_track->name); 
+			mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CDDA_TRACK=%d\n", cd_track->track_nb);
+		  }
+		  break;
+	  }
+  }
+
+  
+  return CD_FRAMESIZE_RAW;
+}
+
+static int seek(stream_t* s,off_t newpos) {
+  cdda_priv* p = (cdda_priv*)s->priv;
+  cd_track_t *cd_track;
+  int sec;
+  int current_track=0, seeked_track=0;
+  int i;
+  
+  s->pos = newpos;
+  if(s->pos < 0) {
+    s->eof = 1;
+    return 0;
+  }
+
+  sec = s->pos/CD_FRAMESIZE_RAW;
+//printf("pos: %d, sec: %d ## %d\n", (int)s->pos, (int)sec, CD_FRAMESIZE_RAW);
+//printf("sector: %d  new: %d\n", p->sector, sec );
+ 
+  for(i=0;i<p->cd->tracks;i++){
+//        printf("trk #%d: %d .. %d\n",i,p->cd->disc_toc[i].dwStartSector,p->cd->disc_toc[i+1].dwStartSector);
+	if( p->sector>=p->cd->disc_toc[i].dwStartSector && p->sector<p->cd->disc_toc[i+1].dwStartSector ) {
+		current_track = i;
+	}
+	if( sec>=p->cd->disc_toc[i].dwStartSector && sec<p->cd->disc_toc[i+1].dwStartSector ) {
+		seeked_track = i;
+	}
+  }
+//printf("current: %d, seeked: %d\n", current_track, seeked_track);
+	if( current_track!=seeked_track ) {
+//printf("Track %d, sector=%d\n", seeked_track, sec);
+		  cd_track = cd_info_get_track(p->cd_info, seeked_track+1);
+		  if( cd_track!=NULL ) {
+			  mp_msg(MSGT_SEEK, MSGL_INFO, "\n%s\n", cd_track->name);
+			  mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CDDA_TRACK=%d\n", cd_track->track_nb);
+		  }
+
+	}
+#if 0
+  if(sec < p->start_sector)
+    sec = p->start_sector;
+  else if(sec > p->end_sector)
+    sec = p->end_sector;
+#endif
+
+  p->sector = sec;
+//  s->pos = sec*CD_FRAMESIZE_RAW;
+
+//printf("seek: %d, sec: %d\n", (int)s->pos, sec);
+  paranoia_seek(p->cdp,sec,SEEK_SET);
+  return 1;
+}
+
+static void close_cdda(stream_t* s) {
+  cdda_priv* p = (cdda_priv*)s->priv;
+  paranoia_free(p->cdp);
+  cdda_close(p->cd);
+  cd_info_free(p->cd_info);
+  free(p);
+}
+
+stream_info_t stream_info_cdda = {
+  "CDDA",
+  "cdda",
+  "Albeu",
+  "",
+  open_cdda,
+  { "cdda", "cddb", NULL },
+  &stream_opts,
+  1 // Urls are an option string
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stream/stream_cddb.c	Mon Jul 31 17:48:50 2006 +0000
@@ -0,0 +1,878 @@
+/*
+ * CDDB HTTP protocol 
+ * by Bertrand Baudet <bertrand_baudet@yahoo.com>
+ * (C) 2002, MPlayer team.
+ *
+ * Implementation follow the freedb.howto1.06.txt specification
+ * from http://freedb.freedb.org
+ * 
+ * discid computation by Jeremy D. Zawodny
+ *	 Copyright (c) 1998-2000 Jeremy D. Zawodny <Jeremy@Zawodny.com>
+ *	 Code release under GPL
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#ifdef WIN32
+#ifdef __MINGW32__
+#define mkdir(a,b) mkdir(a)
+#endif
+#include <windows.h>
+#ifdef HAVE_WINSOCK2
+#include <winsock2.h>
+#endif
+#else
+#include <netdb.h>
+#include <sys/ioctl.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#if defined(__linux__)
+	#include <linux/cdrom.h>
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+	#include <sys/cdio.h>
+#elif defined(WIN32)
+        #include <ddk/ntddcdrm.h>
+#elif (__bsdi__)
+        #include <dvd.h>
+#endif
+
+#include "cdd.h"
+#include "version.h"
+#include "stream.h"
+#include "network.h"
+
+#define DEFAULT_FREEDB_SERVER	"freedb.freedb.org"
+#define DEFAULT_CACHE_DIR	"/.cddb/"
+
+stream_t* open_cdda(char *dev, char *track);
+
+static cd_toc_t cdtoc[100];
+static int cdtoc_last_track;
+
+#if defined(__linux__) || defined(__bsdi__)
+int 
+read_toc(const char *dev) {
+	int drive;
+	struct cdrom_tochdr tochdr;
+	struct cdrom_tocentry tocentry;
+	int i;
+
+	drive = open(dev, O_RDONLY | O_NONBLOCK);
+	if( drive<0 ) {
+		return drive;
+	}
+	
+	ioctl(drive, CDROMREADTOCHDR, &tochdr);
+	for (i = tochdr.cdth_trk0; i <= tochdr.cdth_trk1; i++) {
+		tocentry.cdte_track = i;
+		tocentry.cdte_format = CDROM_MSF;
+		ioctl(drive, CDROMREADTOCENTRY, &tocentry);
+		cdtoc[i-1].min = tocentry.cdte_addr.msf.minute;
+		cdtoc[i-1].sec = tocentry.cdte_addr.msf.second;
+		cdtoc[i-1].frame = tocentry.cdte_addr.msf.frame;
+		cdtoc[i-1].frame += cdtoc[i-1].min*60*75;
+		cdtoc[i-1].frame += cdtoc[i-1].sec*75;
+	}
+	tocentry.cdte_track = 0xAA;
+	tocentry.cdte_format = CDROM_MSF;
+	ioctl(drive, CDROMREADTOCENTRY, &tocentry);
+	cdtoc[tochdr.cdth_trk1].min = tocentry.cdte_addr.msf.minute;
+	cdtoc[tochdr.cdth_trk1].sec = tocentry.cdte_addr.msf.second;
+	cdtoc[tochdr.cdth_trk1].frame = tocentry.cdte_addr.msf.frame;
+	cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].min*60*75;
+	cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].sec*75;
+	close(drive);
+	return tochdr.cdth_trk1;
+}
+
+#elif defined(WIN32)
+int
+read_toc(const char *dev) {
+        HANDLE drive;
+        DWORD r;
+        CDROM_TOC toc;
+        char device[10];
+        int i;
+
+        sprintf(device, "\\\\.\\%s", dev);
+        drive = CreateFile(device, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
+
+        if(!DeviceIoControl(drive, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(CDROM_TOC), &r, 0)) {
+                mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToReadTOC);
+                return 0;
+        }
+
+        for (i = toc.FirstTrack; i <= toc.LastTrack; i++) {
+                toc.FirstTrack = i;
+		cdtoc[i-1].min = toc.TrackData[i - 1].Address[1];
+		cdtoc[i-1].sec = toc.TrackData[i - 1].Address[2];
+		cdtoc[i-1].frame = toc.TrackData[i - 1].Address[3];
+		cdtoc[i-1].frame += cdtoc[i-1].min*60*75;
+		cdtoc[i-1].frame += cdtoc[i-1].sec*75;
+        }
+        toc.FirstTrack = 0xAA;
+        cdtoc[toc.LastTrack].min = toc.TrackData[toc.LastTrack].Address[1];
+        cdtoc[toc.LastTrack].sec = toc.TrackData[toc.LastTrack].Address[2];
+        cdtoc[toc.LastTrack].frame = toc.TrackData[toc.LastTrack].Address[3];
+        cdtoc[toc.LastTrack].frame += cdtoc[toc.LastTrack].min*60*75;
+        cdtoc[toc.LastTrack].frame += cdtoc[toc.LastTrack].sec*75;
+        CloseHandle(drive);
+        return toc.LastTrack;
+}
+
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+int 
+read_toc(const char *dev) {
+	int drive;
+	struct ioc_toc_header tochdr;
+	struct ioc_read_toc_single_entry tocentry;
+	int i;
+
+	drive = open(dev, O_RDONLY | O_NONBLOCK);
+	if( drive<0 ) {
+		return drive;
+	}
+
+	ioctl(drive, CDIOREADTOCHEADER, &tochdr);
+	for (i = tochdr.starting_track; i <= tochdr.ending_track; i++) {
+		tocentry.track = i;
+		tocentry.address_format = CD_MSF_FORMAT;
+		ioctl(drive, CDIOREADTOCENTRY, &tocentry);
+		cdtoc[i-1].min = tocentry.entry.addr.msf.minute;
+		cdtoc[i-1].sec = tocentry.entry.addr.msf.second;
+		cdtoc[i-1].frame = tocentry.entry.addr.msf.frame;
+		cdtoc[i-1].frame += cdtoc[i-1].min*60*75;
+		cdtoc[i-1].frame += cdtoc[i-1].sec*75;
+	}
+	tocentry.track = 0xAA;
+	tocentry.address_format = CD_MSF_FORMAT;
+	ioctl(drive, CDIOREADTOCENTRY, &tocentry);
+	cdtoc[tochdr.ending_track].min = tocentry.entry.addr.msf.minute;
+	cdtoc[tochdr.ending_track].sec = tocentry.entry.addr.msf.second;
+	cdtoc[tochdr.ending_track].frame = tocentry.entry.addr.msf.frame;
+	cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].min*60*75;
+	cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].sec*75;
+	close(drive);
+	return tochdr.ending_track;
+}
+
+#elif defined(__NetBSD__) || defined(__OpenBSD__)
+int
+read_toc(const char *dev) {
+	int drive;
+	struct ioc_toc_header tochdr;
+	struct ioc_read_toc_entry tocentry;
+	int i;
+	struct cd_toc_entry toc_buffer;
+
+	drive = open(dev, O_RDONLY | O_NONBLOCK);
+	if( drive<0 ) {
+		return drive;
+	}
+
+	ioctl(drive, CDIOREADTOCHEADER, &tochdr);
+	for (i = tochdr.starting_track; i <= tochdr.ending_track; i++) {
+		tocentry.starting_track = i;
+		tocentry.address_format = CD_MSF_FORMAT;
+		tocentry.data = &toc_buffer;
+		tocentry.data_len = sizeof(toc_buffer);
+		ioctl(drive, CDIOREADTOCENTRYS, &tocentry);
+		cdtoc[i-1].min = toc_buffer.addr.msf.minute;
+		cdtoc[i-1].sec = toc_buffer.addr.msf.second;
+		cdtoc[i-1].frame = toc_buffer.addr.msf.frame;
+		cdtoc[i-1].frame += cdtoc[i-1].min*60*75;
+		cdtoc[i-1].frame += cdtoc[i-1].sec*75;
+	}
+	tocentry.starting_track = 0xAA;
+	tocentry.address_format = CD_MSF_FORMAT;
+	ioctl(drive, CDIOREADTOCENTRYS, &tocentry);
+	cdtoc[tochdr.ending_track].min = toc_buffer.addr.msf.minute;
+	cdtoc[tochdr.ending_track].sec = toc_buffer.addr.msf.second;
+	cdtoc[tochdr.ending_track].frame = toc_buffer.addr.msf.frame;
+	cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].min*60*75;
+	cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].sec*75;
+	close(drive);
+	return tochdr.ending_track;
+}
+#endif
+
+/** 
+\brief Reads TOC from CD in the given device and prints the number of tracks
+       and the length of each track in minute:second:frame format.
+\param *dev the device to analyse
+\return if the command line -identify is given, returns the last track of
+        the TOC or -1 if the TOC can't be read,
+        otherwise just returns 0 and let cddb_resolve the TOC
+*/
+int cdd_identify(const char *dev)
+{
+	cdtoc_last_track = 0;
+	if (mp_msg_test(MSGT_IDENTIFY, MSGL_INFO))
+	{
+		int i, min, sec, frame;
+		cdtoc_last_track = read_toc(dev);
+		if (cdtoc_last_track < 0) {
+			mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToOpenDevice, dev);
+			return -1;
+		}
+		mp_msg(MSGT_GLOBAL, MSGL_INFO, "ID_CDDA_TRACKS=%d\n", cdtoc_last_track);
+		for (i = 1; i <= cdtoc_last_track; i++)
+		{
+			frame = cdtoc[i].frame - cdtoc[i-1].frame;
+			sec = frame / 75;
+			frame -= sec * 75;
+			min = sec / 60;
+			sec -= min * 60;
+			mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CDDA_TRACK_%d_MSF=%02d:%02d:%02d\n", i, min, sec, frame);
+		}
+	}
+	return cdtoc_last_track;
+}
+
+unsigned int 
+cddb_sum(int n) {
+	unsigned int ret;
+
+	ret = 0;
+	while (n > 0) {
+		ret += (n % 10);
+		n /= 10;
+	}
+	return ret;
+}
+
+unsigned long 
+cddb_discid(int tot_trks) {
+	unsigned int i, t = 0, n = 0;
+
+	i = 0;
+	while (i < (unsigned int)tot_trks) {
+		n = n + cddb_sum((cdtoc[i].min * 60) + cdtoc[i].sec);
+		i++;
+	}
+	t = ((cdtoc[tot_trks].min * 60) + cdtoc[tot_trks].sec) -
+		((cdtoc[0].min * 60) + cdtoc[0].sec);
+	return ((n % 0xff) << 24 | t << 8 | tot_trks);
+}
+
+
+
+int
+cddb_http_request(char *command, int (*reply_parser)(HTTP_header_t*,cddb_data_t*), cddb_data_t *cddb_data) {
+	char request[4096];
+	int fd, ret = 0;
+	URL_t *url;
+	HTTP_header_t *http_hdr;
+	
+	if( reply_parser==NULL || command==NULL || cddb_data==NULL ) return -1;
+	
+	sprintf( request, "http://%s/~cddb/cddb.cgi?cmd=%s%s&proto=%d", cddb_data->freedb_server, command, cddb_data->cddb_hello, cddb_data->freedb_proto_level );
+	mp_msg(MSGT_OPEN, MSGL_INFO,"Request[%s]\n", request );
+
+	url = url_new(request);
+	if( url==NULL ) {
+		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_NotAValidURL);
+		return -1;
+	}
+	
+	fd = http_send_request(url,0);
+	if( fd<0 ) {
+		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToSendHTTPRequest);
+		return -1;
+	}
+
+	http_hdr = http_read_response( fd );
+	if( http_hdr==NULL ) {
+		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToReadHTTPResponse);
+		return -1;
+	}
+
+	http_debug_hdr(http_hdr);
+	mp_msg(MSGT_OPEN, MSGL_INFO,"body=[%s]\n", http_hdr->body );
+
+	switch(http_hdr->status_code) {
+		case 200:
+			ret = reply_parser(http_hdr, cddb_data);
+			break;
+		case 400:
+			mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_HTTPErrorNOTFOUND);
+			break;
+		default:
+			mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_HTTPErrorUnknown);
+	}
+
+	http_free( http_hdr );
+	url_free( url );
+	
+	return ret;
+}
+
+int
+cddb_read_cache(cddb_data_t *cddb_data) {
+	char file_name[100];
+	struct stat stats;
+	int file_fd, ret;
+	size_t file_size;
+
+	if( cddb_data==NULL || cddb_data->cache_dir==NULL ) return -1;
+	
+	sprintf( file_name, "%s%08lx", cddb_data->cache_dir, cddb_data->disc_id);
+	
+	file_fd = open(file_name, O_RDONLY
+#ifdef WIN32
+	| O_BINARY
+#endif
+	);
+	if( file_fd<0 ) {
+		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_NoCacheFound);
+		return -1;
+	}
+
+	ret = fstat( file_fd, &stats );
+	if( ret<0 ) {
+		perror("fstat");
+		file_size = 4096;
+	} else {
+		file_size = stats.st_size;
+	}
+	
+	cddb_data->xmcd_file = malloc(file_size);
+	if( cddb_data->xmcd_file==NULL ) {
+		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MemAllocFailed);
+		close(file_fd);
+		return -1;
+	}
+	cddb_data->xmcd_file_size = read(file_fd, cddb_data->xmcd_file, file_size);
+	if( cddb_data->xmcd_file_size!=file_size ) {
+		mp_msg(MSGT_DEMUX, MSGL_WARN, MSGTR_MPDEMUX_CDDB_NotAllXMCDFileHasBeenRead);
+		close(file_fd);
+		return -1;
+	}
+	
+	close(file_fd);
+	
+	return 0;
+}
+
+int
+cddb_write_cache(cddb_data_t *cddb_data) {
+	// We have the file, save it for cache.
+	struct stat file_stat;
+	char file_name[100];
+	int file_fd, ret;
+	int wrote=0;
+
+	if( cddb_data==NULL || cddb_data->cache_dir==NULL ) return -1;
+
+	// Check if the CDDB cache dir exist
+	ret = stat( cddb_data->cache_dir, &file_stat );
+	if( ret<0 ) {
+		// Directory not present, create it.
+		ret = mkdir( cddb_data->cache_dir, 0755 );
+#ifdef __MINGW32__
+		if( ret<0 && errno != EEXIST ) {
+#else
+		if( ret<0 ) {
+#endif
+			perror("mkdir");
+			mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToCreateDirectory, cddb_data->cache_dir);
+			return -1;
+		}
+	}
+	
+	sprintf( file_name, "%s%08lx", cddb_data->cache_dir, cddb_data->disc_id );
+	
+	file_fd = creat(file_name, S_IREAD|S_IWRITE);
+	if( file_fd<0 ) {
+		perror("create");
+		return -1;
+	}
+	
+	wrote = write(file_fd, cddb_data->xmcd_file, cddb_data->xmcd_file_size);
+	if( wrote<0 ) {
+		perror("write");
+		close(file_fd);
+		return -1;
+	}
+	if( (unsigned int)wrote!=cddb_data->xmcd_file_size ) {
+		mp_msg(MSGT_DEMUX, MSGL_WARN, MSGTR_MPDEMUX_CDDB_NotAllXMCDFileHasBeenWritten);
+		close(file_fd);
+		return -1;
+	}
+	
+	close(file_fd);
+
+	return 0;
+}
+
+int
+cddb_read_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
+	unsigned long disc_id;
+	char category[100];
+	char *ptr=NULL, *ptr2=NULL;
+	int ret, status;
+
+	if( http_hdr==NULL || cddb_data==NULL ) return -1;
+	
+	ret = sscanf( http_hdr->body, "%d ", &status);
+	if( ret!=1 ) {
+		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);
+		return -1;
+	}
+
+	switch(status) {
+		case 210:
+			ret = sscanf( http_hdr->body, "%d %s %08lx", &status, category, &disc_id);
+			if( ret!=3 ) {
+				mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);
+				return -1;
+			}
+			// Check if it's a xmcd database file
+			ptr = strstr(http_hdr->body, "# xmcd");
+			if( ptr==NULL ) {
+				mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_InvalidXMCDDatabaseReturned);
+				return -1;
+			}
+			// Ok found the beginning of the file
+			// look for the end
+			ptr2 = strstr(ptr, "\r\n.\r\n");
+			if( ptr2==NULL ) {
+				ptr2 = strstr(ptr, "\n.\n");
+				if( ptr2==NULL ) {
+					mp_msg(MSGT_DEMUX, MSGL_FIXME, "Unable to find '.'\n");
+					ptr2=ptr+strlen(ptr); //return -1;
+				}
+			}
+			// Ok found the end
+			// do a sanity check
+			if( http_hdr->body_size<(unsigned int)(ptr2-ptr) ) {
+				mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_UnexpectedFIXME);
+				return -1;
+			}
+			cddb_data->xmcd_file = ptr;
+			cddb_data->xmcd_file_size = ptr2-ptr+2;
+			cddb_data->xmcd_file[cddb_data->xmcd_file_size] = '\0';
+			// Avoid the http_free function to free the xmcd file...save a mempcy...
+			http_hdr->body = NULL;
+			http_hdr->body_size = 0;
+			return cddb_write_cache(cddb_data);
+		default:
+			mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_UnhandledCode);
+	}
+	return 0;
+}
+
+int
+cddb_request_titles(cddb_data_t *cddb_data) {
+	char command[1024];
+	sprintf( command, "cddb+read+%s+%08lx", cddb_data->category, cddb_data->disc_id);
+	return cddb_http_request(command, cddb_read_parse, cddb_data); 
+}
+
+int
+cddb_parse_matches_list(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
+	char album_title[100];
+	char *ptr = NULL;
+	int ret;
+	
+	ptr = strstr(http_hdr->body, "\n");
+	if( ptr==NULL ) {
+		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_UnableToFindEOL);
+		return -1;
+	}
+	ptr++;
+	// We have a list of exact/inexact matches, so which one do we use?
+	// So let's take the first one.
+	ret = sscanf(ptr, "%s %08lx %s", cddb_data->category, &(cddb_data->disc_id), album_title);
+	if( ret!=3 ) {
+		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);
+		return -1;
+	}
+	ptr = strstr(http_hdr->body, album_title);
+	if( ptr!=NULL ) {
+		char *ptr2;
+		int len;
+		ptr2 = strstr(ptr, "\n");
+		if( ptr2==NULL ) {
+			len = (http_hdr->body_size)-(ptr-(http_hdr->body));
+		} else {
+			len = ptr2-ptr+1;
+		}
+		strncpy(album_title, ptr, len);
+		album_title[len-2]='\0';
+	}
+	mp_msg(MSGT_DEMUX, MSGL_STATUS, MSGTR_MPDEMUX_CDDB_ParseOKFoundAlbumTitle, album_title);
+	return 0;
+}
+
+int
+cddb_query_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
+	char album_title[100];
+	char *ptr = NULL;
+	int ret, status;
+	
+	ret = sscanf( http_hdr->body, "%d ", &status);
+	if( ret!=1 ) {
+		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);
+		return -1;
+	}
+
+	switch(status) {
+		case 200:
+			// Found exact match
+			ret = sscanf(http_hdr->body, "%d %s %08lx %s", &status, cddb_data->category, &(cddb_data->disc_id), album_title);
+			if( ret!=4 ) {
+				mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);
+				return -1;
+			}
+			ptr = strstr(http_hdr->body, album_title);
+			if( ptr!=NULL ) {
+				char *ptr2;
+				int len;
+				ptr2 = strstr(ptr, "\n");
+				if( ptr2==NULL ) {
+					len = (http_hdr->body_size)-(ptr-(http_hdr->body));
+				} else {
+					len = ptr2-ptr+1;
+				}
+				strncpy(album_title, ptr, len);
+				album_title[len-2]='\0';
+			}
+			mp_msg(MSGT_DEMUX, MSGL_STATUS, MSGTR_MPDEMUX_CDDB_ParseOKFoundAlbumTitle, album_title);
+			return cddb_request_titles(cddb_data);
+		case 202:
+			// No match found
+			mp_msg(MSGT_DEMUX, MSGL_WARN, MSGTR_MPDEMUX_CDDB_AlbumNotFound);
+			break;
+		case 210:
+			// Found exact matches, list follows
+			cddb_parse_matches_list(http_hdr, cddb_data);
+			return cddb_request_titles(cddb_data);
+/*
+body=[210 Found exact matches, list follows (until terminating `.')
+misc c711930d Santana / Supernatural
+rock c711930d Santana / Supernatural
+blues c711930d Santana / Supernatural
+.]
+*/	
+		case 211:
+			// Found inexact matches, list follows
+			cddb_parse_matches_list(http_hdr, cddb_data);
+			return cddb_request_titles(cddb_data);
+		case 500:
+			mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_ServerReturnsCommandSyntaxErr);
+			break;
+		default:
+			mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_UnhandledCode);	
+	}
+	return -1;
+}
+
+int
+cddb_proto_level_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
+	int max;
+	int ret, status;
+	char *ptr;
+	
+	ret = sscanf( http_hdr->body, "%d ", &status);
+	if( ret!=1 ) {
+		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);	
+		return -1;
+	}
+
+	switch(status) {
+		case 210:
+			ptr = strstr(http_hdr->body, "max proto:");
+			if( ptr==NULL ) {
+				mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);
+				return -1;
+			}
+			ret = sscanf(ptr, "max proto: %d", &max);
+			if( ret!=1 ) {
+				mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);
+				return -1;
+			}
+			cddb_data->freedb_proto_level = max;
+			return 0;
+		default:
+			mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_UnhandledCode);	
+	}
+	return -1;
+}
+
+int
+cddb_get_proto_level(cddb_data_t *cddb_data) {
+	return cddb_http_request("stat", cddb_proto_level_parse, cddb_data);
+}
+
+int
+cddb_freedb_sites_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
+	int ret, status;
+
+	ret = sscanf( http_hdr->body, "%d ", &status);
+	if( ret!=1 ) {
+		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError);
+		return -1;
+	}
+
+	switch(status) {
+		case 210:
+			// TODO: Parse the sites
+			ret = cddb_data->anonymous;	// For gcc complaining about unused parameter.
+			return 0;
+		case 401:
+			mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_NoSitesInfoAvailable);
+			break;
+		default:
+			mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_UnhandledCode);
+	}
+	return -1;
+}
+
+int
+cddb_get_freedb_sites(cddb_data_t *cddb_data) {
+	return cddb_http_request("sites", cddb_freedb_sites_parse, cddb_data);
+}
+
+void
+cddb_create_hello(cddb_data_t *cddb_data) {
+	char host_name[51];
+	char *user_name;
+	
+	if( cddb_data->anonymous ) {	// Default is anonymous
+		/* Note from Eduardo Pérez Ureta <eperez@it.uc3m.es> : 
+		 * We don't send current user/host name in hello to prevent spam.
+		 * Software that sends this is considered spyware
+		 * that most people don't like.
+		 */
+		user_name = "anonymous";
+		strcpy(host_name, "localhost");
+	} else {
+		if( gethostname(host_name, 50)<0 ) {
+			strcpy(host_name, "localhost");
+		}
+		user_name = getenv("LOGNAME");
+	}
+	sprintf( cddb_data->cddb_hello, "&hello=%s+%s+%s+%s", user_name, host_name, "MPlayer", VERSION );
+}
+
+int 
+cddb_retrieve(cddb_data_t *cddb_data) {
+	char offsets[1024], command[1024];
+	char *ptr;
+	unsigned int i, time_len;
+	int ret;
+
+	ptr = offsets;
+	for( i=0; i<cddb_data->tracks ; i++ ) {
+		ptr += sprintf(ptr, "%d+", cdtoc[i].frame );
+		if (ptr-offsets > sizeof offsets - 40) break;
+	}
+	ptr[0]=0;
+	time_len = (cdtoc[cddb_data->tracks].frame)/75;
+	
+	cddb_data->freedb_server = DEFAULT_FREEDB_SERVER;
+	cddb_data->freedb_proto_level = 1;
+	cddb_data->xmcd_file = NULL;
+
+	cddb_create_hello(cddb_data);
+	if( cddb_get_proto_level(cddb_data)<0 ) {
+		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToGetProtocolLevel);
+		return -1;
+	}
+
+	//cddb_get_freedb_sites(&cddb_data);
+
+	sprintf(command, "cddb+query+%08lx+%d+%s%d", cddb_data->disc_id, cddb_data->tracks, offsets, time_len );
+	ret = cddb_http_request(command, cddb_query_parse, cddb_data);
+	if( ret<0 ) return -1;
+
+	if( cddb_data->cache_dir!=NULL ) {
+		free(cddb_data->cache_dir);
+	}
+	return 0;
+}
+
+int
+cddb_resolve(const char *dev, char **xmcd_file) {
+	char cddb_cache_dir[] = DEFAULT_CACHE_DIR;
+	char *home_dir = NULL;
+	cddb_data_t cddb_data;
+
+	if (cdtoc_last_track <= 0)
+	{
+	    cdtoc_last_track = read_toc(dev);
+	    if (cdtoc_last_track < 0) {
+		mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToOpenDevice, dev);
+		return -1;
+	    }
+	}
+	cddb_data.tracks = cdtoc_last_track;
+	cddb_data.disc_id = cddb_discid(cddb_data.tracks);
+	cddb_data.anonymous = 1;	// Don't send user info by default
+
+	// Check if there is a CD in the drive
+	// FIXME: That's not really a good way to check
+	if( cddb_data.disc_id==0 ) {
+		mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_NoCDInDrive);
+		return -1;
+	}
+	
+	home_dir = getenv("HOME");
+#ifdef __MINGW32__
+	if( home_dir==NULL ) home_dir = getenv("USERPROFILE");
+	if( home_dir==NULL ) home_dir = getenv("HOMEPATH");
+	// Last resort, store the cddb cache in the mplayer directory
+	if( home_dir==NULL ) home_dir = (char *)get_path("");
+#endif
+	if( home_dir==NULL ) {
+		cddb_data.cache_dir = NULL;
+	} else {
+		cddb_data.cache_dir = malloc(strlen(home_dir)+strlen(cddb_cache_dir)+1);
+		if( cddb_data.cache_dir==NULL ) {
+			mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MemAllocFailed);
+			return -1;
+		}
+		sprintf(cddb_data.cache_dir, "%s%s", home_dir, cddb_cache_dir );
+	}
+
+	// Check for a cached file
+	if( cddb_read_cache(&cddb_data)<0 ) {
+		// No Cache found
+		if( cddb_retrieve(&cddb_data)<0 ) {
+			return -1;
+		}
+	}
+
+	if( cddb_data.xmcd_file!=NULL ) {
+//		printf("%s\n", cddb_data.xmcd_file );
+		*xmcd_file = cddb_data.xmcd_file;
+		return 0;
+	}
+	
+	return -1;
+}
+
+/*******************************************************************************************************************
+ *
+ * xmcd parser
+ *
+ *******************************************************************************************************************/
+char*
+xmcd_parse_dtitle(cd_info_t *cd_info, char *line) {
+	char *ptr, *album;
+	ptr = strstr(line, "DTITLE=");
+	if( ptr!=NULL ) {
+		ptr += 7;
+		album = strstr(ptr, "/");
+		if( album==NULL ) return NULL;
+		cd_info->album = malloc(strlen(album+2)+1);
+		if( cd_info->album==NULL ) {
+			return NULL;
+		}
+		strcpy( cd_info->album, album+2 );
+		album--;
+		album[0] = '\0';
+		cd_info->artist = malloc(strlen(ptr)+1);
+		if( cd_info->artist==NULL ) {
+			return NULL;
+		}
+		strcpy( cd_info->artist, ptr );
+	}
+	return ptr;
+}
+
+char*
+xmcd_parse_dgenre(cd_info_t *cd_info, char *line) {
+	char *ptr;
+	ptr = strstr(line, "DGENRE=");
+	if( ptr!=NULL ) {
+		ptr += 7;
+		cd_info->genre = malloc(strlen(ptr)+1);
+		if( cd_info->genre==NULL ) {
+			return NULL;
+		}
+		strcpy( cd_info->genre, ptr );
+	}
+	return ptr;
+}
+
+char*
+xmcd_parse_ttitle(cd_info_t *cd_info, char *line) {
+	unsigned int track_nb;
+	unsigned long sec, off;
+	char *ptr;
+	ptr = strstr(line, "TTITLE");
+	if( ptr!=NULL ) {
+		ptr += 6;
+		// Here we point to the track number
+		track_nb = atoi(ptr);
+		ptr = strstr(ptr, "=");
+		if( ptr==NULL ) return NULL;
+		ptr++;
+		
+		sec = cdtoc[track_nb].frame;
+		off = cdtoc[track_nb+1].frame-sec+1;
+
+		cd_info_add_track( cd_info, ptr, track_nb+1, (unsigned int)(off/(60*75)), (unsigned int)((off/75)%60), (unsigned int)(off%75), sec, off );
+	}
+	return ptr;
+}
+
+cd_info_t*
+cddb_parse_xmcd(char *xmcd_file) {
+	cd_info_t *cd_info = NULL;
+	int length, pos = 0;
+	char *ptr, *ptr2;
+	unsigned int audiolen;
+	if( xmcd_file==NULL ) return NULL;
+	
+	cd_info = cd_info_new();
+	if( cd_info==NULL ) {
+		return NULL;
+	}
+	
+	length = strlen(xmcd_file);
+	ptr = xmcd_file;
+	while( ptr!=NULL && pos<length ) {
+		// Read a line
+		ptr2 = ptr;
+		while( ptr2[0]!='\0' && ptr2[0]!='\r' && ptr2[0]!='\n' ) ptr2++;
+		if( ptr2[0]=='\0' ) {
+			break;
+		}
+		ptr2[0] = '\0';
+		// Ignore comments
+		if( ptr[0]!='#' ) {
+			// Search for the album title
+			if( xmcd_parse_dtitle(cd_info, ptr) );
+			// Search for the genre
+			else if( xmcd_parse_dgenre(cd_info, ptr) );
+			// Search for a track title
+			else if( xmcd_parse_ttitle(cd_info, ptr) ) audiolen++;	// <-- audiolen++ to shut up gcc warning
+		}
+		if( ptr2[1]=='\n' ) ptr2++;
+		pos = (ptr2+1)-ptr;
+		ptr = ptr2+1;
+	}
+
+	audiolen = cdtoc[cd_info->nb_tracks].frame-cdtoc[0].frame;	
+	cd_info->min  = (unsigned int)(audiolen/(60*75));
+	cd_info->sec  = (unsigned int)((audiolen/75)%60);
+	cd_info->msec = (unsigned int)(audiolen%75);
+	
+	return cd_info;
+}