summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Caujolle-Bert <f1rmb@users.sourceforge.net>2001-12-06 23:53:20 +0000
committerDaniel Caujolle-Bert <f1rmb@users.sourceforge.net>2001-12-06 23:53:20 +0000
commit1243c961ef9281e67814ccbb6d1075caf97d1a49 (patch)
treee4b2caa388f404bab65f4ffcb4d0b8fdd2737bc3 /src
parent85fa502b8d69f72eecee95fe3692344ae4035989 (diff)
downloadxine-lib-1243c961ef9281e67814ccbb6d1075caf97d1a49.tar.gz
xine-lib-1243c961ef9281e67814ccbb6d1075caf97d1a49.tar.bz2
Add audio cd support.
CVS patchset: 1172 CVS date: 2001/12/06 23:53:20
Diffstat (limited to 'src')
-rw-r--r--src/demuxers/Makefile.am5
-rw-r--r--src/demuxers/demux_cda.c303
-rw-r--r--src/input/Makefile.am6
-rw-r--r--src/input/input_cda.c919
-rw-r--r--src/input/input_plugin.h25
5 files changed, 1244 insertions, 14 deletions
diff --git a/src/demuxers/Makefile.am b/src/demuxers/Makefile.am
index 1dd074214..e1d311d88 100644
--- a/src/demuxers/Makefile.am
+++ b/src/demuxers/Makefile.am
@@ -22,7 +22,7 @@ lib_LTLIBRARIES = $(ogg_module) $(qt_modules) xineplug_dmx_avi.la \
xineplug_dmx_mpeg_block.la xineplug_dmx_mpeg.la \
xineplug_dmx_mpeg_elem.la xineplug_dmx_mpeg_audio.la \
xineplug_dmx_mpeg_pes.la xineplug_dmx_mpeg_ts.la \
- xineplug_dmx_asf.la
+ xineplug_dmx_asf.la xineplug_dmx_cda.la
xineplug_dmx_ogg_la_SOURCES = demux_ogg.c
xineplug_dmx_ogg_la_LIBADD = @OGG_LIBS@
@@ -57,6 +57,9 @@ xineplug_dmx_qt_la_LIBADD = -lz
xineplug_dmx_asf_la_SOURCES = demux_asf.c
xineplug_dmx_asf_la_LDFLAGS = -avoid-version -module
+xineplug_dmx_cda_la_SOURCES = demux_cda.c
+xineplug_dmx_cda_la_LDFLAGS = -avoid-version -module
+
include_HEADERS = demux.h
##
diff --git a/src/demuxers/demux_cda.c b/src/demuxers/demux_cda.c
new file mode 100644
index 000000000..df4de96be
--- /dev/null
+++ b/src/demuxers/demux_cda.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2000-2001 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: demux_cda.c,v 1.1 2001/12/06 23:53:20 f1rmb Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "xine_internal.h"
+#include "xineutils.h"
+#include "compat.h"
+#include "demux.h"
+
+#define DEMUX_CDA_IFACE_VERSION 3
+
+typedef struct {
+
+ demux_plugin_t demux_plugin;
+
+ config_values_t *config;
+
+ fifo_buffer_t *video_fifo;
+ fifo_buffer_t *audio_fifo;
+
+ input_plugin_t *input;
+
+ pthread_t thread;
+
+ off_t start;
+
+ int status;
+ int send_end_buffers;
+ int blocksize;
+
+} demux_cda_t ;
+
+/*
+ *
+ */
+static int demux_cda_next (demux_cda_t *this) {
+ buf_element_t *buf;
+ int pos, len;
+
+ buf = this->input->read_block(this->input, this->audio_fifo, this->blocksize);
+
+ pos = this->input->get_current_pos(this->input);
+ len = this->input->get_length(this->input);
+
+ buf->PTS = 0;
+ buf->SCR = 0;
+ buf->input_pos = this->input->get_current_pos(this->input);
+ buf->input_time = buf->input_pos / this->blocksize;
+ buf->type = BUF_AUDIO_MPEG; /* Fake */
+
+ if(this->audio_fifo)
+ this->audio_fifo->put(this->audio_fifo, buf);
+
+ return ((pos < len));
+}
+
+/*
+ *
+ */
+static void *demux_cda_loop (void *this_gen) {
+ demux_cda_t *this = (demux_cda_t *) this_gen;
+ buf_element_t *buf;
+
+ this->send_end_buffers = 1;
+
+ this->input->seek(this->input, this->start, SEEK_SET);
+
+ do {
+
+ if (!demux_cda_next(this))
+ this->status = DEMUX_FINISHED;
+
+ } while (this->status == DEMUX_OK) ;
+
+ this->status = DEMUX_FINISHED;
+
+ if (this->send_end_buffers) {
+ buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
+ buf->type = BUF_CONTROL_END;
+ buf->decoder_info[0] = 0; /* stream finished */
+ this->video_fifo->put (this->video_fifo, buf);
+
+ if(this->audio_fifo) {
+ buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
+ buf->type = BUF_CONTROL_END;
+ buf->decoder_info[0] = 0; /* stream finished */
+ this->audio_fifo->put (this->audio_fifo, buf);
+ }
+ }
+
+ pthread_exit(NULL);
+}
+
+/*
+ *
+ */
+static void demux_cda_stop (demux_plugin_t *this_gen) {
+ demux_cda_t *this = (demux_cda_t *) this_gen;
+ buf_element_t *buf;
+ void *p;
+
+ if (this->status != DEMUX_OK) {
+ printf ("demux_cda: stop...ignored\n");
+ return;
+ }
+
+ /* Force stop */
+ this->input->stop(this->input);
+
+ this->send_end_buffers = 0;
+ this->status = DEMUX_FINISHED;
+
+ pthread_cancel(this->thread);
+ pthread_join(this->thread, &p);
+
+ this->video_fifo->clear(this->video_fifo);
+ if (this->audio_fifo)
+ this->audio_fifo->clear(this->audio_fifo);
+
+ buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
+ buf->type = BUF_CONTROL_END;
+ buf->decoder_info[0] = 1; /* forced */
+ this->video_fifo->put (this->video_fifo, buf);
+
+ if(this->audio_fifo) {
+ buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
+ buf->type = BUF_CONTROL_END;
+ buf->decoder_info[0] = 1; /* forced */
+ this->audio_fifo->put (this->audio_fifo, buf);
+ }
+
+}
+
+/*
+ *
+ */
+static int demux_cda_get_status (demux_plugin_t *this_gen) {
+ demux_cda_t *this = (demux_cda_t *) this_gen;
+
+ return this->status;
+}
+
+/*
+ *
+ */
+static void demux_cda_start (demux_plugin_t *this_gen,
+ fifo_buffer_t *video_fifo,
+ fifo_buffer_t *audio_fifo,
+ off_t start_pos, int start_time) {
+ demux_cda_t *this = (demux_cda_t *) this_gen;
+ buf_element_t *buf;
+ int err;
+
+ this->video_fifo = video_fifo;
+ this->audio_fifo = audio_fifo;
+
+ this->status = DEMUX_OK;
+ this->start = start_pos;
+
+ this->blocksize = this->input->get_blocksize(this->input);
+
+ buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
+ buf->type = BUF_CONTROL_START;
+ this->video_fifo->put (this->video_fifo, buf);
+
+ if(this->audio_fifo) {
+ buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
+ buf->type = BUF_CONTROL_START;
+ this->audio_fifo->put (this->audio_fifo, buf);
+ }
+
+ /*
+ * now start demuxing
+ */
+
+ if ((err = pthread_create (&this->thread,
+ NULL, demux_cda_loop, this)) != 0) {
+ fprintf (stderr, "demux_cda: can't create new thread (%s)\n", strerror(err));
+ exit(1);
+ }
+}
+
+/*
+ *
+ */
+static int demux_cda_open(demux_plugin_t *this_gen, input_plugin_t *input, int stage) {
+ demux_cda_t *this = (demux_cda_t *) this_gen;
+
+ switch(stage) {
+
+ case STAGE_BY_CONTENT:
+ return DEMUX_CANNOT_HANDLE;
+ break;
+
+ case STAGE_BY_EXTENSION: {
+ char *media;
+ char *MRL = input->get_mrl(input);
+
+ media = strstr(MRL, "://");
+ if(media) {
+ if(!strncasecmp(MRL, "cda", 3)) {
+ this->input = input;
+ return DEMUX_CAN_HANDLE;
+ }
+ }
+ }
+ break;
+
+ default:
+ return DEMUX_CANNOT_HANDLE;
+ break;
+ }
+
+ return DEMUX_CANNOT_HANDLE;
+}
+
+/*
+ *
+ */
+static char *demux_cda_get_id(void) {
+ return "CDA";
+}
+
+/*
+ *
+ */
+static char *demux_cda_get_mimetypes(void) {
+ return "audio/cda: CD Audio";
+}
+
+/*
+ *
+ */
+static void demux_cda_close (demux_plugin_t *this) {
+
+}
+
+/*
+ *
+ */
+static int demux_cda_get_stream_length (demux_plugin_t *this_gen) {
+
+ return 0;
+}
+
+/*
+ *
+ */
+demux_plugin_t *init_demuxer_plugin(int iface, xine_t *xine) {
+ demux_cda_t *this;
+
+ if (iface != 6) {
+ printf( "demux_cda: plugin doesn't support plugin API version %d.\n"
+ "demux_cda: this means there's a version mismatch between xine and this "
+ "demux_cda: demuxer plugin.\nInstalling current demux plugins should help.\n",
+ iface);
+ return NULL;
+ }
+
+ this = (demux_cda_t *) xine_xmalloc(sizeof(demux_cda_t));
+ this->config = xine->config;
+
+ this->demux_plugin.interface_version = DEMUX_CDA_IFACE_VERSION;
+ this->demux_plugin.open = demux_cda_open;
+ this->demux_plugin.start = demux_cda_start;
+ this->demux_plugin.stop = demux_cda_stop;
+ this->demux_plugin.close = demux_cda_close;
+ this->demux_plugin.get_status = demux_cda_get_status;
+ this->demux_plugin.get_identifier = demux_cda_get_id;
+ this->demux_plugin.get_stream_length = demux_cda_get_stream_length;
+ this->demux_plugin.get_mimetypes = demux_cda_get_mimetypes;
+
+ return &this->demux_plugin;
+}
diff --git a/src/input/Makefile.am b/src/input/Makefile.am
index 5f478f398..752025027 100644
--- a/src/input/Makefile.am
+++ b/src/input/Makefile.am
@@ -17,9 +17,10 @@ libdir = $(XINE_PLUGINDIR)
if HAVE_CDROM_IOCTLS
in_dvd = xineplug_inp_dvd.la
in_vcd = xineplug_inp_vcd.la
+in_cda = xineplug_inp_cda.la
endif
-lib_LTLIBRARIES = xineplug_inp_file.la $(in_dvd) $(in_vcd) \
+lib_LTLIBRARIES = xineplug_inp_file.la $(in_dvd) $(in_vcd) $(in_cda) \
xineplug_inp_stdin_fifo.la xineplug_inp_net.la \
xineplug_inp_rtp.la xineplug_inp_http.la
@@ -44,6 +45,9 @@ xineplug_inp_rtp_la_LDFLAGS = -avoid-version -module
xineplug_inp_http_la_SOURCES = input_http.c
xineplug_inp_http_la_LDFLAGS = -avoid-version -module
+xineplug_inp_cda_la_SOURCES = input_cda.c
+xineplug_inp_cda_la_LDFLAGS = -avoid-version -module
+
include_HEADERS = input_plugin.h
noinst_HEADERS = dvd_udf.h read_cache.h
diff --git a/src/input/input_cda.c b/src/input/input_cda.c
new file mode 100644
index 000000000..4dd7914bd
--- /dev/null
+++ b/src/input/input_cda.c
@@ -0,0 +1,919 @@
+/*
+ * Copyright (C) 2000-2001 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: input_cda.c,v 1.1 2001/12/06 23:53:20 f1rmb Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#ifdef HAVE_LINUX_CDROM_H
+# include <linux/cdrom.h>
+#endif
+#ifdef HAVE_SYS_CDIO_H
+# include <sys/cdio.h>
+/* TODO: not clean yet */
+# if defined (__FreeBSD__)
+# include <sys/cdrio.h>
+# endif
+#endif
+#if ! defined (HAVE_LINUX_CDROM_H) && ! defined (HAVE_SYS_CDIO_H)
+#error "you need to add cdrom / CDA support for your platform to input_cda and configure.in"
+#endif
+
+#include "xine_internal.h"
+#include "xineutils.h"
+#include "input_plugin.h"
+
+/*
+#define DEBUG_DISC
+#define DEBUG_POS
+*/
+
+#define CDROM "/dev/cdaudio"
+
+/* for type */
+#define CDAUDIO 1
+#define CDDATA 2
+
+/* for status */
+#define CDA_NO 1
+#define CDA_PLAY 2
+#define CDA_PAUSE 3
+#define CDA_STOP 4
+#define CDA_EJECT 5
+#define CDA_COMPLETE 6
+
+#define CDA_BLOCKSIZE 75
+
+typedef struct {
+ int type;
+ int length;
+ int start;
+ int track;
+} trackinfo_t;
+
+typedef struct {
+ int fd;
+ char *device_name;
+ int cur_track;
+ int cur_pos;
+ int status;
+ int num_tracks;
+ int first_track;
+ int length;
+ trackinfo_t *track;
+} cdainfo_t;
+
+typedef struct {
+
+ input_plugin_t input_plugin;
+
+ config_values_t *config;
+ xine_t *xine;
+
+ uint32_t speed;
+
+ char *mrl;
+
+ cdainfo_t *cda;
+
+ char *filelist[100];
+ int mrls_allocated_entries;
+ mrl_t **mrls;
+
+} cda_input_plugin_t;
+
+/* Func proto */
+static void _cda_stop_cd(cdainfo_t *);
+
+/*
+ * ******************************** PRIVATES ***************************************
+ */
+
+/*
+ * Get CDA status (pos, cur track, status)
+ * This function was grabbed and adapted from workbone (thanks to this team).
+ */
+static int _cda_get_status_cd(cdainfo_t *cda) {
+ struct cdrom_subchnl sc;
+ int cur_pos_abs = 0;
+ int cur_frame = 0;
+ int cur_track;
+ int cur_ntracks;
+ int cur_cdlen;
+ int cur_index;
+ int cur_pos_rel = 0;
+ int cur_tracklen;
+
+ if(cda == NULL || cda->fd < 0)
+ return 0;
+
+ cur_track = cda->cur_track;
+ cur_ntracks = cda->num_tracks;
+ cur_cdlen = cda->length;
+
+ sc.cdsc_format = CDROM_MSF;
+
+ if(ioctl(cda->fd, CDROMSUBCHNL, &sc)) {
+ fprintf(stderr, "input_cda: ioctl(CDROMSUBCHNL) failed: %s.\n", strerror(errno));
+ return 0;
+ }
+
+ switch (sc.cdsc_audiostatus) {
+ case CDROM_AUDIO_PLAY:
+ cda->status = CDA_PLAY;
+
+ __get_pos:
+
+ cur_pos_abs = sc.cdsc_absaddr.msf.minute * 60 + sc.cdsc_absaddr.msf.second;
+ cur_frame = cur_pos_abs * 75 + sc.cdsc_absaddr.msf.frame;
+
+ if(cur_track < 1
+ || cur_frame < cda->track[cur_track-1].start
+ || cur_frame >= (cur_track >= cur_ntracks ?
+ (cur_cdlen + 1) * 75 :
+ cda->track[cur_track].start)) {
+ cur_track = 0;
+
+ while (cur_track < cur_ntracks && cur_frame >= cda->track[cur_track].start)
+ cur_track++;
+ }
+
+ if(cur_track >= 1 && sc.cdsc_trk > cda->track[cur_track-1].track)
+ cur_track++;
+
+ cur_index = sc.cdsc_ind;
+
+ __get_posrel:
+
+ if(cur_track >= 1 && cur_track <= cur_ntracks) {
+ cur_pos_rel = (cur_frame - cda->track[cur_track-1].start) / 75;
+ if(cur_pos_rel < 0)
+ cur_pos_rel = -cur_pos_rel;
+ }
+
+ if(cur_pos_abs < 0)
+ cur_pos_abs = cur_frame = 0;
+
+ if(cur_track < 1)
+ cur_tracklen = cda->length;
+ else
+ cur_tracklen = cda->track[cur_track-1].length;
+ break;
+
+ case CDROM_AUDIO_PAUSED:
+ cda->status = CDA_PAUSE;
+ goto __get_pos;
+ break;
+
+ case CDROM_AUDIO_COMPLETED:
+ cda->status = CDA_COMPLETE;
+ break;
+
+ case CDROM_AUDIO_NO_STATUS:
+ cda->status = CDA_STOP;
+ goto __get_posrel;
+ }
+
+ if(cur_track == cda->cur_track)
+ cda->cur_pos = cur_pos_rel;
+ else {
+ if(cda->status == CDA_PLAY) {
+ _cda_stop_cd(cda);
+ cda->status = CDA_STOP;
+ cda->cur_pos = cda->track[cda->cur_track - 1].length;
+ }
+ }
+
+#ifdef DEBUG_DISC
+ printf("Current Track = %d\n", cda->cur_track);
+ printf("Current pos in track = %d (%02d:%02d:%02d)\n", cda->cur_pos,
+ (cda->cur_pos / (60 * 60)),
+ ((cda->cur_pos / 60) % 60),
+ (cda->cur_pos %60));
+ printf("Current status: ");
+ switch(cda->status) {
+ case CDA_NO:
+ printf("NO CD\n");
+ break;
+ case CDA_PLAY:
+ printf("PLAY\n");
+ break;
+ case CDA_PAUSE:
+ printf("PAUSE\n");
+ break;
+ case CDA_STOP:
+ printf("STOP\n");
+ break;
+ case CDA_EJECT:
+ printf("EJECT\n");
+ break;
+ case CDA_COMPLETE:
+ printf("COMPLETE\n");
+ break;
+ }
+#endif
+ return 1;
+}
+
+/*
+ * Play a time chunk (in secs);
+ */
+static int _cda_play_chunk_cd(cdainfo_t *cda, int start, int end) {
+ struct cdrom_msf msf;
+
+ if(cda == NULL || cda->fd < 0)
+ return 0;
+
+ end--;
+
+ if(start >= end)
+ start = end - 1;
+
+ msf.cdmsf_min0 = start / (60*75);
+ msf.cdmsf_sec0 = (start % (60*75)) / 75;
+ msf.cdmsf_frame0 = start % 75;
+ msf.cdmsf_min1 = end / (60*75);
+ msf.cdmsf_sec1 = (end % (60*75)) / 75;
+ msf.cdmsf_frame1 = end % 75;
+
+ if (ioctl(cda->fd, CDROMSTART)) {
+ fprintf(stderr, "input_cda: ioctl(CDROMSTART) failed: %s.\n", strerror(errno));
+ return 0;
+ }
+
+ if(ioctl(cda->fd, CDROMPLAYMSF, &msf)) {
+ fprintf(stderr, "input_cda: ioctl(CDROMPLAYMSF) failed: %s.\n", strerror(errno));
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Open audio cd device FD.
+ */
+static int _cda_open_cd(cdainfo_t *cda) {
+
+ if(cda == NULL)
+ return 0;
+
+ if((cda->fd = open(cda->device_name, 0)) < 0) {
+
+ if(errno == EACCES) {
+ fprintf(stderr, "input_cda: No rights to open %s.\n", cda->device_name);
+ }
+ else if(errno != ENXIO) {
+ fprintf(stderr, "input_cda: open() failed: %s.\n", strerror(errno));
+ }
+
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Close opened audio cd fd.
+ */
+static void _cda_close_cd(cdainfo_t *cda) {
+
+ if(cda == NULL)
+ return;
+
+ if(cda->fd >= 0) {
+ close(cda->fd);
+ cda->fd = -1;
+ }
+}
+
+/*
+ * Stop audio cd.
+ */
+static void _cda_stop_cd(cdainfo_t *cda) {
+
+ if (cda->fd < 0)
+ return;
+
+ if(cda->status != CDA_STOP) {
+ ioctl(cda->fd, CDROMSTOP);
+ _cda_get_status_cd(cda);
+ }
+}
+
+/*
+ * Pause audio cd.
+ */
+static void _cda_pause_cd(cdainfo_t *cda) {
+
+ if (cda->fd < 0)
+ return;
+
+ if(cda->status == CDA_PLAY) {
+ ioctl(cda->fd, CDROMPAUSE);
+ _cda_get_status_cd(cda);
+ }
+}
+
+/*
+ * Resume audio cd.
+ */
+static void _cda_resume_cd(cdainfo_t *cda) {
+
+ if (cda->fd < 0)
+ return;
+
+ if(cda->status == CDA_PAUSE) {
+ ioctl(cda->fd, CDROMRESUME);
+ _cda_get_status_cd(cda);
+ }
+}
+
+/*
+ * Eject audio cd.
+ */
+static int _cda_eject_cd(cdainfo_t *cda) {
+ int err, status;
+
+ if(cda->fd < 0)
+ _cda_open_cd(cda);
+
+#if defined (__linux__)
+ if((status = ioctl(cda->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT)) > 0) {
+ switch(status) {
+ case CDS_TRAY_OPEN:
+ if((err = ioctl(cda->fd, CDROMCLOSETRAY)) != 0) {
+ fprintf(stderr, "input_cda: ioctl(CDROMCLOSETRAY) failed: %s\n", strerror(errno));
+ }
+ break;
+ case CDS_DISC_OK:
+ if((err = ioctl(cda->fd, CDROMEJECT)) != 0) {
+ fprintf(stderr, "input_cda: ioctl(CDROMEJECT) failed: %s\n", strerror(errno));
+ }
+ break;
+ }
+ }
+ else {
+ fprintf(stderr, "input_cda: ioctl(CDROM_DRIVE_STATUS) failed: %s\n", strerror(errno));
+ _cda_close_cd(cda);
+ return 0;
+ }
+#elif defined (__FreeBSD__)
+ if(ioctl(cda->fd, CDIOCALLOW) == -1) {
+ fprintf(stderr, "input_cda: ioctl(CDROMALLOW) failed: %s\n", strerror(errno));
+ }
+ else {
+ if(ioctl(cda->fd, CDIOCEJECT) == -1) {
+ fprintf(stderr, "input_cda: ioctl(CDROMEJECT) failed: %s\n", strerror(errno));
+ }
+ }
+#elif defined (__sun)
+ if((err = ioctl(cda->fd, CDROMEJECT)) != 0) {
+ fprintf(stderr, "input_cda: ioctl(CDROMEJECT) failed: %s\n", strerror(errno));
+ }
+#endif
+
+ _cda_close_cd(cda);
+
+ return 1;
+}
+
+/*
+ * Read cd table of content.
+ */
+static int _cda_read_toc_cd(cdainfo_t *cda) {
+ struct cdrom_tochdr hdr;
+ struct cdrom_tocentry entry;
+ int i, pos;
+
+ if(ioctl(cda->fd, CDROMREADTOCHDR, &hdr)) {
+ fprintf(stderr, "input_cda: ioctl(CDROMREADTOCHDR) failed: %s.\n", strerror(errno));
+ return 0;
+ }
+
+ cda->first_track = hdr.cdth_trk0;
+ cda->num_tracks = hdr.cdth_trk1;
+
+ if(cda->track)
+ cda->track = (trackinfo_t *) realloc(cda->track, (cda->num_tracks + 1) * sizeof(trackinfo_t));
+ else
+ cda->track = (trackinfo_t *) malloc((cda->num_tracks + 1) * sizeof(trackinfo_t));
+
+ for(i = 0; i <= cda->num_tracks; i++) {
+ if(i == cda->num_tracks)
+ entry.cdte_track = CDROM_LEADOUT;
+ else
+ entry.cdte_track = i + 1;
+
+ entry.cdte_format = CDROM_MSF;
+
+ if(ioctl(cda->fd, CDROMREADTOCENTRY, &entry)) {
+ fprintf(stderr, "input_cda: ioctl(CDROMREADTOCENTRY) failed: %s.\n", strerror(errno));
+ return 0;
+ }
+ cda->track[i].track = i + 1;
+ cda->track[i].type = (entry.cdte_ctrl & CDROM_DATA_TRACK) ? CDDATA : CDAUDIO;
+ cda->track[i].length = entry.cdte_addr.msf.minute * 60 + entry.cdte_addr.msf.second;
+ cda->track[i].start = cda->track[i].length * 75 + entry.cdte_addr.msf.frame;
+ }
+
+ /* compute real track length */
+ pos = cda->track[0].length;
+ for(i = 0; i < cda->num_tracks; i++) {
+ cda->track[i].length = cda->track[i+1].length - pos;
+ pos = cda->track[i+1].length;
+ if(cda->track[i].type == CDDATA)
+ cda->track[i].length = (cda->track[i + 1].start - cda->track[i].start) * 2;
+ }
+
+ cda->length = cda->track[cda->num_tracks].length;
+
+#ifdef DEBUG_DISC
+ printf("Disc have %d track(s), first track is %d, length %d (%02d:%02d:%02d)\n",
+ cda->num_tracks, cda->first_track,
+ cda->length, (cda->length / (60 * 60)), ((cda->length / 60) % 60), (cda->length %60));
+ for(i = 0; i < cda->num_tracks; i++) {
+ printf("Track %2d, %s type, length %3d seconds(%02d:%02d:%02d), start at %3d secs\n",
+ i,
+ ((cda->track[i].type == CDDATA)?"DATA":"AUDIO"),
+ cda->track[i].length,
+ (cda->track[i].length / (60 * 60)),
+ ((cda->track[i].length / 60) % 60),
+ (cda->track[i].length %60),
+ cda->track[i].start);
+ }
+#endif
+
+ return 1;
+}
+
+/*
+ *
+ */
+static void _cda_play_track_to_track_from_pos(cdainfo_t *cda,
+ int start_track, int pos, int end_track) {
+ int start;
+ int end;
+
+ if(cda == NULL || cda->fd < 0)
+ return;
+
+ _cda_get_status_cd(cda);
+
+ start = start_track - 1;
+ end = end_track - 1;
+
+ if(start >= cda->num_tracks)
+ end = cda->length * 75;
+ else
+ end = cda->track[(end_track - 1)].start - 1;
+
+ if(_cda_play_chunk_cd(cda, cda->track[start].start + (pos * 75), end))
+ _cda_get_status_cd(cda);
+
+}
+
+/*
+ * Some frontends functions to _cda_play_track_to_track_from_pos()
+ */
+static void _cda_play_track_to_track(cdainfo_t *cda, int start_track, int end_track) {
+ _cda_play_track_to_track_from_pos(cda, start_track, 0, end_track);
+}
+static void _cda_play_track_from_pos(cdainfo_t *cda, int track, int pos) {
+ _cda_play_track_to_track_from_pos(cda, track, pos, track + 1);
+}
+static void _cda_play_track(cdainfo_t *cda, int track) {
+ _cda_play_track_to_track(cda, track, track + 1);
+}
+
+/*
+ *
+ */
+static void _cda_free_cda(cdainfo_t *cda) {
+
+ if(cda == NULL)
+ return;
+
+ _cda_close_cd(cda);
+
+ if(cda->device_name)
+ free(cda->device_name);
+ if(cda->track)
+ free(cda->track);
+ free(cda);
+}
+
+/*
+ * *************************** END OF PRIVATES ************************************
+ */
+
+/*
+ *
+ */
+static int cda_plugin_open (input_plugin_t *this_gen, char *mrl) {
+ cda_input_plugin_t *this = (cda_input_plugin_t *) this_gen;
+ char *filename;
+
+ this->mrl = mrl;
+
+ if(strncasecmp (mrl, "cda://", 6))
+ return 0;
+
+ if(!_cda_open_cd(this->cda)) {
+ _cda_free_cda(this->cda);
+ return 0;
+ }
+
+ if(!_cda_read_toc_cd(this->cda)) {
+ _cda_free_cda(this->cda);
+ return 0;
+ }
+
+ filename = (char *) &mrl[6];
+
+ if(sscanf(filename, "%d", &this->cda->cur_track) != 1) {
+ fprintf(stderr, "input_cda: malformed MRL. Use cda://<track #>\n");
+ _cda_free_cda(this->cda);
+ return 0;
+ }
+
+ if((!this->cda->cur_track) || (this->cda->cur_track > this->cda->num_tracks)) {
+ fprintf(stderr, "input_cda: invalid track %d (valid range: 1 .. %d)\n",
+ this->cda->cur_track, this->cda->num_tracks - 1);
+ _cda_free_cda(this->cda);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ *
+ */
+static buf_element_t *cda_plugin_read_block (input_plugin_t *this_gen,
+ fifo_buffer_t *fifo, off_t nlen) {
+ cda_input_plugin_t *this = (cda_input_plugin_t *) this_gen;
+ buf_element_t *buf;
+ unsigned char buffer[nlen];
+
+ /* Check if speed has changed */
+ if(this->xine->speed != this->speed) {
+ int old_status = this->cda->status;
+ this->speed = this->xine->speed;
+ if((this->speed == SPEED_PAUSE) && this->cda->status == CDA_PLAY) {
+ _cda_pause_cd(this->cda);
+ }
+ else {
+ if(old_status == CDA_PAUSE) {
+ _cda_resume_cd(this->cda);
+ }
+ }
+ }
+
+ memset(&buffer, 'X', sizeof(buffer));
+
+ buf = fifo->buffer_pool_alloc(fifo);
+ buf->content = buf->mem;
+ buf->type = BUF_DEMUX_BLOCK;
+ memcpy(buf->mem, buffer, nlen);
+
+ return buf;
+}
+
+/*
+ *
+ */
+static off_t cda_plugin_read (input_plugin_t *this_gen, char *buf, off_t nlen) {
+ cda_input_plugin_t *this = (cda_input_plugin_t *) this_gen;
+ char *buffer[nlen];
+
+ _cda_get_status_cd(this->cda);
+
+ /* Dummy */
+ memset(&buffer, 'X', sizeof(buf));
+ memcpy(buf, buffer, nlen);
+
+ return nlen;
+}
+
+/*
+ *
+ */
+static off_t cda_plugin_seek (input_plugin_t *this_gen, off_t offset, int origin) {
+ cda_input_plugin_t *this = (cda_input_plugin_t *) this_gen;
+
+ switch (origin) {
+ case SEEK_SET:
+ _cda_play_track_from_pos(this->cda, this->cda->cur_track, (int) (offset/CDA_BLOCKSIZE));
+ break;
+
+ default:
+ fprintf (stderr, "input_cda: error seek to origin %d not implemented!\n",
+ origin);
+ return 0;
+ }
+
+ return offset;
+}
+
+/*
+ * Return current length;
+ */
+static off_t cda_plugin_get_length (input_plugin_t *this_gen) {
+ cda_input_plugin_t *this = (cda_input_plugin_t *) this_gen;
+
+ return (this->cda->track[this->cda->cur_track-1].length * CDA_BLOCKSIZE);
+}
+
+/*
+ * Return current pos.
+ */
+static off_t cda_plugin_get_current_pos (input_plugin_t *this_gen){
+ cda_input_plugin_t *this = (cda_input_plugin_t *) this_gen;
+
+ _cda_get_status_cd(this->cda);
+
+#ifdef DEBUG_POS
+ printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b(%02d:%02d:%02d) (%d)%02d",
+ (this->cda->cur_pos / (60 * 60)),
+ ((this->cda->cur_pos / 60) % 60),
+ (this->cda->cur_pos %60),
+ this->cda->cur_track-1,
+ this->cda->track[this->cda->cur_track-1].length);
+#endif
+
+ return (this->cda->cur_pos * CDA_BLOCKSIZE);
+}
+
+/*
+ * Get plugin capabilities.
+ */
+static uint32_t cda_plugin_get_capabilities (input_plugin_t *this_gen) {
+
+ return INPUT_CAP_SEEKABLE | INPUT_CAP_AUTOPLAY | INPUT_CAP_GET_DIR;
+}
+
+/*
+ * Get (pseudo) blocksize.
+ */
+static uint32_t cda_plugin_get_blocksize (input_plugin_t *this_gen) {
+
+ return CDA_BLOCKSIZE;
+}
+
+/*
+ * Eject current media.
+ */
+static int cda_plugin_eject_media (input_plugin_t *this_gen) {
+ cda_input_plugin_t *this = (cda_input_plugin_t *) this_gen;
+
+ return (_cda_eject_cd(this->cda));
+}
+
+/*
+ * Close plugin.
+ */
+static void cda_plugin_close(input_plugin_t *this_gen) {
+ cda_input_plugin_t *this = (cda_input_plugin_t *) this_gen;
+
+ _cda_stop_cd(this->cda);
+}
+
+/*
+ * Plugin stop.
+ */
+static void cda_plugin_stop (input_plugin_t *this_gen) {
+ cda_input_plugin_t *this = (cda_input_plugin_t *) this_gen;
+
+ _cda_stop_cd(this->cda);
+ _cda_close_cd(this->cda);
+}
+
+/*
+ *
+ */
+static char *cda_plugin_get_description (input_plugin_t *this_gen) {
+ return "cd audio plugin as shipped with xine";
+}
+
+/*
+ *
+ */
+static char *cda_plugin_get_identifier (input_plugin_t *this_gen) {
+ return "CDA";
+}
+
+/*
+ * Get dir.
+ */
+static mrl_t **cda_plugin_get_dir (input_plugin_t *this_gen,
+ char *filename, int *nEntries) {
+ cda_input_plugin_t *this = (cda_input_plugin_t *) this_gen;
+ int i;
+
+ *nEntries = 0;
+
+ if(filename)
+ return NULL;
+
+ if(!_cda_open_cd(this->cda)) {
+ _cda_free_cda(this->cda);
+ return NULL;
+ }
+
+ if(!_cda_read_toc_cd(this->cda)) {
+ _cda_free_cda(this->cda);
+ return NULL;
+ }
+
+ _cda_close_cd(this->cda);
+
+ if(!this->cda->num_tracks)
+ return NULL;
+
+ *nEntries = this->cda->num_tracks;
+
+ for(i=1; i <= this->cda->num_tracks; i++) {
+ char mrl[1024];
+
+ memset(&mrl, 0, sizeof (mrl));
+ sprintf(mrl, "cda://%d",i);
+
+ if((i-1) >= this->mrls_allocated_entries) {
+ ++this->mrls_allocated_entries;
+ /* note: 1 extra pointer for terminating NULL */
+ this->mrls = realloc(this->mrls, (this->mrls_allocated_entries+1) * sizeof(mrl_t*));
+ this->mrls[(i-1)] = (mrl_t *) xine_xmalloc(sizeof(mrl_t));
+ }
+ else {
+ memset(this->mrls[(i-1)], 0, sizeof(mrl_t));
+ }
+
+ if(this->mrls[(i-1)]->mrl) {
+ this->mrls[(i-1)]->mrl = (char *)
+ realloc(this->mrls[(i-1)]->mrl, strlen(mrl) + 1);
+ }
+ else {
+ this->mrls[(i-1)]->mrl = (char *) xine_xmalloc(strlen(mrl) + 1);
+ }
+
+ this->mrls[i-1]->origin = NULL;
+ sprintf(this->mrls[i-1]->mrl, "%s", mrl);
+ this->mrls[i-1]->link = NULL;
+ this->mrls[i-1]->type = (0 | mrl_cda);
+ this->mrls[i-1]->size = this->cda->track[i-1].length;
+ }
+
+ /*
+ * Freeing exceeded mrls if exists.
+ */
+ while(this->mrls_allocated_entries > *nEntries) {
+ MRL_ZERO(this->mrls[this->mrls_allocated_entries - 1]);
+ free(this->mrls[this->mrls_allocated_entries--]);
+ }
+
+ this->mrls[*nEntries] = NULL;
+
+ return this->mrls;
+}
+
+/*
+ * Get autoplay.
+ */
+static char **cda_plugin_get_autoplay_list (input_plugin_t *this_gen, int *nFiles) {
+ cda_input_plugin_t *this = (cda_input_plugin_t *) this_gen;
+ int i;
+
+
+ *nFiles = 0;
+
+ if(!_cda_open_cd(this->cda)) {
+ _cda_free_cda(this->cda);
+ return NULL;
+ }
+
+ if(!_cda_read_toc_cd(this->cda)) {
+ _cda_free_cda(this->cda);
+ return NULL;
+ }
+
+ _cda_close_cd(this->cda);
+
+ if(!this->cda->num_tracks)
+ return NULL;
+
+ *nFiles = this->cda->num_tracks;
+
+ for(i = 1; i <= this->cda->num_tracks; i++)
+ sprintf (this->filelist[i-1], "cda://%d",i);
+
+ this->filelist[i-1] = NULL;
+
+ return this->filelist;
+}
+
+/*
+ * Return current MRL.
+ */
+static char* cda_plugin_get_mrl (input_plugin_t *this_gen) {
+ cda_input_plugin_t *this = (cda_input_plugin_t *) this_gen;
+
+ return this->mrl;
+}
+
+/*
+ * Get optional data.
+ */
+static int cda_plugin_get_optional_data (input_plugin_t *this_gen, void *data, int data_type) {
+
+ return INPUT_OPTIONAL_UNSUPPORTED;
+}
+
+/*
+ * Initialize plugin.
+ */
+input_plugin_t *init_input_plugin (int iface, xine_t *xine) {
+ cda_input_plugin_t *this;
+ config_values_t *config;
+ int i;
+
+ if (iface != 5) {
+ printf("cda input plugin doesn't support plugin API version %d.\n"
+ "PLUGIN DISABLED.\n"
+ "This means there's a version mismatch between xine and this input"
+ "plugin.\nInstalling current input plugins should help.\n",
+ iface);
+ return NULL;
+ }
+
+ this = (cda_input_plugin_t *) xine_xmalloc(sizeof(cda_input_plugin_t));
+ config = xine->config;
+
+ for (i = 0; i < 100; i++) {
+ this->filelist[i] = (char *) xine_xmalloc (256);
+ }
+
+ this->input_plugin.interface_version = INPUT_PLUGIN_IFACE_VERSION;
+ this->input_plugin.get_capabilities = cda_plugin_get_capabilities;
+ this->input_plugin.open = cda_plugin_open;
+ this->input_plugin.read = cda_plugin_read;
+ this->input_plugin.read_block = cda_plugin_read_block;
+ this->input_plugin.seek = cda_plugin_seek;
+ this->input_plugin.get_current_pos = cda_plugin_get_current_pos;
+ this->input_plugin.get_length = cda_plugin_get_length;
+ this->input_plugin.get_blocksize = cda_plugin_get_blocksize;
+ this->input_plugin.eject_media = cda_plugin_eject_media;
+ this->input_plugin.close = cda_plugin_close;
+ this->input_plugin.stop = cda_plugin_stop;
+ this->input_plugin.get_identifier = cda_plugin_get_identifier;
+ this->input_plugin.get_description = cda_plugin_get_description;
+ this->input_plugin.get_dir = cda_plugin_get_dir;
+ this->input_plugin.get_mrl = cda_plugin_get_mrl;
+ this->input_plugin.get_autoplay_list = cda_plugin_get_autoplay_list;
+ this->input_plugin.get_optional_data = cda_plugin_get_optional_data;
+ this->input_plugin.is_branch_possible = NULL;
+
+ this->xine = xine;
+ this->config = config;
+
+ this->mrl = NULL;
+
+ this->cda = (cdainfo_t *) xine_xmalloc(sizeof(cdainfo_t));
+ this->cda->cur_track = -1;
+ this->cda->cur_pos = -1;
+
+ this->cda->device_name = strdup(config->register_string(config, "input.cda_device", CDROM,
+ "path to your local cd audio device file",
+ NULL, NULL, NULL));
+
+ this->mrls = (mrl_t **) xine_xmalloc(sizeof(mrl_t*));
+ this->mrls_allocated_entries = 0;
+
+ return (input_plugin_t *) this;
+}
diff --git a/src/input/input_plugin.h b/src/input/input_plugin.h
index a820a6186..ea702126e 100644
--- a/src/input/input_plugin.h
+++ b/src/input/input_plugin.h
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: input_plugin.h,v 1.18 2001/12/01 22:38:31 guenter Exp $
+ * $Id: input_plugin.h,v 1.19 2001/12/06 23:53:20 f1rmb Exp $
*/
#ifndef HAVE_INPUT_PLUGIN_H
@@ -49,17 +49,18 @@ extern void *xmalloc(size_t);
#define mrl_net (1 << 2)
#define mrl_rtp (1 << 3)
#define mrl_stdin (1 << 4)
-#define mrl_file (1 << 5)
-#define mrl_file_fifo (1 << 6)
-#define mrl_file_chardev (1 << 7)
-#define mrl_file_directory (1 << 8)
-#define mrl_file_blockdev (1 << 9)
-#define mrl_file_normal (1 << 10)
-#define mrl_file_symlink (1 << 11)
-#define mrl_file_sock (1 << 12)
-#define mrl_file_exec (1 << 13)
-#define mrl_file_backup (1 << 14)
-#define mrl_file_hidden (1 << 15)
+#define mrl_cda (1 << 5)
+#define mrl_file (1 << 6)
+#define mrl_file_fifo (1 << 7)
+#define mrl_file_chardev (1 << 8)
+#define mrl_file_directory (1 << 9)
+#define mrl_file_blockdev (1 << 10)
+#define mrl_file_normal (1 << 11)
+#define mrl_file_symlink (1 << 12)
+#define mrl_file_sock (1 << 13)
+#define mrl_file_exec (1 << 14)
+#define mrl_file_backup (1 << 15)
+#define mrl_file_hidden (1 << 16)
/*
* Freeing/zeroing all of entries of given mrl.