summaryrefslogtreecommitdiffstats
path: root/mpg123_artsplugin/mpg123/readers.c
diff options
context:
space:
mode:
Diffstat (limited to 'mpg123_artsplugin/mpg123/readers.c')
-rw-r--r--mpg123_artsplugin/mpg123/readers.c618
1 files changed, 618 insertions, 0 deletions
diff --git a/mpg123_artsplugin/mpg123/readers.c b/mpg123_artsplugin/mpg123/readers.c
new file mode 100644
index 00000000..de5f53db
--- /dev/null
+++ b/mpg123_artsplugin/mpg123/readers.c
@@ -0,0 +1,618 @@
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "mpg123.h"
+#include "buffer.h"
+#include "common.h"
+
+#ifdef READ_MMAP
+#include <sys/mman.h>
+#ifndef MAP_FAILED
+#define MAP_FAILED ( (void *) -1 )
+#endif
+#endif
+
+static int get_fileinfo(struct reader *,char *buf);
+static void readers_add_data(struct reader *rds,unsigned char *buf,int len);
+
+/* can hold 4096-1 = 4095 bytes! */
+#define BACKBUF_SIZE (8192)
+
+/*******************************************************************
+ * stream based operation
+ */
+static int bufdiff(struct reader *rds,int start, int end)
+{
+ return (end >= start) ? end - start : rds->bufsize + end - start;
+}
+
+static int fullread(struct reader *rds,int fd,unsigned char *buf,int count)
+{
+ int ret,cnt=0;
+
+ while(cnt < count) {
+ int toread = count-cnt;
+ int num = bufdiff(rds,rds->bufpos,rds->bufend);
+
+ /* if we have some data in the backbuffer .. use it first */
+ if(num > 0) {
+ int part1,part2;
+
+ if(toread > num)
+ toread = num;
+
+ part1 = rds->bufsize - rds->bufpos;
+ if(part1 > toread)
+ part1 = toread;
+ part2 = toread - part1;
+ memcpy(buf+cnt,&rds->backbuf[rds->bufpos],part1);
+ if(part2 > 0)
+ memcpy(buf+cnt+part1,&rds->backbuf[0],part2);
+ rds->bufpos += toread;
+ if(rds->bufpos >= rds->bufsize)
+ rds->bufpos -= rds->bufsize;
+ ret = toread;
+
+ if(!rds->mark)
+ rds->bufstart = rds->bufpos;
+ }
+ else {
+ ret = read(fd,buf+cnt,toread);
+
+ if(ret < 0)
+ return ret;
+ if(ret == 0)
+ break;
+
+ if(rds->mark) {
+ readers_add_data(rds,buf+cnt,ret);
+ rds->bufpos = rds->bufend;
+ }
+
+ }
+ cnt += ret;
+ }
+
+
+if(0)
+{
+ int i;
+ fprintf(stderr,"Fullread2 %d\n",cnt);
+ for(i=0;i<cnt;i++) {
+ fprintf(stderr,"%02x ",buf[i]);
+ if(i % 16 == 15)
+ fprintf(stderr,"\n");
+ }
+}
+
+
+ return cnt;
+}
+
+static void readers_add_data(struct reader *rds,unsigned char *buf,int len)
+{
+ int diff,part1,part2,store = len;
+
+ if(store >= rds->bufsize)
+ store = rds->bufsize - 1;
+
+ /* check whether the new bytes would overwrite the buffer front */
+ diff = bufdiff(rds,rds->bufstart,rds->bufend);
+ if(diff+store >= rds->bufsize) {
+ fprintf(stderr,"Warning: backbuffer overfull %d %d\n",diff+store,rds->bufsize);
+ /* +1 because end should never be the same as start if the is data in the buffer */
+ rds->bufstart += diff + store + 1 - rds->bufsize;
+ if(rds->bufstart >= rds->bufsize)
+ rds->bufstart -= rds->bufsize;
+ }
+
+ part1 = rds->bufsize - rds->bufend;
+ if(part1 > store)
+ part1 = store;
+ part2 = store - part1;
+
+ memcpy(rds->backbuf+rds->bufend,&buf[len-part1+part2],part1);
+ if(part2 > 0)
+ memcpy(rds->backbuf,&buf[len-part2],part2);
+
+ rds->bufend += store;
+ if(rds->bufend >= rds->bufsize)
+ rds->bufend -= rds->bufsize;
+
+
+}
+
+void readers_pushback_header(struct reader *rds,unsigned long aLong)
+{
+ unsigned char buf[4];
+
+ if(rds->mark || (rds->bufpos != rds->bufend) ) {
+ rds->bufpos -= 4;
+ if(rds->bufpos < 0)
+ rds->bufpos += rds->bufsize;
+ }
+ else {
+ buf[0] = (aLong>>24) & 0xff;
+ buf[1] = (aLong>>16) & 0xff;
+ buf[2] = (aLong>>8) & 0xff;
+ buf[3] = (aLong>>0) & 0xff;
+ }
+
+ readers_add_data(rds,buf,4);
+}
+
+void readers_mark_pos(struct reader *rds) {
+ /* fprintf(stderr,"M%d ",rds->bufpos); */
+ rds->bufstart = rds->bufpos;
+ rds->mark = 1;
+}
+
+void readers_goto_mark(struct reader *rds) {
+ /* fprintf(stderr,"G%d ",rds->bufstart); */
+ rds->mark = 0;
+ rds->bufpos = rds->bufstart;
+}
+
+
+static int default_init(struct reader *rds)
+{
+ char buf[128];
+
+ rds->mark = 0;
+ rds->bufend = 0;
+ rds->bufstart = 0;
+ rds->bufpos = 0;
+ rds->bufsize = BACKBUF_SIZE;
+
+ rds->backbuf = (unsigned char *) malloc(rds->bufsize);
+
+ rds->filepos = 0;
+ rds->filelen = get_fileinfo(rds,buf);
+
+ if(rds->filelen > 0) {
+ if(!strncmp(buf,"TAG",3)) {
+ rds->flags |= READER_ID3TAG;
+ memcpy(rds->id3buf,buf,128);
+ }
+ }
+ return 0;
+}
+
+void stream_close(struct reader *rds)
+{
+ if (rds->flags & READER_FD_OPENED)
+ close(rds->filept);
+}
+
+/****************************************
+ * HACK,HACK,HACK: step back <num> frames
+ * can only work if the 'stream' isn't a real stream but a file
+ */
+static int stream_back_bytes(struct reader *rds,int bytes)
+{
+ if(lseek(rds->filept,-bytes,SEEK_CUR) < 0)
+ return -1;
+ if(param.usebuffer)
+ buffer_resync();
+ return 0;
+}
+
+static int stream_back_frame(struct reader *rds,struct frame *fr,int num)
+{
+ long bytes;
+ int skipped;
+
+ if(!fr->firsthead)
+ return 0;
+
+ bytes = (fr->framesize+8)*(num+2);
+
+ /* Skipping back/forth requires a bit more work in buffered mode.
+ * See mapped_back_frame().
+ */
+#ifndef NOXFERMEM
+ if(param.usebuffer)
+ bytes += (long)(xfermem_get_usedspace(buffermem) /
+ (buffermem->buf[0] * buffermem->buf[1]
+ * (buffermem->buf[2] & AUDIO_FORMAT_MASK ?
+ 16.0 : 8.0 ))
+ * (tabsel_123[fr->lsf][fr->lay-1][fr->bitrate_index] << 10));
+#endif
+ /*
+ bytes += (long)(compute_buffer_offset(fr)*compute_bpf(fr));
+ */
+ if(lseek(rds->filept,-bytes,SEEK_CUR) < 0)
+ return -1;
+
+ sync_stream(rds,fr,0xffff,&skipped);
+
+ read_frame(rds,fr);
+ read_frame(rds,fr);
+
+ if(fr->lay == 3) {
+ set_pointer(fr->sideInfoSize,512);
+ }
+
+ if(param.usebuffer)
+ buffer_resync();
+
+ return 0;
+}
+
+static int stream_head_read(struct reader *rds,unsigned long *newhead)
+{
+ unsigned char hbuf[4];
+
+ if(fullread(rds,rds->filept,hbuf,4) != 4)
+ return FALSE;
+
+ *newhead = ((unsigned long) hbuf[0] << 24) |
+ ((unsigned long) hbuf[1] << 16) |
+ ((unsigned long) hbuf[2] << 8) |
+ (unsigned long) hbuf[3];
+
+ return TRUE;
+}
+
+static int stream_head_shift(struct reader *rds,unsigned long *head)
+{
+ unsigned char hbuf;
+
+ if(fullread(rds,rds->filept,&hbuf,1) != 1)
+ return 0;
+ *head <<= 8;
+ *head |= hbuf;
+ *head &= 0xffffffff;
+ return 1;
+}
+
+static int stream_skip_bytes(struct reader *rds,int len)
+{
+ if (!param.usebuffer)
+ return lseek(rds->filept,len,SEEK_CUR);
+
+ else {
+ int ret = lseek(rds->filept,len,SEEK_CUR);
+ buffer_resync();
+ return ret;
+ }
+}
+
+static int stream_read_frame_body(struct reader *rds,unsigned char *buf,
+ int size)
+{
+ long l;
+
+ if( (l=fullread(rds,rds->filept,buf,size)) != size)
+ {
+ if(l <= 0)
+ return 0;
+ memset(buf+l,0,size-l);
+ }
+
+ return 1;
+}
+
+static long stream_tell(struct reader *rds)
+{
+ return lseek(rds->filept,0,SEEK_CUR);
+}
+
+static void stream_rewind(struct reader *rds)
+{
+ lseek(rds->filept,0,SEEK_SET);
+ if(param.usebuffer)
+ buffer_resync();
+}
+
+/*
+ * returns length of a file (if filept points to a file)
+ * reads the last 128 bytes information into buffer
+ */
+static int get_fileinfo(struct reader *rds,char *buf)
+{
+ int len;
+
+ if((len=lseek(rds->filept,0,SEEK_END)) < 0) {
+ return -1;
+ }
+ if(lseek(rds->filept,-128,SEEK_END) < 0)
+ return -1;
+ if(fullread(rds,rds->filept,(unsigned char *)buf,128) != 128) {
+ return -1;
+ }
+ if(!strncmp(buf,"TAG",3)) {
+ len -= 128;
+ }
+ if(lseek(rds->filept,0,SEEK_SET) < 0)
+ return -1;
+ if(len <= 0)
+ return -1;
+ return len;
+}
+
+
+#ifdef READ_MMAP
+/*********************************************************+
+ * memory mapped operation
+ *
+ */
+static unsigned char *mapbuf;
+static unsigned char *mappnt;
+static unsigned char *mapend;
+
+static int mapped_init(struct reader *rds)
+{
+ long len;
+ char buf[128];
+
+ len = get_fileinfo(rds,buf);
+ if(len < 0)
+ return -1;
+
+ if(!strncmp(buf,"TAG",3)) {
+ rds->flags |= READER_ID3TAG;
+ memcpy(rds->id3buf,buf,128);
+ }
+
+ mappnt = mapbuf = (unsigned char *)
+ mmap(NULL, len, PROT_READ, MAP_SHARED , rds->filept, 0);
+ if(!mapbuf || mapbuf == MAP_FAILED)
+ return -1;
+
+ mapend = mapbuf + len;
+
+ if(param.verbose > 1)
+ fprintf(stderr,"Using memory mapped IO for this stream.\n");
+
+ rds->filelen = len;
+ return 0;
+}
+
+static void mapped_rewind(struct reader *rds)
+{
+ mappnt = mapbuf;
+ if (param.usebuffer)
+ buffer_resync();
+}
+
+static void mapped_close(struct reader *rds)
+{
+ munmap((void *)mapbuf,mapend-mapbuf);
+ if (rds->flags & READER_FD_OPENED)
+ close(rds->filept);
+}
+
+static int mapped_head_read(struct reader *rds,unsigned long *newhead)
+{
+ unsigned long nh;
+
+ if(mappnt + 4 > mapend)
+ return FALSE;
+
+ nh = (*mappnt++) << 24;
+ nh |= (*mappnt++) << 16;
+ nh |= (*mappnt++) << 8;
+ nh |= (*mappnt++) ;
+
+ *newhead = nh;
+ return TRUE;
+}
+
+static int mapped_head_shift(struct reader *rds,unsigned long *head)
+{
+ if(mappnt + 1 > mapend)
+ return FALSE;
+ *head <<= 8;
+ *head |= *mappnt++;
+ *head &= 0xffffffff;
+ return TRUE;
+}
+
+static int mapped_skip_bytes(struct reader *rds,int len)
+{
+ if(mappnt + len > mapend)
+ return FALSE;
+ mappnt += len;
+ if (param.usebuffer)
+ buffer_resync();
+ return TRUE;
+}
+
+static int mapped_read_frame_body(struct reader *rds,unsigned char *buf,
+ int size)
+{
+ if(size <= 0) {
+ fprintf(stderr,"Ouch. Read_frame called with size <= 0\n");
+ return FALSE;
+ }
+ if(mappnt + size > mapend)
+ return FALSE;
+ memcpy(buf,mappnt,size);
+ mappnt += size;
+
+ return TRUE;
+}
+
+static int mapped_back_bytes(struct reader *rds,int bytes)
+{
+ if( (mappnt - bytes) < mapbuf || (mappnt - bytes + 4) > mapend)
+ return -1;
+ mappnt -= bytes;
+ if(param.usebuffer)
+ buffer_resync();
+ return 0;
+}
+
+static int mapped_back_frame(struct reader *rds,struct frame *fr,int num)
+{
+ long bytes;
+ unsigned long newhead;
+
+
+ if(!firsthead)
+ return 0;
+
+ bytes = (fr->framesize+8)*(num+2);
+
+ /* Buffered mode is a bit trickier. From the size of the buffered
+ * output audio stream we have to make a guess at the number of frames
+ * this corresponds to.
+ */
+#ifndef NOXFERMEM
+ if(param.usebuffer)
+ bytes += (long)(xfermem_get_usedspace(buffermem) /
+ (buffermem->buf[0] * buffermem->buf[1]
+ * (buffermem->buf[2] & AUDIO_FORMAT_MASK ?
+ 16.0 : 8.0 ))
+ * (tabsel_123[fr->lsf][fr->lay-1][fr->bitrate_index] << 10));
+#endif
+ /*
+ bytes += (long)(compute_buffer_offset(fr)*compute_bpf(fr));
+ */
+
+ if( (mappnt - bytes) < mapbuf || (mappnt - bytes + 4) > mapend)
+ return -1;
+ mappnt -= bytes;
+
+ newhead = (mappnt[0]<<24) + (mappnt[1]<<16) + (mappnt[2]<<8) + mappnt[3];
+ mappnt += 4;
+
+ while( (newhead & HDRCMPMASK) != (firsthead & HDRCMPMASK) ) {
+ if(mappnt + 1 > mapend)
+ return -1;
+ newhead <<= 8;
+ newhead |= *mappnt++;
+ newhead &= 0xffffffff;
+ }
+ mappnt -= 4;
+
+ read_frame(fr);
+ read_frame(fr);
+
+ if(fr->lay == 3)
+ set_pointer(fr->sideInfoSize,512);
+
+ if(param.usebuffer)
+ buffer_resync();
+
+ return 0;
+}
+
+static long mapped_tell(struct reader *rds)
+{
+ return mappnt - mapbuf;
+}
+
+#endif
+
+/*****************************************************************
+ * read frame helper
+ */
+
+struct reader *rd;
+struct reader readers[] = {
+#ifdef READ_SYSTEM
+ { system_init,
+ NULL, /* filled in by system_init() */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL } ,
+#endif
+#ifdef READ_MMAP
+ { mapped_init,
+ mapped_close,
+ mapped_head_read,
+ mapped_head_shift,
+ mapped_skip_bytes,
+ mapped_read_frame_body,
+ mapped_back_bytes,
+ mapped_back_frame,
+ mapped_tell,
+ mapped_rewind } ,
+#endif
+ { default_init,
+ stream_close,
+ stream_head_read,
+ stream_head_shift,
+ stream_skip_bytes,
+ stream_read_frame_body,
+ stream_back_bytes,
+ stream_back_frame,
+ stream_tell,
+ stream_rewind } ,
+ { NULL, }
+};
+
+
+/* open the device to read the bit stream from it */
+
+struct reader *open_stream(const char *bs_filenam,int fd)
+{
+ int i;
+ int filept_opened = 1;
+ int filept;
+
+ if (!bs_filenam) {
+ if(fd < 0) {
+ filept = 0;
+ filept_opened = 0;
+ }
+ else
+ filept = fd;
+ }
+ else if (!strncasecmp(bs_filenam, "http://", 7))
+ filept = http_open(bs_filenam);
+ else if (!strncasecmp(bs_filenam, "ftp://", 6))
+ filept = http_open(bs_filenam);
+
+#ifndef O_BINARY
+#define O_BINARY (0)
+#endif
+ else if ( (filept = open(bs_filenam, O_RDONLY|O_BINARY)) < 0) {
+ perror (bs_filenam);
+ return NULL;
+ }
+
+ rd = NULL;
+ for(i=0;;i++) {
+ readers[i].filelen = -1;
+ readers[i].filept = filept;
+ readers[i].flags = 0;
+ if(filept_opened)
+ readers[i].flags |= READER_FD_OPENED;
+ if(!readers[i].init) {
+ fprintf(stderr,"Fatal error!\n");
+ exit(1);
+ }
+ if(readers[i].init(readers+i) >= 0) {
+ rd = &readers[i];
+ break;
+ }
+ }
+
+ if(rd && rd->flags & READER_ID3TAG) {
+ print_id3_tag(rd->id3buf);
+ }
+
+ return rd;
+}
+
+
+
+
+
+
+
+
+
+
+
+