summaryrefslogtreecommitdiffstats
path: root/sys/vcd/vcdsrc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/vcd/vcdsrc.c')
-rw-r--r--sys/vcd/vcdsrc.c402
1 files changed, 402 insertions, 0 deletions
diff --git a/sys/vcd/vcdsrc.c b/sys/vcd/vcdsrc.c
new file mode 100644
index 00000000..e6fb2e90
--- /dev/null
+++ b/sys/vcd/vcdsrc.c
@@ -0,0 +1,402 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <linux/cdrom.h>
+
+#include <vcdsrc.h>
+
+
+static GstElementDetails vcdsrc_details = {
+ "VCD Source",
+ "Source/File/VCD",
+ "Asynchronous read from VCD disk",
+ VERSION,
+ "Erik Walthinsen <omega@cse.ogi.edu>",
+ "(C) 1999",
+};
+
+
+/* VCDSrc signals and args */
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ ARG_LOCATION,
+ ARG_TRACK,
+ ARG_BYTESPERREAD,
+ ARG_OFFSET,
+};
+
+static void vcdsrc_class_init (VCDSrcClass *klass);
+static void vcdsrc_init (VCDSrc *vcdsrc);
+static void vcdsrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void vcdsrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+
+static GstBuffer * vcdsrc_get (GstPad *pad);
+/*static GstBuffer * vcdsrc_get_region (GstPad *pad,gulong offset,gulong size); */
+static GstElementStateReturn vcdsrc_change_state (GstElement *element);
+
+static void vcdsrc_recalculate(VCDSrc *vcdsrc);
+
+
+static GstElementClass *parent_class = NULL;
+/*static guint vcdsrc_signals[LAST_SIGNAL] = { 0 }; */
+
+GType
+vcdsrc_get_type (void)
+{
+ static GType vcdsrc_type = 0;
+
+ if (!vcdsrc_type) {
+ static const GTypeInfo vcdsrc_info = {
+ sizeof(VCDSrcClass), NULL,
+ NULL,
+ (GClassInitFunc)vcdsrc_class_init,
+ NULL,
+ NULL,
+ sizeof(VCDSrc),
+ 0,
+ (GInstanceInitFunc)vcdsrc_init,
+ };
+ vcdsrc_type = g_type_register_static(GST_TYPE_ELEMENT, "VCDSrc", &vcdsrc_info, 0);
+ }
+ return vcdsrc_type;
+}
+
+static void
+vcdsrc_class_init (VCDSrcClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gstelement_class = (GstElementClass*)klass;
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_LOCATION,
+ g_param_spec_string("location","location","location",
+ NULL, G_PARAM_READWRITE)); /* CHECKME */
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TRACK,
+ g_param_spec_int("track","track","track",
+ G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BYTESPERREAD,
+ g_param_spec_int("bytesperread","bytesperread","bytesperread",
+ G_MININT,G_MAXINT,0,G_PARAM_READABLE)); /* CHECKME */
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_OFFSET,
+ g_param_spec_int("offset","offset","offset",
+ G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
+
+ gobject_class->set_property = vcdsrc_set_property;
+ gobject_class->get_property = vcdsrc_get_property;
+
+ gstelement_class->change_state = vcdsrc_change_state;
+}
+
+static void
+vcdsrc_init (VCDSrc *vcdsrc)
+{
+ vcdsrc->srcpad = gst_pad_new("src",GST_PAD_SRC);
+ gst_pad_set_get_function (vcdsrc->srcpad, vcdsrc_get);
+/* gst_pad_set_get_region_function (vcdsrc->srcpad, vcdsrc_getregion); */
+ gst_element_add_pad(GST_ELEMENT(vcdsrc),vcdsrc->srcpad);
+
+ vcdsrc->device = g_strdup ("/dev/cdrom");
+ vcdsrc->track = 2;
+ vcdsrc->fd = 0;
+ vcdsrc->trackoffset = 0;
+ vcdsrc->curoffset = 0;
+ vcdsrc->bytes_per_read = VCD_BYTES_PER_SECTOR;
+ vcdsrc->seq = 0;
+}
+
+
+static void
+vcdsrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ VCDSrc *src;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_VCDSRC(object));
+ src = VCDSRC(object);
+
+ switch (prop_id) {
+ case ARG_LOCATION:
+ /* the element must be stopped in order to do this */
+/* g_return_if_fail(!GST_FLAG_IS_SET(src,GST_STATE_RUNNING)); */
+
+ if (src->device) g_free(src->device);
+ /* clear the filename if we get a NULL (is that possible?) */
+ if (g_value_get_string (value) == NULL)
+ src->device = NULL;
+ /* otherwise set the new filename */
+ else
+ src->device = g_strdup(g_value_get_string (value));
+ break;
+ case ARG_TRACK:
+ src->track = g_value_get_int (value);
+ vcdsrc_recalculate(src);
+ break;
+/* case ARG_BYTESPERREAD:
+ src->bytes_per_read = g_value_get_int (value);
+ break;*/
+ case ARG_OFFSET:
+ src->curoffset = g_value_get_int (value) / VCD_BYTES_PER_SECTOR;
+ break;
+ default:
+ break;
+ }
+
+}
+
+static void
+vcdsrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ VCDSrc *src;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_VCDSRC(object));
+ src = VCDSRC(object);
+
+ switch (prop_id) {
+ case ARG_LOCATION:
+ g_value_set_string (value, src->device);
+ break;
+ case ARG_TRACK:
+ g_value_set_int (value, src->track);
+ break;
+ case ARG_BYTESPERREAD:
+ g_value_set_int (value, src->bytes_per_read);
+ break;
+ case ARG_OFFSET:
+ g_value_set_int (value, src->curoffset * VCD_BYTES_PER_SECTOR);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstBuffer *
+vcdsrc_get (GstPad *pad)
+{
+ VCDSrc *vcdsrc;
+ GstBuffer *buf;
+ gulong offset;
+ struct cdrom_msf *msf;
+ gint error_count = 0;
+
+ /* fprintf(stderr,"in vcdsrc_push\n"); */
+
+ g_return_val_if_fail(pad != NULL, NULL);
+ g_return_val_if_fail(GST_IS_PAD(pad), NULL);
+
+ vcdsrc = VCDSRC (GST_OBJECT_PARENT (pad));
+ g_return_val_if_fail (GST_FLAG_IS_SET (vcdsrc, VCDSRC_OPEN), NULL);
+
+ /* create the buffer */
+ /* FIXME: should eventually use a bufferpool for this */
+ buf = gst_buffer_new();
+ g_return_val_if_fail(buf != NULL, NULL);
+
+ /* allocate the space for the buffer data */
+ GST_BUFFER_DATA(buf) = g_malloc(vcdsrc->bytes_per_read);
+ memset(GST_BUFFER_DATA(buf),0,vcdsrc->bytes_per_read);
+ g_return_val_if_fail(GST_BUFFER_DATA(buf) != NULL, NULL);
+
+ msf = (struct cdrom_msf *)GST_BUFFER_DATA(buf);
+
+ read_sector:
+
+ /* read it in from the device */
+ offset = vcdsrc->trackoffset + vcdsrc->curoffset;
+ msf->cdmsf_frame0 = offset % 75;
+ msf->cdmsf_sec0 = (offset / 75) % 60;
+ msf->cdmsf_min0 = (offset / (75 * 60));
+
+ /*gst_info("msf is %d:%d:%d\n",msf->cdmsf_min0,msf->cdmsf_sec0, */
+ /* msf->cdmsf_frame0); */
+
+ if (ioctl(vcdsrc->fd,CDROMREADRAW,msf)) {
+ if (++error_count > 16)
+ {
+ fprintf (stderr, "End of CD\n");
+ exit(1);
+ }
+
+ fprintf (stderr, "%s while reading raw data from cdrom at %d:%d:%d\n",
+ strerror (errno),
+ msf->cdmsf_min0, msf->cdmsf_sec0, msf->cdmsf_frame0);
+ vcdsrc->curoffset += 1;
+ goto read_sector;
+ }
+
+/* if (readbytes == 0) { */
+/* gst_src_signal_eos(GST_SRC(vcdsrc)); */
+/* gst_element_set_state(GST_ELEMENT(vcdsrc),~GST_STATE_PLAYING); */
+/* gst_element_set_state(GST_ELEMENT(vcdsrc),~GST_STATE_RUNNING); */
+/* return; */
+/* } */
+
+ GST_BUFFER_OFFSET(buf) = vcdsrc->curoffset;
+ GST_BUFFER_SIZE(buf) = vcdsrc->bytes_per_read;
+ vcdsrc->curoffset += 1;
+
+ return buf;
+}
+
+/* open the file, necessary to go to RUNNING state */
+static gboolean
+vcdsrc_open_file(VCDSrc *src)
+{
+ int i;
+
+ g_return_val_if_fail(!GST_FLAG_IS_SET(src,VCDSRC_OPEN), FALSE);
+
+ /* open the device */
+ src->fd = open(src->device,O_RDONLY);
+ if (src->fd < 0) {
+ perror("open()");
+ gst_element_error(GST_ELEMENT(src),"opening file");
+ return FALSE;
+ }
+
+ /* read the table of contents */
+ if (ioctl(src->fd,CDROMREADTOCHDR,&src->tochdr)) {
+ perror("reading toc of VCD\n");
+/* FIXME */
+/* exit(1); */
+ }
+
+ /* allocate enough track structs for disk */
+ src->numtracks = (src->tochdr.cdth_trk1 - src->tochdr.cdth_trk0) + 1;
+ src->tracks = g_new (struct cdrom_tocentry, src->numtracks);
+
+ /* read each track entry */
+ for (i=0;i<src->numtracks;i++) {
+ src->tracks[i].cdte_track = i+1;
+ src->tracks[i].cdte_format = CDROM_MSF;
+ if (ioctl(src->fd,CDROMREADTOCENTRY, &src->tracks[i])) {
+ perror("reading tocentry");
+/* FIXME */
+/* exit(1);*/
+ }
+ fprintf(stderr,"VCDSrc: track begins at %d:%d:%d\n",
+ src->tracks[i].cdte_addr.msf.minute,
+ src->tracks[i].cdte_addr.msf.second,
+ src->tracks[i].cdte_addr.msf.frame);
+ }
+
+ src->trackoffset =
+(((src->tracks[src->track-1].cdte_addr.msf.minute * 60) +
+ src->tracks[src->track-1].cdte_addr.msf.second) * 75) +
+ src->tracks[src->track-1].cdte_addr.msf.frame;
+ fprintf(stderr,"VCDSrc: track offset is %ld\n",src->trackoffset);
+
+ GST_FLAG_SET(src,VCDSRC_OPEN);
+ return TRUE;
+}
+
+/* close the file */
+static void
+vcdsrc_close_file (VCDSrc *src)
+{
+ g_return_if_fail(GST_FLAG_IS_SET(src,VCDSRC_OPEN));
+
+ /* close the file */
+ close(src->fd);
+
+ /* zero out a lot of our state */
+ src->fd = 0;
+ src->curoffset = 0;
+ src->seq = 0;
+
+ GST_FLAG_UNSET(src,VCDSRC_OPEN);
+}
+
+static GstElementStateReturn
+vcdsrc_change_state (GstElement *element)
+{
+ g_return_val_if_fail(GST_IS_VCDSRC(element), GST_STATE_FAILURE);
+
+ /* if going down into NULL state, close the file if it's open */
+ if (GST_STATE_PENDING(element) == GST_STATE_NULL) {
+ if (GST_FLAG_IS_SET(element,VCDSRC_OPEN))
+ vcdsrc_close_file(VCDSRC(element));
+ /* otherwise (READY or higher) we need to open the sound card */
+ } else {
+ if (!GST_FLAG_IS_SET(element,VCDSRC_OPEN)) {
+ if (!vcdsrc_open_file(VCDSRC(element)))
+ return GST_STATE_FAILURE;
+ }
+ }
+
+ if (GST_ELEMENT_CLASS(parent_class)->change_state)
+ return GST_ELEMENT_CLASS(parent_class)->change_state(element);
+ return GST_STATE_SUCCESS;
+}
+
+static void
+vcdsrc_recalculate (VCDSrc *vcdsrc)
+{
+ if (GST_FLAG_IS_SET(vcdsrc,VCDSRC_OPEN)) {
+ /* calculate track offset (beginning of track) */
+ vcdsrc->trackoffset =
+(((vcdsrc->tracks[vcdsrc->track-1].cdte_addr.msf.minute * 60) +
+ vcdsrc->tracks[vcdsrc->track-1].cdte_addr.msf.second) * 75) +
+ vcdsrc->tracks[vcdsrc->track-1].cdte_addr.msf.frame;
+ fprintf(stderr,"VCDSrc: track offset is %ld\n",vcdsrc->trackoffset);
+ }
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstElementFactory *factory;
+
+ /* create an elementfactory for the vcdsrc element */
+ factory = gst_elementfactory_new("vcdsrc",GST_TYPE_VCDSRC,
+ &vcdsrc_details);
+ g_return_val_if_fail(factory != NULL, FALSE);
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "vcdsrc",
+ plugin_init
+};