shithub: aacenc

ref: fdff41e7018a893b62e37214199e58972228650c
dir: /frontend/aacenc.c/

View raw version
/*
 * FAAC - Freeware Advanced Audio Coder
 * Copyright (C) 2001 Menno Bakker
 * Copyright (C) 2002-2017 Krzysztof Nikiel
 * Copyright (C) 2004 Dan Villiom P. Christiansen
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <faac.h>

static Biobuf out;

static int
done(void*, char*)
{
	Bflush(&out);
	return 0;
}

static void
usage(void)
{
	fprint(2, "usage: %s [-b] [-c CHAN] [-q QUANT] [-r RATE] [-t low|main|ltp] [-B BITRATE]\n", argv0);
	exits("usage");
}

void
main(int argc, char **argv)
{
	int nch, srate, type, brate, sz, n, r, q, i, nobuffer;
	ulong insamples, outsz, insz;
	faacEncConfigurationPtr fmt;
	u8int *obuf, ph[7+1+4+8];
	faacEncHandle e;
	s16int *pcm;
	Biobuf in;
	uvlong ns;
	char *s;

	nobuffer = 0;
	brate = 0;
	srate = 44100;
	nch = 2;
	type = LOW;
	q = 0;
	ARGBEGIN{
	case 'b':
		nobuffer = 1;
		break;
	case 'B':
		if((brate = atoi(EARGF(usage()))) < 0)
			sysfatal("invalid bitrate %d", brate);
		break;
	case 'c':
		if((nch = atoi(EARGF(usage()))) < 1 || nch > 64)
			sysfatal("invalid number of channels %d", nch);
		break;
	case 'r':
		if((srate = atoi(EARGF(usage()))) < 1)
			sysfatal("invalid samplerate %d", srate);
		break;
	case 'q':
		if((q = atoi(EARGF(usage()))) < 1)
			sysfatal("invalid quantization quality %d", q);
		break;
	case 't':
		s = EARGF(usage());
		if(cistrcmp(s, "low") == 0)
			type = LOW;
		else if(cistrcmp(s, "main") == 0)
			type = MAIN;
		else if(cistrcmp(s, "ltp") == 0)
			type = LTP;
		else
			sysfatal("invalid type %s", s);
		break;
	default:
		usage();
	}ARGEND

	if(argc != 0)
		usage();
	if(Binit(&in, 0, OREAD) != 0 || Binit(&out, 1, OWRITE) != 0)
		sysfatal("io init failed");

	setfcr(getfcr() & ~(FPINVAL|FPOVFL));

	if((e = faacEncOpen(srate, nch, &insamples, &outsz)) == nil)
		sysfatal("faacEncOpen");
	insz = insamples * sizeof(*pcm);
	if((pcm = malloc(insz)) == nil)
		sysfatal("memory");
	if((obuf = malloc(outsz)) == nil)
		sysfatal("memory");

	fmt = faacEncGetCurrentConfiguration(e);
	fmt->inputFormat = FAAC_INPUT_16BIT;
	fmt->mpegVersion = MPEG2;
	fmt->outputFormat = ADTS_STREAM;
	fmt->aacObjectType = type;
	if(brate > 0)
		fmt->bitRate = brate / nch;
	if(q > 0)
		fmt->quantqual = q;
	if(!faacEncSetConfiguration(e, fmt))
		sysfatal("invalid encoder configuration");

	atnotify(done, 1);

	ns = nsec();
	for(;;){
		for(n = 0; n == 0 || (n & (sizeof(*pcm)-1)) != 0; n += r){
			if((r = Bread(&in, pcm+n, insz-n)) < 0)
				sysfatal("read: %r");
			if(r == 0)
				break;
		}
		if(n == 0)
			break;
		if((sz = faacEncEncode(e, pcm, n/sizeof(*pcm), obuf, outsz)) < 0)
			sysfatal("faacEncEncode");
		else if(sz == 0)
			continue;

		if(ns != 0){
			memmove(ph, obuf, 7);
			/* set frame size */
			ph[3] &= ~3;
			ph[4] = sizeof(ph)>>3;
			ph[5] = (ph[5]&~0xe0) | sizeof(ph)<<5;
			ph[7] = 0x04; /* DSE */
			ph[8] = 'n';
			ph[9] = 's';
			ph[10] = 'e';
			ph[11] = 'c';
			for(i = 0; i < 8; i++, ns >>= 8)
				ph[12+i] = ns;
			ns = 0;
			if(Bwrite(&out, ph, sizeof(ph)) < 0)
				break;
			Bflush(&out);
		}
		if(Bwrite(&out, obuf, sz) < 0)
			break;
		if(nobuffer)
			Bflush(&out);
	}
	Bflush(&out);

	exits(nil);
}