ref: 167170d01b188e5a6b59cf2e2fb20177417c0d50
dir: aacenc/frontend/aacenc.c
/* * 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> enum { Taudio = 0xc0, Tvideo = 0xe0, }; static int peswrite(Biobuf *o, uvlong ns, int type, u8int *data, int sz) { u8int p[] = { 0x00, 0x00, 0x01, /* start code */ type, /* stream id 0 */ 0, 0, /* packet length */ 0x00, /* a bunch of nothing */ 0x80, /* PTS included */ 5, /* PTS is 5 bytes */ 0, 0, 0, 0, 0, /* PTS value */ 0, 0, 0, 0, 0, /* DTS value */ }; int plen, psz, dsz; uvlong pts; pts = ns / 99999ULL; p[9] = 1<<5 | (pts>>30)<<1 | 1; p[10] = pts>>22; p[11] = pts>>14 | 1; p[12] = pts>>7; p[13] = pts<<1 | 1; psz = sizeof(p)-5; if((type & 0xf0) == Tvideo){ psz += 5; p[7] |= 0x40; /* DTS is included */ p[8] += 5; memmove(p+14, p+9, 5); } for(; sz > 0; sz -= dsz, data += dsz){ dsz = 0xffff - (psz-6); /* maximum */ dsz = sz <= dsz ? sz : dsz; plen = psz-6 + dsz; p[4] = plen >> 8; p[5] = plen; if(Bwrite(o, p, psz) < 0 || Bwrite(o, data, dsz) < 0) return -1; } return 0; } static void usage(void) { fprint(2, "usage: %s [-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, pes, frsz; ulong insamples, outsz, insz; faacEncConfigurationPtr fmt; uvlong mul, div, nfr; faacEncHandle e; s16int *pcm; u8int *obuf; Biobuf out; Biobuf in; char *s; brate = 0; srate = 44100; nch = 2; type = LOW; pes = 0; q = 0; ARGBEGIN{ 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 'p': pes = 1; 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"); for(mul = 1000000000ULL, div = srate;;){ if((mul % 10) == 0 && (div % 10) == 0){ mul /= 10; div /= 10; }else break; } 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"); frsz = insamples / nch; for(nfr = 0;;){ for(n = 0; n == 0 || (n & (sizeof(*pcm)-1)) != 0; n += r){ if((r = Bread(&in, pcm+n, insz-n)) <= 0) break; } if(n == 0) break; if((sz = faacEncEncode(e, pcm, n/sizeof(*pcm), obuf, outsz)) < 0) sysfatal("faacEncEncode"); if(pes){ if(peswrite(&out, nfr*mul/div, Taudio, obuf, sz) < 0) break; n = n / sizeof(*pcm) / nch; nfr += n < frsz ? frsz : 0; }else if(Bwrite(&out, obuf, sz) < 0) break; } Bflush(&out); exits(nil); }