Blame src/mpg123-strip.c

Packit c32a2d
/*
Packit c32a2d
	extract_frams: utlize the framebyframe API and mpg123_framedata to extract the MPEG frames out of a stream (strip off anything else).
Packit c32a2d
Packit c32a2d
	copyright 2011-2013 by the mpg123 project - free software under the terms of the LGPL 2.1
Packit c32a2d
	see COPYING and AUTHORS files in distribution or http://mpg123.org
Packit c32a2d
	initially written by Thomas Orgis
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
#include "config.h"
Packit c32a2d
#include "compat.h"
Packit c32a2d
#include <mpg123.h>
Packit c32a2d
Packit c32a2d
#include "getlopt.h"
Packit c32a2d
Packit c32a2d
Packit c32a2d
static struct
Packit c32a2d
{
Packit c32a2d
	int info;
Packit c32a2d
	long icy_interval;
Packit c32a2d
	int verbose;
Packit c32a2d
} param =
Packit c32a2d
{
Packit c32a2d
	 TRUE
Packit c32a2d
	,0
Packit c32a2d
	,0
Packit c32a2d
};
Packit c32a2d
Packit c32a2d
static const char* progname;
Packit c32a2d
Packit c32a2d
static void usage(int err)
Packit c32a2d
{
Packit c32a2d
	FILE* o = stdout;
Packit c32a2d
	if(err)
Packit c32a2d
	{
Packit c32a2d
		o = stderr; 
Packit c32a2d
		fprintf(o, "You made some mistake in program usage... let me briefly remind you:\n\n");
Packit c32a2d
	}
Packit c32a2d
	fprintf(o, "Extract only MPEG frames from a stream using libmpg123 (stdin to stdout)\n");
Packit c32a2d
	fprintf(o, "\tversion %s; written and copyright by Thomas Orgis and the mpg123 project\n", PACKAGE_VERSION);
Packit c32a2d
	fprintf(o,"\nusage: %s [option(s)] < input > output\n", progname);
Packit c32a2d
	fprintf(o,"\noptions:\n");
Packit c32a2d
	fprintf(o," -h     --help              give usage help\n");
Packit c32a2d
	fprintf(o," -i <n> --icy-interval <n>  stream has ICY metadata present with this interval\n");
Packit c32a2d
	fprintf(o," -n     --no-info           also strip info frame at beginning\n");
Packit c32a2d
	fprintf(o," -v[*]  --verbose           increase verbosity level\n");
Packit c32a2d
	exit(err);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void want_usage(char* bla)
Packit c32a2d
{
Packit c32a2d
	usage(0);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void set_verbose (char *arg)
Packit c32a2d
{
Packit c32a2d
    param.verbose++;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static topt opts[] =
Packit c32a2d
{
Packit c32a2d
	 {'h', "help", 0, want_usage, 0, 0}
Packit c32a2d
	,{'i', "icy-interval", GLO_ARG|GLO_LONG, 0, &param.icy_interval, 0}
Packit c32a2d
	,{'n', "no-info", GLO_INT, 0, &param.info, FALSE}
Packit c32a2d
	,{'v', "verbose", 0, set_verbose, 0, 0}
Packit c32a2d
	,{0, 0, 0, 0, 0, 0}
Packit c32a2d
};
Packit c32a2d
Packit c32a2d
int do_work(mpg123_handle *m);
Packit c32a2d
Packit c32a2d
int main(int argc, char **argv)
Packit c32a2d
{
Packit c32a2d
	int ret = 0;
Packit c32a2d
	mpg123_handle *m;
Packit c32a2d
Packit c32a2d
	progname = argv[0];
Packit c32a2d
Packit c32a2d
	while ((ret = getlopt(argc, argv, opts)))
Packit c32a2d
	switch (ret) {
Packit c32a2d
		case GLO_UNKNOWN:
Packit c32a2d
			fprintf (stderr, "%s: Unknown option \"%s\".\n", 
Packit c32a2d
				progname, loptarg);
Packit c32a2d
			usage(1);
Packit c32a2d
		case GLO_NOARG:
Packit c32a2d
			fprintf (stderr, "%s: Missing argument for option \"%s\".\n",
Packit c32a2d
				progname, loptarg);
Packit c32a2d
			usage(1);
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	mpg123_init();
Packit c32a2d
	m = mpg123_new(NULL, &ret;;
Packit c32a2d
Packit c32a2d
	if(m == NULL)
Packit c32a2d
	{
Packit c32a2d
		fprintf(stderr, "Cannot create handle: %s", mpg123_plain_strerror(ret));
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		ret = mpg123_param(m, MPG123_VERBOSE, param.verbose, 0.);
Packit c32a2d
		if(ret == MPG123_OK)
Packit c32a2d
		{
Packit c32a2d
			if(param.verbose)
Packit c32a2d
			fprintf(stderr, "Info frame handling: %s\n",
Packit c32a2d
				param.info ? "pass-through" : "remove");
Packit c32a2d
			ret = param.info /* If info frame is ignored, it is treated as MPEG data. */
