ref: 0e1b2b1c2c5854d690112f4f3de3d92d8bfb9d1f
dir: /frontend/main.c/
/*
** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
** Any non-GPL usage of this software or parts of this software is strictly
** forbidden.
**
** The "appropriate copyright message" mentioned in section 2c of the GPLv2
** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com"
**
** Commercial non-GPL licensing of this software is possible.
** For more info contact Nero AG through Mpeg4AAClicense@nero.com.
**
** $Id: main.c,v 1.89 2015/01/19 09:46:12 knik Exp $
**/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <neaacdec.h>
#define min(a,b) ((a)<=(b)?(a):(b))
#define MAX_CHANNELS 6 /* make this higher to support files with more channels */
/* FAAD file buffering routines */
typedef struct {
long bytes_into_buffer;
long bytes_consumed;
long file_offset;
unsigned char *buffer;
int at_eof;
}aac_buffer;
static Biobuf stdin, stdout;
static int
fill_buffer(aac_buffer *b)
{
int bread;
if(b->bytes_consumed > 0){
if(b->bytes_into_buffer)
memmove(b->buffer, b->buffer + b->bytes_consumed, b->bytes_into_buffer);
if(!b->at_eof){
bread = Bread(&stdin, (void*)(b->buffer + b->bytes_into_buffer), b->bytes_consumed);
if(bread != b->bytes_consumed)
b->at_eof = 1;
b->bytes_into_buffer += bread;
}
b->bytes_consumed = 0;
if(b->bytes_into_buffer > 3 && memcmp(b->buffer, "TAG", 3) == 0)
b->bytes_into_buffer = 0;
if(b->bytes_into_buffer > 11 && memcmp(b->buffer, "LYRICSBEGIN", 11) == 0)
b->bytes_into_buffer = 0;
if(b->bytes_into_buffer > 8 && memcmp(b->buffer, "APETAGEX", 8) == 0)
b->bytes_into_buffer = 0;
}
return 1;
}
static void
advance_buffer(aac_buffer *b, int bytes)
{
while(b->bytes_into_buffer > 0 && bytes > 0){
int chunk = min(bytes, b->bytes_into_buffer);
bytes -= chunk;
b->file_offset += chunk;
b->bytes_consumed = chunk;
b->bytes_into_buffer -= chunk;
if(b->bytes_into_buffer == 0)
fill_buffer(b);
}
}
static int
decode(void)
{
NeAACDecHandle hDecoder;
NeAACDecFrameInfo frameInfo;
NeAACDecConfigurationPtr config;
unsigned long samplerate;
unsigned char channels;
void *sample_buffer;
int bread;
aac_buffer b;
memset(&b, 0, sizeof(b));
if((b.buffer = malloc(FAAD_MIN_STREAMSIZE*MAX_CHANNELS)) == nil)
return -1;
memset(b.buffer, 0, FAAD_MIN_STREAMSIZE*MAX_CHANNELS);
bread = Bread(&stdin, b.buffer, FAAD_MIN_STREAMSIZE*MAX_CHANNELS);
b.bytes_into_buffer = bread;
b.bytes_consumed = 0;
b.file_offset = 0;
if(bread != FAAD_MIN_STREAMSIZE*MAX_CHANNELS)
b.at_eof = 1;
hDecoder = NeAACDecOpen();
config = NeAACDecGetCurrentConfiguration(hDecoder);
config->defSampleRate = 44100;
config->defObjectType = LC;
config->outputFormat = FAAD_FMT_16BIT;
config->downMatrix = 0;
config->useOldADTSFormat = 0;
NeAACDecSetConfiguration(hDecoder, config);
fill_buffer(&b);
if((bread = NeAACDecInit(hDecoder, b.buffer, b.bytes_into_buffer, &samplerate, &channels)) < 0){
sysfatal("NeAACDecInit failed: %d", bread);
if(b.buffer)
free(b.buffer);
NeAACDecClose(hDecoder);
return -1;
}
advance_buffer(&b, bread);
fill_buffer(&b);
if(samplerate != 44100 || channels != 2){
int pfd[2], pid;
char fmt[32];
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%ld", channels, samplerate);
execl("/bin/audio/pcmconv", "pcmconv", "-i", fmt, nil);
sysfatal("%r");
}
close(pfd[1]);
Binit(&stdout, pfd[0], OWRITE);
}
for(;;){
sample_buffer = NeAACDecDecode(hDecoder, &frameInfo, b.buffer, b.bytes_into_buffer);
/* update buffer indices */
advance_buffer(&b, frameInfo.bytesconsumed);
if(frameInfo.error != 0)
sysfatal("%s: %d", NeAACDecGetErrorMessage(frameInfo.error), frameInfo.error);
if(frameInfo.samples > 0 && Bwrite(&stdout, sample_buffer, frameInfo.samples*2) != frameInfo.samples*2)
break;
fill_buffer(&b);
if(b.bytes_into_buffer == 0)
break;
}
NeAACDecClose(hDecoder);
if(b.buffer)
free(b.buffer);
return frameInfo.error;
}
static void
usage(void)
{
print("usage: %s [-i] [options]\n", argv0);
return;
}
void
main(int argc, char **argv)
{
USED(argc); USED(argv);
Binit(&stdin, 0, OREAD);
Binit(&stdout, 1, OWRITE);
exits(decode() == 0 ? nil : "failed");
}