# HG changeset patch # User ben # Date 1154368130 0 # Node ID e53b30cd047f6fb24809a31aef41227e18eecb19 # Parent 64d82a45a05d841eefb9a51cb5a00a3a1d9e5adc renamed cddX stream interface to stream_cddX for consistency diff -r 64d82a45a05d -r e53b30cd047f stream/Makefile --- 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 diff -r 64d82a45a05d -r e53b30cd047f stream/cdda.c --- 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 -#include -#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;itracks;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;isector++; - 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;icd->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;icd->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->sectorcd->disc_toc[i+1].dwStartSector ) { - current_track = i; - } - if( sec>=p->cd->disc_toc[i].dwStartSector && seccd->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 -}; diff -r 64d82a45a05d -r e53b30cd047f stream/cddb.c --- 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 - * (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 - * Code release under GPL - * - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#ifdef WIN32 -#ifdef __MINGW32__ -#define mkdir(a,b) mkdir(a) -#endif -#include -#ifdef HAVE_WINSOCK2 -#include -#endif -#else -#include -#include -#endif -#include -#include - -#include "mp_msg.h" -#include "help_mp.h" - -#if defined(__linux__) - #include -#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) - #include -#elif defined(WIN32) - #include -#elif (__bsdi__) - #include -#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 : - * 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; itracks ; 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 && posnb_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; -} diff -r 64d82a45a05d -r e53b30cd047f stream/stream_cdda.c --- /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 +#include +#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;itracks;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;isector++; + 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;icd->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;icd->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->sectorcd->disc_toc[i+1].dwStartSector ) { + current_track = i; + } + if( sec>=p->cd->disc_toc[i].dwStartSector && seccd->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 +}; diff -r 64d82a45a05d -r e53b30cd047f stream/stream_cddb.c --- /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 + * (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 + * Code release under GPL + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#ifdef __MINGW32__ +#define mkdir(a,b) mkdir(a) +#endif +#include +#ifdef HAVE_WINSOCK2 +#include +#endif +#else +#include +#include +#endif +#include +#include + +#include "mp_msg.h" +#include "help_mp.h" + +#if defined(__linux__) + #include +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) + #include +#elif defined(WIN32) + #include +#elif (__bsdi__) + #include +#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 : + * 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; itracks ; 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 && posnb_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; +}