#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); /******************************************************************* * stream based operation */ static int fullread(int fd,unsigned char *buf,int count) { int ret,cnt=0; while(cnt < count) { ret = read(fd,buf+cnt,count-cnt); if(ret < 0) return ret; if(ret == 0) break; cnt += ret; } return cnt; } static int default_init(struct reader *rds) { char buf[128]; 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; unsigned char buf[4]; unsigned long newhead; if(!firsthead) return 0; bytes = (fr->framesize+8)*(num+2); /* Skipping back/forth requires a bit more work in buffered mode. * See mapped_back_frame(). */ 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)); /* bytes += (long)(compute_buffer_offset(fr)*compute_bpf(fr)); */ if(lseek(rds->filept,-bytes,SEEK_CUR) < 0) return -1; if(fullread(rds->filept,buf,4) != 4) return -1; newhead = (buf[0]<<24) + (buf[1]<<16) + (buf[2]<<8) + buf[3]; while( (newhead & HDRCMPMASK) != (firsthead & HDRCMPMASK) ) { if(fullread(rds->filept,buf,1) != 1) return -1; newhead <<= 8; newhead |= buf[0]; newhead &= 0xffffffff; } if( lseek(rds->filept,-4,SEEK_CUR) < 0) return -1; read_frame(fr); read_frame(fr); if(fr->lay == 3) { set_pointer(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->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->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->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->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. */ 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)); /* 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(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 */ void open_stream(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 (!strncmp(bs_filenam, "http://", 7)) 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); exit(1); } 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); } }