#include #include #include #include #include "mpg123.h" #include "buffer.h" #include "common.h" #ifdef READ_MMAP #include #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= 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 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; }