⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 readers.c

📁 mips上编译过的mpg 运行正常 环境:AU12
💻 C
📖 第 1 页 / 共 2 页
字号:
/* TODO: Check all read calls (in loops, especially!) for return value 0 (EOF)! *//*	readers.c: reading input data	copyright ?-2008 by the mpg123 project - free software under the terms of the LGPL 2.1	see COPYING and AUTHORS files in distribution or http://mpg123.org	initially written by Michael Hipp*/#include <sys/stat.h>#include <fcntl.h>#include <errno.h>/* For select(), I need select.h according to POSIX 2001, else: sys/time.h sys/types.h unistd.h *//* Including these here although it works without on my Linux install... curious about _why_. */#ifdef HAVE_SYS_SELECT_H#include <sys/select.h>#endif#ifdef HAVE_SYS_TIME_H#include <sys/time.h>#endif#ifdef HAVE_SYS_TYPES_H#include <sys/types.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include "mpg123lib_intern.h"#include "debug.h"static int default_init(mpg123_handle *fr);static off_t get_fileinfo(mpg123_handle *);static ssize_t posix_read(int fd, void *buf, size_t count){ return read(fd, buf, count); }static off_t   posix_lseek(int fd, off_t offset, int whence){ return lseek(fd, offset, whence); }static ssize_t plain_fullread(mpg123_handle *fr,unsigned char *buf, ssize_t count);/* Bufferchain methods. */static void bc_init(struct bufferchain *bc);static void bc_reset(struct bufferchain *bc);static int bc_append(struct bufferchain *bc, ssize_t size);#if 0static void bc_drop(struct bufferchain *bc);#endifstatic int bc_add(struct bufferchain *bc, unsigned char *data, ssize_t size);static ssize_t bc_give(struct bufferchain *bc, unsigned char *out, size_t size);static ssize_t bc_skip(struct bufferchain *bc, ssize_t count);static ssize_t bc_seekback(struct bufferchain *bc, ssize_t count);static void bc_forget(struct bufferchain *bc);/* A normal read and a read with timeout. */static ssize_t plain_read(mpg123_handle *fr, void *buf, size_t count){	ssize_t ret = fr->rdat.read(fr->rdat.filept, buf, count);	debug2("read %li bytes of %li", (long)ret, (long)count);	return ret;}#ifndef WIN32/* Wait for data becoming available, allowing soft-broken network connection to die   This is needed for Shoutcast servers that have forgotten about us while connection was temporarily down. */static ssize_t timeout_read(mpg123_handle *fr, void *buf, size_t count){	struct timeval tv;	ssize_t ret = 0;	fd_set fds;	tv.tv_sec = fr->rdat.timeout_sec;	tv.tv_usec = 0;	FD_ZERO(&fds);	FD_SET(fr->rdat.filept, &fds);	ret = select(fr->rdat.filept+1, &fds, NULL, NULL, &tv);	/* This works only with "my" read function. Not user-replaced. */	if(ret > 0) ret = read(fr->rdat.filept, buf, count);	else	{		ret=-1; /* no activity is the error */		if(NOQUIET) error("stream timed out");	}	return ret;}#endif/* stream based operation  with icy meta data*/static ssize_t icy_fullread(mpg123_handle *fr, unsigned char *buf, ssize_t count){	ssize_t ret,cnt;	cnt = 0;	if(fr->rdat.flags & READER_SEEKABLE)	{		if(NOQUIET) error("mpg123 programmer error: I don't do ICY on seekable streams.");		return -1;	}	/*		We check against READER_ID3TAG instead of rds->filelen >= 0 because if we got the ID3 TAG we know we have the end of the file.		If we don't have an ID3 TAG, then it is possible the file has grown since we started playing, so we want to keep reading from it if possible.	*/	if((fr->rdat.flags & READER_ID3TAG) && fr->rdat.filepos + count > fr->rdat.filelen) count = fr->rdat.filelen - fr->rdat.filepos;	while(cnt < count)	{		/* all icy code is inside this if block, everything else is the plain fullread we know */		/* debug1("read: %li left", (long) count-cnt); */		if(fr->icy.next < count-cnt)		{			unsigned char temp_buff;			size_t meta_size;			ssize_t cut_pos;			/* we are near icy-metaint boundary, read up to the boundary */			if(fr->icy.next > 0)			{				cut_pos = fr->icy.next;				ret = fr->rdat.fdread(fr,buf,cut_pos);				if(ret < 1)				{					if(ret == 0) break; /* Just EOF. */					if(NOQUIET) error("icy boundary read");					return READER_ERROR;				}				fr->rdat.filepos += ret;				cnt += ret;				fr->icy.next -= ret;				if(fr->icy.next > 0)				{					debug1("another try... still %li left", fr->icy.next);					continue;				}			}			/* now off to read icy data */			/* one byte icy-meta size (must be multiplied by 16 to get icy-meta length) */						ret = fr->rdat.fdread(fr,&temp_buff,1); /* Getting one single byte hast to suceed. */			if(ret < 0){ if(NOQUIET) error("reading icy size"); return READER_ERROR; }			if(ret == 0) break;			debug2("got meta-size byte: %u, at filepos %li", temp_buff, (long)fr->rdat.filepos );			if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret; /* 1... */			if((meta_size = ((size_t) temp_buff) * 16))			{				/* we have got some metadata */				char *meta_buff;				meta_buff = malloc(meta_size+1);				if(meta_buff != NULL)				{					ssize_t left = meta_size;					while(left > 0)					{						ret = fr->rdat.fdread(fr,meta_buff+meta_size-left,left);						/* 0 is error here, too... there _must_ be the ICY data, the server promised! */						if(ret < 1){ if(NOQUIET) error("reading icy-meta"); return READER_ERROR; }						left -= ret;					}					meta_buff[meta_size] = 0; /* string paranoia */					if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret;					if(fr->icy.data) free(fr->icy.data);					fr->icy.data = meta_buff;					fr->metaflags |= MPG123_NEW_ICY;					debug2("icy-meta: %s size: %d bytes", fr->icy.data, (int)meta_size);				}				else				{					if(NOQUIET) error1("cannot allocate memory for meta_buff (%lu bytes) ... trying to skip the metadata!", (unsigned long)meta_size);					fr->rd->skip_bytes(fr, meta_size);				}			}			fr->icy.next = fr->icy.interval;		}		ret = plain_fullread(fr, buf+cnt, count-cnt);		if(ret < 0){ if(NOQUIET) error1("reading the rest of %li", (long)(count-cnt)); return READER_ERROR; }		if(ret == 0) break;		cnt += ret;		fr->icy.next -= ret;	}	/* debug1("done reading, got %li", (long)cnt); */	return cnt;}/* stream based operation */static ssize_t plain_fullread(mpg123_handle *fr,unsigned char *buf, ssize_t count){	ssize_t ret,cnt=0;	/*		We check against READER_ID3TAG instead of rds->filelen >= 0 because if we got the ID3 TAG we know we have the end of the file.		If we don't have an ID3 TAG, then it is possible the file has grown since we started playing, so we want to keep reading from it if possible.	*/	if((fr->rdat.flags & READER_ID3TAG) && fr->rdat.filepos + count > fr->rdat.filelen) count = fr->rdat.filelen - fr->rdat.filepos;	while(cnt < count)	{		ret = fr->rdat.fdread(fr,buf+cnt,count-cnt);		if(ret < 0) return READER_ERROR;		if(ret == 0) break;		if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret;		cnt += ret;	}	return cnt;}static off_t stream_lseek(mpg123_handle *fr, off_t pos, int whence){	off_t ret;	ret = fr->rdat.lseek(fr->rdat.filept, pos, whence);	if (ret >= 0)	fr->rdat.filepos = ret;	else ret = READER_ERROR; /* not the original value */	return ret;}static void stream_close(mpg123_handle *fr){	if(fr->rdat.flags & READER_FD_OPENED) close(fr->rdat.filept);	if(fr->rdat.flags & READER_BUFFERED)  bc_reset(&fr->rdat.buffer);}static int stream_seek_frame(mpg123_handle *fr, off_t newframe){	if(fr->rdat.flags & READER_SEEKABLE)	{		off_t preframe;		/* two leading frames? hm, doesn't seem to be really needed... */		/*if(newframe > 1) newframe -= 2;		else newframe = 0;*/		/* now seek to nearest leading index position and read from there until newframe is reached */		if(stream_lseek(fr,frame_index_find(fr, newframe, &preframe),SEEK_SET) < 0)		return READER_ERROR;		debug2("going to %lu; just got %lu", (long unsigned)newframe, (long unsigned)preframe);		fr->num = preframe-1; /* Watch out! I am going to read preframe... fr->num should indicate the frame before! */		while(fr->num < newframe)		{			/* try to be non-fatal now... frameNum only gets advanced on success anyway */			if(!read_frame(fr)) break;		}		/* Now the wanted frame should be ready for decoding. */		/* I think, I don't want this...		if(fr->lay == 3) set_pointer(fr, 512); */		debug1("arrived at %lu", (long unsigned)fr->num);		return MPG123_OK;	}	else return READER_ERROR; /* invalid, no seek happened */}/* return FALSE on error, TRUE on success, READER_MORE on occasion */static int generic_head_read(mpg123_handle *fr,unsigned long *newhead){	unsigned char hbuf[4];	int ret = fr->rd->fullread(fr,hbuf,4);	if(ret == READER_MORE) return ret;	if(ret != 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;}/* return FALSE on error, TRUE on success, READER_MORE on occasion */static int generic_head_shift(mpg123_handle *fr,unsigned long *head){	unsigned char hbuf;	int ret = fr->rd->fullread(fr,&hbuf,1);	if(ret == READER_MORE) return ret;	if(ret != 1) return FALSE;	*head <<= 8;	*head |= hbuf;	*head &= 0xffffffff;	return TRUE;}/* returns reached position... negative ones are bad... */static off_t stream_skip_bytes(mpg123_handle *fr,off_t len){	if(fr->rdat.flags & READER_SEEKABLE)	{		off_t ret = stream_lseek(fr, len, SEEK_CUR);		return ret<0 ? READER_ERROR : ret;	}	else if(len >= 0)	{		unsigned char buf[1024]; /* ThOr: Compaq cxx complained and it makes sense to me... or should one do a cast? What for? */		ssize_t ret;		while (len > 0)		{			ssize_t num = len < (off_t)sizeof(buf) ? (ssize_t)len : (ssize_t)sizeof(buf);			ret = fr->rd->fullread(fr, buf, num);			if (ret < 0) return ret;			else if(ret == 0) break; /* EOF... an error? interface defined to tell the actual position... */			len -= ret;		}		return fr->rd->tell(fr);	}	else if(fr->rdat.flags & READER_BUFFERED)	{ /* Perhaps we _can_ go a bit back. */		if(fr->rdat.buffer.pos >= -len)		{			fr->rdat.buffer.pos += len;			return fr->rd->tell(fr);		}		else return READER_ERROR;	}	else return READER_ERROR;}/* Return 0 on success... */static int stream_back_bytes(mpg123_handle *fr, off_t bytes){	off_t want = fr->rd->tell(fr)-bytes;	if(want < 0) return READER_ERROR;	if(stream_skip_bytes(fr,-bytes) != want) return READER_ERROR;	return 0;}/* returns size on success... */static int generic_read_frame_body(mpg123_handle *fr,unsigned char *buf, int size){	long l;	if((l=fr->rd->fullread(fr,buf,size)) != size)	{		long ll = l;		if(ll <= 0) ll = 0;		/* This allows partial frames at the end... do we really want to pad and decode these?! */		memset(buf+ll,0,size-ll);	}	return l;}static off_t generic_tell(mpg123_handle *fr){	if(fr->rdat.flags & READER_BUFFERED)	fr->rdat.filepos = fr->rdat.buffer.fileoff+fr->rdat.buffer.pos;	return fr->rdat.filepos;}/* This does not (fully) work for non-seekable streams... You have to check for that flag, pal! */static void stream_rewind(mpg123_handle *fr){	if(fr->rdat.flags & READER_SEEKABLE)	fr->rdat.buffer.fileoff = fr->rdat.filepos = stream_lseek(fr,0,SEEK_SET);	if(fr->rdat.flags & READER_BUFFERED)	{		fr->rdat.buffer.pos      = 0;		fr->rdat.buffer.firstpos = 0;		fr->rdat.filepos = fr->rdat.buffer.fileoff;	}}/* * returns length of a file (if filept points to a file) * reads the last 128 bytes information into buffer * ... that is not totally safe... */static off_t get_fileinfo(mpg123_handle *fr){	off_t len;	if((len=fr->rdat.lseek(fr->rdat.filept,0,SEEK_END)) < 0)	return -1;	if(fr->rdat.lseek(fr->rdat.filept,-128,SEEK_END) < 0) return -1;	if(fr->rd->fullread(fr,(unsigned char *)fr->id3buf,128) != 128)	return -1;	if(!strncmp((char*)fr->id3buf,"TAG",3))	len -= 128;	if(fr->rdat.lseek(fr->rdat.filept,0,SEEK_SET) < 0)	return -1;	if(len <= 0)	return -1;	return len;}/* Methods for the buffer chain, mainly used for feed reader, but not just that. */static void bc_init(struct bufferchain *bc){	bc->first = NULL;	bc->last  = bc->first;	bc->size  = 0;	bc->pos   = 0;	bc->firstpos = 0;	bc->fileoff  = 0;}static void bc_reset(struct bufferchain *bc){	/* free the buffer chain */	struct buffy *b = bc->first;	while(b != NULL)	{		struct buffy *n = b->next;		free(b->data);		free(b);		b = n;	}	bc_init(bc);}/* Create a new buffy at the end to be filled. */static int bc_append(struct bufferchain *bc, ssize_t size){	struct buffy *newbuf;	if(size < 1) return -1;	newbuf = malloc(sizeof(struct buffy));	if(newbuf == NULL) return -2;	newbuf->data = malloc(size);	if(newbuf->data == NULL)	{		free(newbuf);		return -3;	}	newbuf->size = size;	newbuf->next = NULL;	if(bc->last != NULL)  bc->last->next = newbuf;	else if(bc->first == NULL) bc->first = newbuf;	bc->last  = newbuf;	bc->size += size;	return 0;}#if 0/* Drop the last one (again).   This is not optimal but should happen on error situations only, anyway. */static void bc_drop(struct bufferchain *bc){	struct buffy *cur = bc->first;	if(bc->first == NULL || bc->last == NULL) return;	/* Special case: only one buffer there. */	if(cur->next == NULL)	{		free(cur->data);		free(cur);		bc->first = bc->last = NULL;		bc->size  = 0;		return;	}	/* Find the pre-last buffy. If chain is consistent, this _will_ succeed. */	while(cur->next != bc->last){ cur = cur->next; }	bc->size -= bc->last->size;	free(bc->last->data);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -