?? mpg123.c
字號:
/* mpg123: main code of the program (not of the decoder...) copyright 1995-2006 by the mpg123 project - free software under the terms of the LGPL 2.1 see COPYING and AUTHORS files in distribution or http://mpg123.de initially written by Michael Hipp*/#include "config.h"#include "debug.h"#define ME "main"#include <stdlib.h>#include <sys/types.h>#if !defined(WIN32) && !defined(GENERIC)#include <sys/wait.h>#include <sys/time.h>#include <sys/resource.h>#endif#include <errno.h>#include <string.h>#include <fcntl.h>#include <time.h>#ifdef HAVE_SCHED_H#include <sched.h>#endif#include "mpg123.h"#include "getlopt.h"#include "buffer.h"#include "term.h"#ifdef GAPLESS#include "layer3.h"#endif#include "playlist.h"#include "id3.h"#include "icy.h"static void usage(int err);static void want_usage(char* arg);static void long_usage(int err);static void want_long_usage(char* arg);static void print_title(FILE* o);struct parameter param = { FALSE , /* aggressiv */ FALSE , /* shuffle */ FALSE , /* remote */ FALSE , /* remote to stderr */ DECODE_AUDIO , /* write samples to audio device */ FALSE , /* silent operation */ FALSE , /* xterm title on/off */ 0 , /* second level buffer size */ TRUE , /* resync after stream error */ 0 , /* verbose level */#ifdef HAVE_TERMIOS FALSE , /* term control */#endif -1 , /* force mono */ 0 , /* force stereo */ 0 , /* force 8bit */ 0 , /* force rate */ 0 , /* down sample */ FALSE , /* checkrange */ 0 , /* doublespeed */ 0 , /* halfspeed */ 0 , /* force_reopen, always (re)opens audio device for next song */#ifdef USE_3DNOW 0 , /* autodetect from CPUFLAGS */ FALSE , /* normal operation */#endif FALSE, /* try to run process in 'realtime mode' */ { 0,}, /* wav,cdr,au Filename */#ifdef GAPLESS 0, /* gapless off per default - yet */#endif 0, /* default is to play all titles in playlist */ 0, /* do not use rva per default */ NULL, /* no playlist per default */ 0 /* condensed id3 per default */};char *prgName = NULL;char *equalfile = NULL;/* ThOr: pointers are not TRUE or FALSE */int have_eq_settings = FALSE;long outscale = MAXOUTBURST;long numframes = -1;long startFrame= 0;int buffer_fd[2];int buffer_pid;static int intflag = FALSE;int OutputDescriptor;#if !defined(WIN32) && !defined(GENERIC)static void catch_child(void){ while (waitpid(-1, NULL, WNOHANG) > 0);}static void catch_interrupt(void){ intflag = TRUE;}#endif/* oh, what a mess... */void next_track(void){ intflag = TRUE;}void safe_exit(int code){#ifdef HAVE_TERMIOS if(param.term_ctrl) term_restore();#endif exit(code);}static struct frame fr;struct audio_info_struct ai,pre_ai;txfermem *buffermem = NULL;#define FRAMEBUFUNIT (18 * 64 * 4)void set_synth_functions(struct frame *fr);void init_output(void){ static int init_done = FALSE; if (init_done) return; init_done = TRUE;#ifndef NOXFERMEM /* * Only DECODE_AUDIO and DECODE_FILE are sanely handled by the * buffer process. For now, we just ignore the request * to buffer the output. [dk] */ if (param.usebuffer && (param.outmode != DECODE_AUDIO) && (param.outmode != DECODE_FILE)) { fprintf(stderr, "Sorry, won't buffer output unless writing plain audio.\n"); param.usebuffer = 0; } if (param.usebuffer) { unsigned int bufferbytes; sigset_t newsigset, oldsigset; if (param.usebuffer < 32) param.usebuffer = 32; /* minimum is 32 Kbytes! */ bufferbytes = (param.usebuffer * 1024); bufferbytes -= bufferbytes % FRAMEBUFUNIT; /* +1024 for NtoM rounding problems */ xfermem_init (&buffermem, bufferbytes ,0,1024); pcm_sample = (unsigned char *) buffermem->data; pcm_point = 0; sigemptyset (&newsigset); sigaddset (&newsigset, SIGUSR1); sigprocmask (SIG_BLOCK, &newsigset, &oldsigset); #if !defined(WIN32) && !defined(GENERIC) catchsignal (SIGCHLD, catch_child); #endif switch ((buffer_pid = fork())) { case -1: /* error */ perror("fork()"); safe_exit(1); case 0: /* child */ if(rd) rd->close(rd); /* child doesn't need the input stream */ xfermem_init_reader (buffermem); buffer_loop (&ai, &oldsigset); xfermem_done_reader (buffermem); xfermem_done (buffermem); exit(0); default: /* parent */ xfermem_init_writer (buffermem); param.outmode = DECODE_BUFFER; } } else {#endif /* + 1024 for NtoM rate converter */ if (!(pcm_sample = (unsigned char *) malloc(audiobufsize * 2 + 1024))) { perror ("malloc()"); safe_exit (1);#ifndef NOXFERMEM }#endif } switch(param.outmode) { case DECODE_AUDIO: if(audio_open(&ai) < 0) { perror("audio"); safe_exit(1); } break; case DECODE_WAV: wav_open(&ai,param.filename); break; case DECODE_AU: au_open(&ai,param.filename); break; case DECODE_CDR: cdr_open(&ai,param.filename); break; }}static void set_output_h(char *a){ if(ai.output <= 0) ai.output = AUDIO_OUT_HEADPHONES; else ai.output |= AUDIO_OUT_HEADPHONES;}static void set_output_s(char *a){ if(ai.output <= 0) ai.output = AUDIO_OUT_INTERNAL_SPEAKER; else ai.output |= AUDIO_OUT_INTERNAL_SPEAKER;}static void set_output_l(char *a){ if(ai.output <= 0) ai.output = AUDIO_OUT_LINE_OUT; else ai.output |= AUDIO_OUT_LINE_OUT;}static void set_output (char *arg){ switch (*arg) { case 'h': set_output_h(arg); break; case 's': set_output_s(arg); break; case 'l': set_output_l(arg); break; default: error3("%s: Unknown argument \"%s\" to option \"%s\".\n", prgName, arg, loptarg); safe_exit(1); }}void set_verbose (char *arg){ param.verbose++;}void set_wav(char *arg){ param.outmode = DECODE_WAV; strncpy(param.filename,arg,255); param.filename[255] = 0;}void set_cdr(char *arg){ param.outmode = DECODE_CDR; strncpy(param.filename,arg,255); param.filename[255] = 0;}void set_au(char *arg){ param.outmode = DECODE_AU; strncpy(param.filename,arg,255); param.filename[255] = 0;}static void SetOutFile(char *Arg){ param.outmode=DECODE_FILE; OutputDescriptor=open(Arg,O_WRONLY,0); if(OutputDescriptor==-1) { error2("Can't open %s for writing (%s).\n",Arg,strerror(errno)); safe_exit(1); }}static void SetOutStdout(char *Arg){ param.outmode=DECODE_FILE; OutputDescriptor=1;}static void SetOutStdout1(char *Arg){ param.outmode=DECODE_AUDIOFILE; OutputDescriptor=1;}void realtime_not_compiled(char *arg){ fprintf(stderr,"Option '-T / --realtime' not compiled into this binary.\n");}/* Please note: GLO_NUM expects point to LONG! *//* ThOr: * Yeah, and despite that numerous addresses to int variables were passed. * That's not good on my Alpha machine with int=32bit and long=64bit! * Introduced GLO_INT and GLO_LONG as different bits to make that clear. * GLO_NUM no longer exists. */topt opts[] = { {'k', "skip", GLO_ARG | GLO_LONG, 0, &startFrame, 0}, {'a', "audiodevice", GLO_ARG | GLO_CHAR, 0, &ai.device, 0}, {'2', "2to1", GLO_INT, 0, ¶m.down_sample, 1}, {'4', "4to1", GLO_INT, 0, ¶m.down_sample, 2}, {'t', "test", GLO_INT, 0, ¶m.outmode, DECODE_TEST}, {'s', "stdout", GLO_INT, SetOutStdout, ¶m.outmode, DECODE_FILE}, {'S', "STDOUT", GLO_INT, SetOutStdout1, ¶m.outmode,DECODE_AUDIOFILE}, {'O', "outfile", GLO_ARG | GLO_CHAR, SetOutFile, NULL, 0}, {'c', "check", GLO_INT, 0, ¶m.checkrange, TRUE}, {'v', "verbose", 0, set_verbose, 0, 0}, {'q', "quiet", GLO_INT, 0, ¶m.quiet, TRUE}, {'y', "resync", GLO_INT, 0, ¶m.tryresync, FALSE}, {'0', "single0", GLO_INT, 0, ¶m.force_mono, 0}, {0, "left", GLO_INT, 0, ¶m.force_mono, 0}, {'1', "single1", GLO_INT, 0, ¶m.force_mono, 1}, {0, "right", GLO_INT, 0, ¶m.force_mono, 1}, {'m', "singlemix", GLO_INT, 0, ¶m.force_mono, 3}, {0, "mix", GLO_INT, 0, ¶m.force_mono, 3}, {0, "mono", GLO_INT, 0, ¶m.force_mono, 3}, {0, "stereo", GLO_INT, 0, ¶m.force_stereo, 1}, {0, "reopen", GLO_INT, 0, ¶m.force_reopen, 1}, {'g', "gain", GLO_ARG | GLO_LONG, 0, &ai.gain, 0}, {'r', "rate", GLO_ARG | GLO_LONG, 0, ¶m.force_rate, 0}, {0, "8bit", GLO_INT, 0, ¶m.force_8bit, 1}, {0, "headphones", 0, set_output_h, 0,0}, {0, "speaker", 0, set_output_s, 0,0}, {0, "lineout", 0, set_output_l, 0,0}, {'o', "output", GLO_ARG | GLO_CHAR, set_output, 0, 0}, {'f', "scale", GLO_ARG | GLO_LONG, 0, &outscale, 0}, {'n', "frames", GLO_ARG | GLO_LONG, 0, &numframes, 0}, #ifdef HAVE_TERMIOS {'C', "control", GLO_INT, 0, ¶m.term_ctrl, TRUE}, #endif {'b', "buffer", GLO_ARG | GLO_LONG, 0, ¶m.usebuffer, 0}, {'R', "remote", GLO_INT, 0, ¶m.remote, TRUE}, {0, "remote-err", GLO_INT, 0, ¶m.remote_err, TRUE}, {'d', "doublespeed", GLO_ARG | GLO_LONG, 0, ¶m.doublespeed,0}, {'h', "halfspeed", GLO_ARG | GLO_LONG, 0, ¶m.halfspeed, 0}, {'p', "proxy", GLO_ARG | GLO_CHAR, 0, &proxyurl, 0}, {'@', "list", GLO_ARG | GLO_CHAR, 0, ¶m.listname, 0}, /* 'z' comes from the the german word 'zufall' (eng: random) */ {'z', "shuffle", GLO_INT, 0, ¶m.shuffle, 1}, {'Z', "random", GLO_INT, 0, ¶m.shuffle, 2}, {'E', "equalizer", GLO_ARG | GLO_CHAR, 0, &equalfile,1}, #ifdef HAVE_SETPRIORITY {0, "aggressive", GLO_INT, 0, ¶m.aggressive, 2}, #endif #ifdef USE_3DNOW {0, "force-3dnow", GLO_INT, 0, ¶m.stat_3dnow, 1}, {0, "no-3dnow", GLO_INT, 0, ¶m.stat_3dnow, 2}, {0, "test-3dnow", GLO_INT, 0, ¶m.test_3dnow, TRUE}, #endif #if !defined(WIN32) && !defined(GENERIC) {'u', "auth", GLO_ARG | GLO_CHAR, 0, &httpauth, 0}, #endif #ifdef HAVE_SCHED_SETSCHEDULER /* check why this should be a long variable instead of int! */ {'T', "realtime", GLO_LONG, 0, ¶m.realtime, TRUE }, #else {'T', "realtime", 0, realtime_not_compiled, 0, 0 }, #endif {0, "title", GLO_INT, 0, ¶m.xterm_title, TRUE }, {'w', "wav", GLO_ARG | GLO_CHAR, set_wav, 0 , 0 }, {0, "cdr", GLO_ARG | GLO_CHAR, set_cdr, 0 , 0 }, {0, "au", GLO_ARG | GLO_CHAR, set_au, 0 , 0 }, #ifdef GAPLESS {0, "gapless", GLO_INT, 0, ¶m.gapless, 1}, #endif {'?', "help", 0, want_usage, 0, 0 }, {0 , "longhelp" , 0, want_long_usage, 0, 0 }, {0 , "version" , 0, give_version, 0, 0 }, {'l', "listentry", GLO_ARG | GLO_LONG, 0, ¶m.listentry, 0 }, {0, "rva-mix", GLO_INT, 0, ¶m.rva, 1 }, {0, "rva-radio", GLO_INT, 0, ¶m.rva, 1 }, {0, "rva-album", GLO_INT, 0, ¶m.rva, 2 }, {0, "rva-audiophile", GLO_INT, 0, ¶m.rva, 2 }, {0, "long-tag", GLO_INT, 0, ¶m.long_id3, 1 }, {0, 0, 0, 0, 0, 0}};/* * Change the playback sample rate. * Consider that changing it after starting playback is not covered by gapless code! */static void reset_audio(void){#ifndef NOXFERMEM if (param.usebuffer) { /* wait until the buffer is empty, * then tell the buffer process to * change the sample rate. [OF] */ while (xfermem_get_usedspace(buffermem) > 0) if (xfermem_block(XF_WRITER, buffermem) == XF_CMD_TERMINATE) { intflag = TRUE; break; } buffermem->freeindex = -1; buffermem->readindex = 0; /* I know what I'm doing! ;-) */ buffermem->freeindex = 0; if (intflag) return;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -