ref: bc540e422eb7492a5c506e9bd4fd747facbc8225
dir: /mp3dec.c/
#include <u.h> #include <libc.h> #include <bio.h> #define MINIMP3_IMPLEMENTATION #define MINIMP3_NO_STDIO #include "minimp3_ex.h" static int noseek, startsz; static uvlong curpos; static Biobuf in; static uchar inb[MINIMP3_BUF_SIZE]; static uchar start[2*MINIMP3_BUF_SIZE]; static size_t readcb(void *buf, size_t size, void *) { int n; if(noseek && curpos < startsz){ n = startsz - curpos; n = size < n ? size : n; memmove(buf, start+curpos, n); curpos += n; }else{ n = Bread(&in, buf, size); } return n > 0 ? n : 0; } static int seekcb(uint64_t position, void *) { if(noseek && curpos <= startsz) curpos = position; else curpos = Bseek(&in, position, 0); return 0; } static void usage(void) { fprint(2, "usage: %s [ -s SECONDS ]\n", argv0); exits("usage"); } static mp3dec_ex_t dec; static mp3dec_io_t io = { .read = readcb, .seek = seekcb, }; static mp3d_sample_t buf[2*4410]; void main(int argc, char **argv) { size_t n; double seekto; int out, pfd[2], pid; char fmt[32]; seekto = 0.0; ARGBEGIN{ case 's': seekto = atof(EARGF(usage())); break; default: usage(); }ARGEND if(Binits(&in, 0, OREAD, inb, sizeof(inb)) != 0) sysfatal("Binits"); noseek = Bseek(&in, 0, 2) < 0; if(!noseek) Bseek(&in, 0, 0); else startsz = Bread(&in, start, sizeof(start)); if(mp3dec_ex_open_cb(&dec, &io, MP3D_SEEK_TO_SAMPLE|MP3D_DO_NOT_SCAN) != 0) sysfatal("mp3dec_ex_open_cb"); if(seekto != 0.0) fprint(2, "time: %g\n", (noseek || mp3dec_ex_seek(&dec, seekto*dec.info.channels*dec.info.hz) != 0) ? 0.0 : seekto); out = 1; if(dec.info.channels != 2 || dec.info.hz != 44100){ pid = -1; if(pipe(pfd) < 0 || (pid = fork()) < 0) sysfatal("%r"); if(pid == 0){ dup(pfd[1], 0); close(pfd[1]); close(pfd[0]); snprint(fmt, sizeof(fmt), "s16c%dr%d", dec.info.channels, dec.info.hz); execl("/bin/audio/pcmconv", "pcmconv", "-i", fmt, nil); sysfatal("%r"); } close(1); close(pfd[1]); out = pfd[0]; } while((n = mp3dec_ex_read(&dec, buf, nelem(buf))) > 0) write(out, buf, n*sizeof(buf[0])); Bterm(&in); close(out); mp3dec_ex_close(&dec); exits(nil); }