Packit c32a2d
				? mpg123_param(m, MPG123_ADD_FLAGS, MPG123_IGNORE_INFOFRAME, 0.)
Packit c32a2d
				: mpg123_param(m, MPG123_REMOVE_FLAGS, MPG123_IGNORE_INFOFRAME, 0.);
Packit c32a2d
		}
Packit c32a2d
		if(ret == MPG123_OK && param.icy_interval > 0)
Packit c32a2d
		{
Packit c32a2d
			if(param.verbose) fprintf(stderr, "ICY interval: %li\n", param.icy_interval);
Packit c32a2d
			ret = mpg123_param(m, MPG123_ICY_INTERVAL, param.icy_interval, 0);
Packit c32a2d
		}
Packit c32a2d
Packit c32a2d
		if(ret == MPG123_OK) ret = do_work(m);
Packit c32a2d
Packit c32a2d
		if(ret != MPG123_OK) fprintf(stderr, "Some error occured: %s\n", mpg123_strerror(m));
Packit c32a2d
Packit c32a2d
		mpg123_delete(m); /* Closes, too. */
Packit c32a2d
	}
Packit c32a2d
	mpg123_exit();
Packit c32a2d
Packit c32a2d
	return ret;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int do_work(mpg123_handle *m)
Packit c32a2d
{
Packit c32a2d
	int ret;
Packit c32a2d
	size_t count = 0;
Packit c32a2d
	ret = mpg123_open_fd(m, STDIN_FILENO);
Packit c32a2d
	if(ret != MPG123_OK) return ret;
Packit c32a2d
Packit c32a2d
	while( (ret = mpg123_framebyframe_next(m)) == MPG123_OK || ret == MPG123_NEW_FORMAT )
Packit c32a2d
	{
Packit c32a2d
		unsigned long header;
Packit c32a2d
		unsigned char *bodydata;
Packit c32a2d
		size_t bodybytes;
Packit c32a2d
		if(mpg123_framedata(m, &header, &bodydata, &bodybytes) == MPG123_OK)
Packit c32a2d
		{
Packit c32a2d
			/* Need to extract the 4 header bytes from the native storage in the correct order. */
Packit c32a2d
			unsigned char hbuf[4];
Packit c32a2d
			int i;
Packit c32a2d
			for(i=0; i<4; ++i) hbuf[i] = (unsigned char) ((header >> ((3-i)*8)) & 0xff);
Packit c32a2d
Packit c32a2d
			/* Now write out both header and data, fire and forget. */
Packit c32a2d
			write(STDOUT_FILENO, hbuf, 4);
Packit c32a2d
			write(STDOUT_FILENO, bodydata, bodybytes);
Packit c32a2d
			if(param.verbose)
Packit c32a2d
			fprintf(stderr, "%"SIZE_P": header 0x%08lx, %"SIZE_P" body bytes\n"
Packit c32a2d
			, (size_p)++count, header, (size_p)bodybytes);
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	if(ret != MPG123_DONE)
Packit c32a2d
	fprintf(stderr, "Some error occured (non-fatal?): %s\n", mpg123_strerror(m));
Packit c32a2d
Packit c32a2d
	if(param.verbose) fprintf(stderr, "Done with %"SIZE_P" MPEG frames.\n"
Packit c32a2d
	, (size_p)count);
Packit c32a2d
Packit c32a2d
	return MPG123_OK;
Packit c32a2d
}