📄 mp3play.c
字号:
/****************************************************************************//* * mp3play.c -- Play MP3 data files * * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com) * (C) Copyright 1997-1997, St閜hane TAVENARD * All Rights Reserved * * This code is a derivitive of Stephane Tavenard's mpegdev_demo.c. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//****************************************************************************/#include "defs.h"#include "mpegdec.h"#include "genre.h"#include <sys/types.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/uio.h>#include <sys/file.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <getopt.h>#include <signal.h>#include <linux/soundcard.h>#include <sys/resource.h>#include <linux/config.h>#ifdef CONFIG_KEY#include <linux/key.h>#endif/****************************************************************************/int verbose;int quiet;int http_streaming;int lcd_line, lcd_time;int prebuflimit;int lcdfd = -1;int gotsigusr1;char key[128];/* * Keep track of start and end times. */struct timeval tvstart, tvend;/* * Global settings per decode stream. Used to control the final * PCM to raw driver data conversion. */static int stereo;static int bits;static int testtone;static int quality;/****************************************************************************//* * Master MP3 decoder settings. */static MPEGDEC_STREAM *mps = NULL;static MPEGDEC_CTRL mpa_ctrl;static MPEGDEC_CTRL mpa_defctrl = { NULL, // Bitstream access is default file I/O // Layers I & II settings (#3) { FALSE, { 1, 2, 48000 }, { 1, 2, 48000 } }, // Layer III settings (#3) { FALSE, { 1, 2, 48000 }, { 1, 2, 48000 } }, 0, // #2: Don't check mpeg validity at start // (needed for mux stream) 2048 // #2: Stream Buffer size};static char *modes[] = { "stereo", "j-stereo", "dual", "mono" };/****************************************************************************//* * MP3 data stream support (could be file or http stream). */#define MP3_BUF_SIZE (4*1024)static char *mp3_filename;static int mp3_fd;static INT8 *mp3_buffer;static UINT32 mp3_buffer_size;static UINT32 mp3_buffer_offset;static UINT32 mp3_buffer_next_block;static UINT32 mp3_stream_size;static char *rawbuf;static char *prebuffer;int prebufsize;int prebufcnt;int prebufnow;/****************************************************************************//* * MP3 file TAG info. Output when in verbose mode. This structure is * designed to match the in-file structure, don't change it! * Nice printable strings are generated in the other vars below. */struct mp3tag { char tag[3]; char title[30]; char artist[30]; char album[30]; char year[4]; char comments[30]; unsigned char genre;};static struct mp3tag mp3_tag;static int mp3_gottag;static char mp3_title[32];static char mp3_artist[32];static char mp3_year[8];static char mp3_album[32];static char mp3_comments[32];static char *mp3_genre;/****************************************************************************//* * Trivial signal handler, processing is done from the main loop. */void usr1_handler(int ignore){ gotsigusr1 = 1;}/****************************************************************************//* * Get stream size (just file size). */static int getstreamsize(void){ struct stat st; if (stat(mp3_filename, &st) < 0) return(0); return(st.st_size);}/****************************************************************************//* * Get another chunk of data into RAM. */static UINT32 getnextbuffer(){ int rc; lseek(mp3_fd, mp3_buffer_next_block, SEEK_SET); rc = read(mp3_fd, mp3_buffer, MP3_BUF_SIZE); mp3_buffer_size = (rc < 0) ? 0 : rc; mp3_buffer_next_block += mp3_buffer_size; return(mp3_buffer_size);}/****************************************************************************//* * Start our own bitstream access routines. */INT32 bs_open(char *stream_name, INT32 buffer_size, INT32 *stream_size){#if 0 printf("bs_open: '%s'\n", stream_name);#endif if (!mp3_buffer) return(0); mp3_buffer_offset = 0; /* We know total size, we can set it */ *stream_size = mp3_stream_size; /* Just return a dummy handle (not NULL) */ return(1);}/****************************************************************************/void bs_close(INT32 handle){#if 0 printf("bs_close\n");#endif /* Don't need to do anything... */}/****************************************************************************/INT32 bs_read(INT32 handle, void *buffer, INT32 num_bytes){ INT32 read_size; if (!handle ) return(-1);tryagain: read_size = mp3_buffer_size - mp3_buffer_offset; if (read_size > num_bytes) read_size = num_bytes; if (read_size > 0) { if(!buffer) return(-1); memcpy(buffer, &mp3_buffer[mp3_buffer_offset], read_size); mp3_buffer_offset += read_size; } else { if (getnextbuffer() > 0) { mp3_buffer_offset = 0; goto tryagain; } read_size = -1; /* End of stream */ } return(read_size);}/****************************************************************************/int bs_seek(INT32 handle, INT32 abs_byte_seek_pos){ if (!handle) return(-1); if (abs_byte_seek_pos <= 0) mp3_buffer_offset = 0; else if (abs_byte_seek_pos >= mp3_buffer_size) return(-1); else mp3_buffer_offset = abs_byte_seek_pos; return(0);}/****************************************************************************/MPEGDEC_ACCESS bs_access = { bs_open, bs_close, bs_read, bs_seek };/****************************************************************************/void mkstring(char *str, char *buf, int size){ int i, j = 0; char save; for (i = size - 1; i >= 0; i--) { if (buf[i] != ' ') { while (buf[j] == ' ') j++; strncpy(str, &buf[j], i - j + 1); str[i-j+1] = '\0'; return; } }}/****************************************************************************//* * Get TAG info from mp3 file, if it is present. No point doing a * fatal exit on errors, just assume no tag info is present. */void getmp3taginfo(void){ long pos; int size; mp3_gottag = 0; size = sizeof(mp3_tag); pos = mp3_stream_size - size; if (pos < 0) return; if (lseek(mp3_fd, pos, SEEK_SET) < 0) return; if (read(mp3_fd, &mp3_tag, size) != size) return; if (strncmp(&mp3_tag.tag[0], "TAG", 3) != 0) return; /* Return file pointer to start of file */ lseek(mp3_fd, 0, SEEK_SET); /* Construct fill NULL terminated strings */ mkstring(&mp3_title[0], &mp3_tag.title[0], sizeof(mp3_tag.title)); mkstring(&mp3_artist[0], &mp3_tag.artist[0], sizeof(mp3_tag.artist)); mkstring(&mp3_album[0], &mp3_tag.album[0], sizeof(mp3_tag.album)); mkstring(&mp3_year[0], &mp3_tag.year[0], sizeof(mp3_tag.year)); mkstring(&mp3_comments[0], &mp3_tag.comments[0], sizeof(mp3_tag.comments)); mp3_genre = (mp3_tag.genre >= genre_count) ? "Unknown" : genre_table[mp3_tag.genre]; mp3_gottag = 1;}/****************************************************************************//* * Print out everything we know about the MP3 stream. */void printmp3info(void){ if (quiet) return; if (verbose == 0) { printf("%s: MPEG%d-%s (%ld ms)\n", mp3_filename, mps->norm, (mps->layer == 1)?"I":(mps->layer == 2)?"II":"III", mps->ms_duration); return; } /* This is the verbose output */ printf("%s:\n", mp3_filename); printf(" MPEG%d-%s %s %dkbps %dHz (%ld ms)\n", mps->norm, (mps->layer == 1) ? "I" : (mps->layer == 2) ? "II" : "III", modes[mps->mode], mps->bitrate, mps->frequency, mps->ms_duration ); printf(" Decoding: Channels=%d Quality=%d Frequency=%dHz\n", mps->dec_channels, mps->dec_quality, mps->dec_frequency ); if (mp3_gottag) { printf(" Title: %s\n", mp3_title); printf(" Artist: %s\n", mp3_artist); printf(" Album: %s\n", mp3_album ); printf(" Year: %s\n", mp3_year); printf(" Comments: %s\n", mp3_comments); printf(" Genre: %s\n", mp3_genre); }}/****************************************************************************//* * Print out the name on a display device if present. */void lcdtitle(void){ char ctrl, *name; int ivp; struct iovec iv[4]; char prebuf[10]; char postbuf; char *p; int namelen; /* Install a signal handler to allow updates to be forced */ signal(SIGUSR1, usr1_handler); /* Determine the name to display. We use the tag if it is * present and the basename of the file if not. */ if (mp3_gottag) { name = mp3_title; namelen = strlen(name); } else { name = strrchr(mp3_filename, '/'); if (name == NULL) name = mp3_filename; else name++; p = strchr(name, '.'); if (p == NULL) namelen = strlen(name); else namelen = p - name; } if (lcd_line) { /* Lock the file so we can access it... */ if (flock(lcdfd, LOCK_SH | LOCK_NB) == -1) return; if (lcd_line == 0) { prebuf[0] = '\f'; prebuf[1] = '\0'; } else if (lcd_line == 1) { strcpy(prebuf, "\003\005"); } else if (lcd_line == 2) { strcpy(prebuf, "\003\v\005"); } /* * Now we'll write the title out. We'll do this atomically * just in case two players decide to coexecute... */ ivp = 0; iv[ivp].iov_len = strlen(prebuf) * sizeof(char); iv[ivp++].iov_base = prebuf; iv[ivp].iov_len = namelen * sizeof(char); iv[ivp++].iov_base = name; //postbuf = '\n'; //iv[ivp].iov_len = sizeof(char); //iv[ivp++].iov_base = &postbuf; writev(lcdfd, iv, ivp); /* Finally, unlock it since we've finished. */ flock(lcdfd, LOCK_UN); }}/****************************************************************************//* * Output time info to display device. */void lcdtime(time_t sttime){ static time_t lasttime; time_t t; char buf[15], *p; int m, s; t = time(NULL) - sttime; if (t != lasttime && flock(lcdfd, LOCK_SH | LOCK_NB) == 0) { p = buf; *p++ = '\003'; if (lcd_time == 2) *p++ = '\v'; *p++ = '\005'; m = t / 60; s = t % 60; if (s < 0) s += 60; sprintf(p, "%02d:%02d", m, s); write(lcdfd, buf, strlen(buf)); flock(lcdfd, LOCK_UN); } lasttime = t;}/****************************************************************************//* * Configure DSP engine settings for playing this track. */ void setdsp(int fd, int playstereo, int playbits)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -