📄 frame.c
字号:
fr->begin_os = frame_ins2outs(fr, fr->begin_s); fr->end_os = frame_ins2outs(fr, fr->end_s); debug2("frame_gapless_realinit: from %lu to %lu samples", (long unsigned)fr->begin_os, (long unsigned)fr->end_os);}#endif/* The frame seek... This is not simply the seek to fe*spf(fr) samples in output because we think of _input_ frames here. Seek to frame offset 1 may be just seek to 200 samples offset in output since the beginning of first frame is delay/padding. Hm, is that right? OK for the padding stuff, but actually, should the decoder delay be better totally hidden or not? With gapless, even the whole frame position could be advanced further than requested (since Homey don't play dat). */void frame_set_frameseek(mpg123_handle *fr, off_t fe){ fr->firstframe = fe;#ifdef GAPLESS if(fr->p.flags & MPG123_GAPLESS) { /* Take care of the beginning... */ off_t beg_f = frame_offset(fr, fr->begin_os); if(fe <= beg_f) { fr->firstframe = beg_f; fr->firstoff = fr->begin_os - frame_outs(fr, beg_f); } else fr->firstoff = 0; /* The end is set once for a track at least, on the frame_set_frameseek called in get_next_frame() */ if(fr->end_os > 0) { fr->lastframe = frame_offset(fr,fr->end_os); fr->lastoff = fr->end_os - frame_outs(fr, fr->lastframe); } else fr->lastoff = 0; } else { fr->firstoff = fr->lastoff = 0; fr->lastframe = -1; }#endif fr->ignoreframe = fr->lay == 3 ? fr->firstframe-IGNORESHIFT : fr->firstframe;#ifdef GAPLESS debug5("frame_set_frameseek: begin at %li frames and %li samples, end at %li and %li; ignore from %li", (long) fr->firstframe, (long) fr->firstoff, (long) fr->lastframe, (long) fr->lastoff, (long) fr->ignoreframe);#else debug3("frame_set_frameseek: begin at %li frames, end at %li; ignore from %li", (long) fr->firstframe, (long) fr->lastframe, (long) fr->ignoreframe);#endif}/* Sample accurate seek prepare for decoder. *//* This gets unadjusted output samples and takes resampling into account */void frame_set_seek(mpg123_handle *fr, off_t sp){ fr->firstframe = frame_offset(fr, sp); fr->ignoreframe = fr->lay == 3 ? fr->firstframe-IGNORESHIFT : fr->firstframe;#ifdef GAPLESS /* The sample offset is used for non-gapless mode, too! */ fr->firstoff = sp - frame_outs(fr, fr->firstframe); debug5("frame_set_seek: begin at %li frames and %li samples, end at %li and %li; ignore from %li", (long) fr->firstframe, (long) fr->firstoff, (long) fr->lastframe, (long) fr->lastoff, (long) fr->ignoreframe);#else debug3("frame_set_seek: begin at %li frames, end at %li; ignore from %li", (long) fr->firstframe, (long) fr->lastframe, (long) fr->ignoreframe);#endif}/* Unadjusted! */off_t frame_tell_seek(mpg123_handle *fr){ off_t pos = frame_outs(fr, fr->firstframe);#ifdef GAPLESS pos += fr->firstoff;#endif return pos;}/* to vanish */void frame_outformat(mpg123_handle *fr, int format, int channels, long rate){ fr->af.encoding = format; fr->af.rate = rate; fr->af.channels = channels;}/* set synth functions for current frame, optimizations handled by opt_* macros */int set_synth_functions(mpg123_handle *fr){ int ds = fr->down_sample; int p8=0; static func_synth funcs[2][4] = { { NULL, synth_2to1, synth_4to1, synth_ntom } , { NULL, synth_2to1_8bit, synth_4to1_8bit, synth_ntom_8bit } }; static func_synth_mono funcs_mono[2][2][4] = { { { NULL , synth_2to1_mono2stereo , synth_4to1_mono2stereo , synth_ntom_mono2stereo } , { NULL , synth_2to1_8bit_mono2stereo , synth_4to1_8bit_mono2stereo , synth_ntom_8bit_mono2stereo } } , { { NULL , synth_2to1_mono , synth_4to1_mono , synth_ntom_mono } , { NULL , synth_2to1_8bit_mono , synth_4to1_8bit_mono , synth_ntom_8bit_mono } } }; /* possibly non-constand entries filled here */ funcs[0][0] = (func_synth) opt_synth_1to1(fr); funcs[1][0] = (func_synth) opt_synth_1to1_8bit(fr); funcs_mono[0][0][0] = (func_synth_mono) opt_synth_1to1_mono2stereo(fr); funcs_mono[0][1][0] = (func_synth_mono) opt_synth_1to1_8bit_mono2stereo(fr); funcs_mono[1][0][0] = (func_synth_mono) opt_synth_1to1_mono(fr); funcs_mono[1][1][0] = (func_synth_mono) opt_synth_1to1_8bit_mono(fr); if(fr->af.encoding & MPG123_ENC_8) p8 = 1; fr->synth = funcs[p8][ds]; fr->synth_mono = funcs_mono[fr->af.channels==2 ? 0 : 1][p8][ds]; if(p8) { if(make_conv16to8_table(fr) != 0) { /* it's a bit more work to get proper error propagation up */ return -1; } } return 0;}int mpg123_volume_change(mpg123_handle *mh, double change){ if(mh == NULL) return MPG123_ERR; return mpg123_volume(mh, change + (double) mh->p.outscale / MAXOUTBURST);}int mpg123_volume(mpg123_handle *mh, double vol){ if(mh == NULL) return MPG123_ERR; if(vol >= 0) mh->p.outscale = (double) MAXOUTBURST * vol; do_rva(mh); return MPG123_OK;}static int get_rva(mpg123_handle *fr, double *peak, double *gain){ double p = -1; double g = 0; int ret = 0; if(fr->p.rva) { int rt = 0; /* Should one assume a zero RVA as no RVA? */ if(fr->p.rva == 2 && fr->rva.level[1] != -1) rt = 1; if(fr->rva.level[rt] != -1) { p = fr->rva.peak[rt]; g = fr->rva.gain[rt]; ret = 1; /* Success. */ } } if(peak != NULL) *peak = p; if(gain != NULL) *gain = g; return ret;}/* adjust the volume, taking both fr->outscale and rva values into account */void do_rva(mpg123_handle *fr){ double peak = 0; double gain = 0; scale_t newscale; double rvafact = 1; if(get_rva(fr, &peak, &gain)) { if(NOQUIET && fr->p.verbose > 1) fprintf(stderr, "Note: doing RVA with gain %f\n", gain); rvafact = pow(10,gain/20); } newscale = fr->p.outscale*rvafact; /* if peak is unknown (== 0) this check won't hurt */ if((peak*newscale) > MAXOUTBURST) { newscale = (scale_t) ((double) MAXOUTBURST/peak); warning2("limiting scale value to %li to prevent clipping with indicated peak factor of %f", newscale, peak); } /* first rva setting is forced with fr->lastscale < 0 */ if(newscale != fr->lastscale) { debug3("changing scale value from %li to %li (peak estimated to %li)", fr->lastscale != -1 ? fr->lastscale : fr->p.outscale, newscale, (long) (newscale*peak)); fr->lastscale = newscale; opt_make_decode_tables(fr); /* the actual work */ }}int mpg123_getvolume(mpg123_handle *mh, double *base, double *really, double *rva_db){ if(mh == NULL) return MPG123_ERR; if(base) *base = (double)mh->p.outscale/MAXOUTBURST; if(really) *really = (double)mh->lastscale/MAXOUTBURST; get_rva(mh, NULL, rva_db); return MPG123_OK;}int frame_cpu_opt(mpg123_handle *fr, const char* cpu){ char* chosen = ""; /* the chosed decoder opt as string */ int auto_choose = 0; int done = 0; if( (cpu == NULL) || (cpu[0] == 0) || !strcasecmp(cpu, "auto") ) auto_choose = 1;#ifndef OPT_MULTI { char **sd = mpg123_decoders(); /* this contains _one_ decoder */ if(!auto_choose && strcasecmp(cpu, sd[0])) done = 0; else { chosen = sd[0]; done = 1; } }#else fr->cpu_opts.type = nodec; /* covers any i386+ cpu; they actually differ only in the synth_1to1 function... */ #ifdef OPT_X86 #ifdef OPT_MMXORSSE fr->cpu_opts.make_decode_tables = make_decode_tables; fr->cpu_opts.init_layer3_gainpow2 = init_layer3_gainpow2; fr->cpu_opts.init_layer2_table = init_layer2_table; #endif #ifdef OPT_3DNOW fr->cpu_opts.dct36 = dct36; #endif #ifdef OPT_3DNOWEXT fr->cpu_opts.dct36 = dct36; #endif if(cpu_i586(cpu_flags)) { debug2("standard flags: 0x%08x\textended flags: 0x%08x", cpu_flags.std, cpu_flags.ext); #ifdef OPT_3DNOWEXT if( !done && (auto_choose || !strcasecmp(cpu, "3dnowext")) && cpu_3dnow(cpu_flags) && cpu_3dnowext(cpu_flags) && cpu_mmx(cpu_flags) ) { int go = 1; if(fr->p.force_rate) { #if defined(K6_FALLBACK) || defined(PENTIUM_FALLBACK) if(!auto_choose){ if(NOQUIET) error("I refuse to choose 3DNowExt as this will screw up with forced rate!"); } else if(VERBOSE) fprintf(stderr, "Note: Not choosing 3DNowExt because flexible rate not supported.\n"); go = 0; #else if(NOQUIET) error("You will hear some awful sound because of flexible rate being chosen with 3DNowExt decoder!"); #endif } if(go){ /* temporary hack for flexible rate bug, not going indent this - fix it instead! */ chosen = "3DNowExt"; fr->cpu_opts.type = dreidnowext; fr->cpu_opts.class = mmxsse; fr->cpu_opts.dct36 = dct36_3dnowext; fr->cpu_opts.synth_1to1 = synth_1to1_3dnowext; fr->cpu_opts.dct64 = dct64_mmx; /* only use the 3dnow version in the synth_1to1_sse */ fr->cpu_opts.make_decode_tables = make_decode_tables_mmx; fr->cpu_opts.init_layer3_gainpow2 = init_layer3_gainpow2_mmx; fr->cpu_opts.init_layer2_table = init_layer2_table_mmx; fr->cpu_opts.mpl_dct64 = dct64_3dnowext; done = 1; } } #endif #ifdef OPT_SSE if( !done && (auto_choose || !strcasecmp(cpu, "sse")) && cpu_sse(cpu_flags) && cpu_mmx(cpu_flags) ) { int go = 1; if(fr->p.force_rate) { #ifdef PENTIUM_FALLBACK if(!auto_choose){ if(NOQUIET) error("I refuse to choose SSE as this will screw up with forced rate!"); } else if(VERBOSE) fprintf(stderr, "Note: Not choosing SSE because flexible rate not supported.\n"); go = 0; #else if(NOQUIET) error("You will hear some awful sound because of flexible rate being chosen with SSE decoder!"); #endif } if(go){ /* temporary hack for flexible rate bug, not going indent this - fix it instead! */ chosen = "SSE"; fr->cpu_opts.type = sse; fr->cpu_opts.class = mmxsse; fr->cpu_opts.synth_1to1 = synth_1to1_sse; fr->cpu_opts.dct64 = dct64_mmx; /* only use the sse version in the synth_1to1_sse */ fr->cpu_opts.make_decode_tables = make_decode_tables_mmx; fr->cpu_opts.init_layer3_gainpow2 = init_layer3_gainpow2_mmx; fr->cpu_opts.init_layer2_table = init_layer2_table_mmx; fr->cpu_opts.mpl_dct64 = dct64_sse; done = 1; } } #endif #ifdef OPT_3DNOW fr->cpu_opts.dct36 = dct36; /* TODO: make autodetection for _all_ x86 optimizations (maybe just for i586+ and keep separate 486 build?) */ /* check cpuflags bit 31 (3DNow!) and 23 (MMX) */ if( !done && (auto_choose || !strcasecmp(cpu, "3dnow")) && cpu_3dnow(cpu_flags) && cpu_mmx(cpu_flags) ) { chosen = "3DNow"; fr->cpu_opts.type = dreidnow; fr->cpu_opts.dct36 = dct36_3dnow; /* 3DNow! optimized dct36() */ fr->cpu_opts.synth_1to1 = synth_1to1_3dnow; fr->cpu_opts.dct64 = dct64_i386; /* use the 3dnow one? */ done = 1; } #endif #ifdef OPT_MMX if( !done && (auto_choose || !strcasecmp(cpu, "mmx")) && cpu_mmx(cpu_flags) ) { int go = 1; if(fr->p.force_rate) { #ifdef PENTIUM_FALLBACK if(!auto_choose){ if(NOQUIET) error("I refuse to choose MMX as this will screw up with forced rate!"); } else if(VERBOSE) fprintf(stderr, "Note: Not choosing MMX because flexible rate not supported.\n"); go = 0; #else error("You will hear some awful sound because of flexible rate being chosen with MMX decoder!"); #endif } if(go){ /* temporary hack for flexible rate bug, not going indent this - fix it instead! */ chosen = "MMX"; fr->cpu_opts.type = mmx; fr->cpu_opts.class = mmxsse; fr->cpu_opts.synth_1to1 = synth_1to1_mmx; fr->cpu_opts.dct64 = dct64_mmx; fr->cpu_opts.make_decode_tables = make_decode_tables_mmx; fr->cpu_opts.init_layer3_gainpow2 = init_layer3_gainpow2_mmx; fr->cpu_opts.init_layer2_table = init_layer2_table_mmx; done = 1; } } #endif #ifdef OPT_I586 if(!done && (auto_choose || !strcasecmp(cpu, "i586"))) { chosen = "i586/pentium"; fr->cpu_opts.type = ifuenf; fr->cpu_opts.synth_1to1 = synth_1to1_i586; fr->cpu_opts.synth_1to1_i586_asm = synth_1to1_i586_asm; fr->cpu_opts.dct64 = dct64_i386; done = 1; } #endif #ifdef OPT_I586_DITHER if(!done && (auto_choose || !strcasecmp(cpu, "i586_dither"))) { chosen = "dithered i586/pentium"; fr->cpu_opts.type = ifuenf_dither; fr->cpu_opts.synth_1to1 = synth_1to1_i586; fr->cpu_opts.dct64 = dct64_i386; fr->cpu_opts.synth_1to1_i586_asm = synth_1to1_i586_asm_dither; done = 1; } #endif } #ifdef OPT_I486 /* that won't cooperate nicely in multi opt mode - forcing i486 in layer3.c */ if(!done && (auto_choose || !strcasecmp(cpu, "i486"))) { chosen = "i486"; fr->cpu_opts.type = ivier; fr->cpu_opts.synth_1to1 = synth_1to1_i386; /* i486 function is special */ fr->cpu_opts.dct64 = dct64_i386; done = 1; } #endif #ifdef OPT_I386 if(!done && (auto_choose || !strcasecmp(cpu, "i386"))) { chosen = "i386"; fr->cpu_opts.type = idrei; fr->cpu_opts.synth_1to1 = synth_1to1_i386; fr->cpu_opts.dct64 = dct64_i386; done = 1; } #endif if(done) /* set common x86 functions */ { fr->cpu_opts.synth_1to1_mono = synth_1to1_mono_i386; fr->cpu_opts.synth_1to1_mono2stereo = synth_1to1_mono2stereo_i386; fr->cpu_opts.synth_1to1_8bit = synth_1to1_8bit_i386; fr->cpu_opts.synth_1to1_8bit_mono = synth_1to1_8bit_mono_i386; fr->cpu_opts.synth_1to1_8bit_mono2stereo = synth_1to1_8bit_mono2stereo_i386; } #endif /* OPT_X86 */ #ifdef OPT_ALTIVEC if(!done && (auto_choose || !strcasecmp(cpu, "altivec"))) { chosen = "AltiVec"; fr->cpu_opts.type = altivec; fr->cpu_opts.dct64 = dct64_altivec; fr->cpu_opts.synth_1to1 = synth_1to1_altivec; fr->cpu_opts.synth_1to1_mono = synth_1to1_mono_altivec; fr->cpu_opts.synth_1to1_mono2stereo = synth_1to1_mono2stereo_altivec; fr->cpu_opts.synth_1to1_8bit = synth_1to1_8bit_altivec; fr->cpu_opts.synth_1to1_8bit_mono = synth_1to1_8bit_mono_altivec; fr->cpu_opts.synth_1to1_8bit_mono2stereo = synth_1to1_8bit_mono2stereo_altivec; done = 1; } #endif #ifdef OPT_GENERIC if(!done && (auto_choose || !strcasecmp(cpu, "generic"))) { chosen = "generic"; fr->cpu_opts.type = generic; fr->cpu_opts.dct64 = dct64; fr->cpu_opts.synth_1to1 = synth_1to1; fr->cpu_opts.synth_1to1_mono = synth_1to1_mono; fr->cpu_opts.synth_1to1_mono2stereo = synth_1to1_mono2stereo; fr->cpu_opts.synth_1to1_8bit = synth_1to1_8bit; fr->cpu_opts.synth_1to1_8bit_mono = synth_1to1_8bit_mono; fr->cpu_opts.synth_1to1_8bit_mono2stereo = synth_1to1_8bit_mono2stereo; done = 1; } #endif#endif if(done) { if(VERBOSE) fprintf(stderr, "Decoder: %s\n", chosen); return 1; } else { if(NOQUIET) error("Could not set optimization!"); return 0; }}enum optdec dectype(const char* decoder){ if(decoder == NULL) return autodec; if(!strcasecmp(decoder, "3dnowext")) return dreidnowext; if(!strcasecmp(decoder, "3dnow")) return dreidnow; if(!strcasecmp(decoder, "sse")) return sse; if(!strcasecmp(decoder, "mmx")) return mmx; if(!strcasecmp(decoder, "generic")) return generic; if(!strcasecmp(decoder, "altivec")) return altivec; if(!strcasecmp(decoder, "i386")) return idrei; if(!strcasecmp(decoder, "i486")) return ivier; if(!strcasecmp(decoder, "i586")) return ifuenf; if(!strcasecmp(decoder, "i586_dither")) return ifuenf_dither; return nodec;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -