/* mpg123_to_wav.c copyright 2007-2016 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 Nicholas Humfrey The most complicated part is about the choices to make about output format, and prepare for the unlikely case a bastard mp3 might file change it. */ #include #include #include #include void usage(const char *cmd) { printf("Usage: %s [ [ [encoding [buffersize]]]]\n" , cmd); printf( "\nPlay MPEG audio from intput file to output file/device using\n" "specified out123 driver, sample encoding and buffer size optional.\n\n" ); exit(99); } void cleanup(mpg123_handle *mh, out123_handle *ao) { out123_del(ao); /* It's really to late for error checks here;-) */ mpg123_close(mh); mpg123_delete(mh); mpg123_exit(); } int main(int argc, char *argv[]) { mpg123_handle *mh = NULL; out123_handle *ao = NULL; char *infile = NULL; char *driver = NULL; char *outfile = NULL; unsigned char* buffer = NULL; const char *encname; size_t buffer_size = 0; size_t done = 0; int channels = 0; int encoding = 0; int framesize = 1; long rate = 0; int err = MPG123_OK; off_t samples = 0; if(argc<2) usage(argv[0]); infile = argv[1]; if(argc >= 3) driver = argv[2]; if(argc >= 4) outfile = argv[3]; printf("Input file: %s\n", infile); printf("Output driver: %s\n", driver ? driver : " (default)"); printf("Output file: %s\n", outfile ? outfile : " (default)"); err = mpg123_init(); if(err != MPG123_OK || (mh = mpg123_new(NULL, &err)) == NULL) { fprintf(stderr, "Basic setup goes wrong: %s", mpg123_plain_strerror(err)); cleanup(mh, ao); return -1; } ao = out123_new(); if(!ao) { fprintf(stderr, "Cannot create output handle.\n"); cleanup(mh, ao); return -1; } if(argc >= 5) { /* Make mpg123 support the desired encoding only for all rates. */ const long *rates; size_t rate_count; size_t i; int enc; /* If that is zero, you'll get the error soon enough from mpg123. */ enc = out123_enc_byname(argv[4]); mpg123_format_none(mh); mpg123_rates(&rates, &rate_count); for(i=0; i (default)"); printf("Effective output file: %s\n", outfile ? outfile : " (default)"); /* Ensure that this output format will not change (it might, when we allow it). */ mpg123_format_none(mh); mpg123_format(mh, rate, channels, encoding); encname = out123_enc_name(encoding); printf( "Playing with %i channels and %li Hz, encoding %s.\n" , channels, rate, encname ? encname : "???" ); if( out123_start(ao, rate, channels, encoding) || out123_getformat(ao, NULL, NULL, NULL, &framesize) ) { fprintf(stderr, "Cannot start output / get framesize: %s\n" , out123_strerror(ao)); cleanup(mh, ao); return -1; } /* Buffer could be almost any size here, mpg123_outblock() is just some recommendation. The size should be a multiple of the PCM frame size. */ buffer_size = argc >= 6 ? atol(argv[5]) : mpg123_outblock(mh); buffer = malloc( buffer_size ); do { size_t played; err = mpg123_read( mh, buffer, buffer_size, &done ); played = out123_play(ao, buffer, done); if(played != done) { fprintf(stderr , "Warning: written less than gotten from libmpg123: %li != %li\n" , (long)played, (long)done); } samples += played/framesize; /* We are not in feeder mode, so MPG123_OK, MPG123_ERR and MPG123_NEW_FORMAT are the only possibilities. We do not handle a new format, MPG123_DONE is the end... so abort on anything not MPG123_OK. */ } while (done && err==MPG123_OK); free(buffer); if(err != MPG123_DONE) fprintf( stderr, "Warning: Decoding ended prematurely because: %s\n", err == MPG123_ERR ? mpg123_strerror(mh) : mpg123_plain_strerror(err) ); printf("%li samples written.\n", (long)samples); cleanup(mh, ao); return 0; }