ref: bbc7f161baf39a034cf02ae841e3ce72939e82ce
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\n", argv0); exits("usage"); } void main(int argc, char **argv) { int n; ARGBEGIN{ default: usage(); }ARGEND Binit(&stdin, 0, OREAD); Binit(&stdout, 1, OWRITE); n = decode(); Bterm(&stdout); waitpid(); exits(n == 0 ? nil : "failed"); }