shithub: aacenc

ref: 29dead338461d0883d734fc6e8e8f83d22510e43
dir: /frontend/main.c/

View raw version
/*
 * FAAC - Freeware Advanced Audio Coder
 * Copyright (C) 2001 Menno Bakker
 *
 * 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
 *
 * $Id: main.c,v 1.29 2002/11/23 17:34:59 knik Exp $
 */

#ifdef _WIN32
#include <windows.h>
#endif

#ifdef __unix__
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>

#ifdef HAVE_GETOPT_H
# include <getopt.h>
#else
# include "getopt.h"
# include "getopt.c"
#endif

#include <faac.h>

#include "input.h"

#ifndef min
#define min(a,b) ( (a) < (b) ? (a) : (b) )
#endif

/* globals */
char* progName;

int StringCompI(char const *str1, char const *str2, unsigned long len)
{
    signed int c1 = 0, c2 = 0;

    while (len--) {
        c1 = tolower(*str1++);
        c2 = tolower(*str2++);

        if (c1 == 0 || c1 != c2)
            break;
    }

    return c1 - c2;
}

int main(int argc, char *argv[])
{
    int frames, currentFrame;
    faacEncHandle hEncoder;
    pcmfile_t *infile;

    unsigned int sr, chan;
    unsigned long samplesInput, maxBytesOutput;

    faacEncConfigurationPtr myFormat;
    unsigned int mpegVersion = MPEG2;
    unsigned int objectType = LOW;
    unsigned int useMidSide = 1;
    unsigned int useTns = 0;
    unsigned int useAdts = 1;
    int cutOff = -1;
    unsigned long bitRate = 0;
    int psymodelidx = -1;
    const double bwbrfac = 1.3;
    const int bwdefault = 16000;

    char *audioFileName;
    char *aacFileName;

    short *pcmbuf;

    unsigned char *bitbuf;
    int bytesInput = 0;

    FILE *outfile;

    fprintf(stderr, "FAAC version " FAACENC_VERSION " (" __DATE__ ")\n");

    /* begin process command line */
    progName = argv[0];
    while (1) {
        int c = -1;
        int option_index = 0;
        static struct option long_options[] = {
            { "mpeg", 0, 0, 'm' },
            { "objecttype", 0, 0, 'o' },
            { "raw", 0, 0, 'r' },
            { "nomidside", 0, 0, 'n' },
            { "usetns", 0, 0, 't' },
            { "cutoff", 1, 0, 'c' },
            { "bitrate", 1, 0, 'b' }
        };

	c = getopt_long(argc, argv, "m:o:rntc:b:p:",
            long_options, &option_index);

        if (c == -1)
            break;

        switch (c) {
        case 'm': {
            unsigned int i;
            if (optarg) {
                if (sscanf(optarg, "%u", &i) < 1) {
                    mpegVersion = MPEG2;
                } else {
                    if (i == 2)
                        mpegVersion = MPEG2;
                    else
                        mpegVersion = MPEG4;
                }
            } else {
                mpegVersion = MPEG2;
            }
            break;
        }
        case 'o': {
            unsigned char i[10];
            if (optarg) {
                if (sscanf(optarg, "%s", i) < 1) {
                    objectType = LOW;
                } else {
                    if (StringCompI(i, "MAIN", 4) == 0)
                        objectType = MAIN;
                    else if (StringCompI(i, "LTP", 3) == 0)
                        objectType = LTP;
                    else
                        objectType = LOW;
                }
            } else {
                objectType = LOW;
            }
            break;
        }
        case 'r': {
            useAdts = 0;
            break;
        }
        case 'n': {
            useMidSide = 0;
            break;
        }
        case 't': {
            useTns = 1;
            break;
        }
        case 'c': {
            unsigned int i;
	    if (sscanf(optarg, "%u", &i) > 0) {
                cutOff = i;
            }
            break;
        }
	case 'b':
	  {
            unsigned int i;
	    if (sscanf(optarg, "%u", &i) > 0)
	    {
	      if (i > 0 && i < 1000)
		bitRate = i * 1000;
            }
            break;
        }
	case 'p':
	  {
	    unsigned int i;
	    if (sscanf(optarg, "%u", &i) > 0)
	      psymodelidx = i;
	  break;
	  }
        case '?':
            break;
        default:
            fprintf(stderr, "%s: unknown option specified, ignoring: %c\n",
                progName, c);
        }
    }

    /* check that we have at least two non-option arguments */
    if ((argc - optind) < 2)
    {
      int i;

      // get available psymodels
      hEncoder = faacEncOpen(44100, 2, &samplesInput, &maxBytesOutput);
      myFormat = faacEncGetCurrentConfiguration(hEncoder);

        fprintf(stderr, "\nUsage: %s -options infile outfile\n", progName);
        fprintf(stderr, "Options:\n");
        fprintf(stderr, "  -m X   AAC MPEG version, X can be 2 or 4.\n");
        fprintf(stderr, "  -o X   AAC object type, X can be LC, MAIN or LTP.\n");
	for (i = 0; myFormat->psymodellist[i].ptr; i++)
	{
	  fprintf(stderr, "  -p %d   Use %s.%s\n", i,
		  myFormat->psymodellist[i].name,
		  (i == myFormat->psymodelidx) ? " (default)" : "");
	}
        fprintf(stderr, "  -n     Don\'t use mid/side coding.\n");
        fprintf(stderr, "  -r     RAW AAC output file.\n");
        fprintf(stderr, "  -t     Use TNS coding.\n");
    fprintf(stderr,
	    "  -c X   Set the bandwidth, X in Hz. (default=automatic)\n");
    fprintf(stderr, "  -b X   Set the bitrate per channel, X in kbps."
	    " (default is auto)\n\n");

    faacEncClose(hEncoder);

        return 1;
    }

    /* point to the specified file names */
    audioFileName = argv[optind++];
    aacFileName = argv[optind++];

    /* open the audio input file */
    infile = wav_open_read(audioFileName);
    if (infile == NULL)
    {
        fprintf(stderr, "Couldn't open input file %s\n", audioFileName);
        return 1;
    }

    /* open the aac output file */
    outfile = fopen(aacFileName, "wb");
    if (!outfile)
    {
        fprintf(stderr, "Couldn't create output file %s\n", aacFileName);
        return 1;
    }

    /* determine input file parameters */
    sr = infile->samplerate;
    chan = infile->channels;

    /* open the encoder library */
    hEncoder = faacEncOpen(sr, chan, &samplesInput, &maxBytesOutput);

    pcmbuf = (short*)malloc(samplesInput*sizeof(short));
    bitbuf = (unsigned char*)malloc(maxBytesOutput*sizeof(unsigned char));

    if (!bitRate)
    {
      bitRate = pow((double)(sr / 2) / bwdefault, 1.0 / bwbrfac) * 64000;
      bitRate = ((bitRate + 500) / 500) * 500;
      if (bitRate > 64000)
	bitRate = 64000;
    }
    if (cutOff <= 0)
    {
      if (cutOff < 0) // default
	cutOff = pow((double)bitRate / 64000, bwbrfac) * bwdefault;
      else // disabled
	cutOff = sr / 2;
    }
    if (cutOff > (sr / 2))
      cutOff = sr / 2;
    fprintf(stderr, "Bit rate: %ld bps per channel\n", bitRate);
    fprintf(stderr, "Cutoff frequency is ");
    if (cutOff == sr / 2)
      fprintf(stderr, "disabled\n");
    else
      fprintf(stderr, "%d Hz\n", cutOff);

    /* put the options in the configuration struct */
    myFormat = faacEncGetCurrentConfiguration(hEncoder);
    myFormat->aacObjectType = objectType;
    myFormat->mpegVersion = mpegVersion;
    myFormat->useTns = useTns;
    myFormat->allowMidside = useMidSide;
    myFormat->bitRate = bitRate;
    myFormat->bandWidth = cutOff;
    myFormat->outputFormat = useAdts;
    if (psymodelidx >= 0)
      myFormat->psymodelidx = psymodelidx;
    if (!faacEncSetConfiguration(hEncoder, myFormat)) {
        fprintf(stderr, "Unsupported output format!\n");
        return 1;
    }

    if (outfile)
    {
	int showcnt = 0;
#ifdef _WIN32
	long begin = GetTickCount();
#endif
	frames = (int)infile->samples / 1024 + 2;
        currentFrame = 0;

	fprintf(stderr, "Encoding %s\n", audioFileName);
	fprintf(stderr,
		"   frame          | elapsed/estim | play/CPU | ETA\n");
        /* encoding loop */
        for ( ;; )
        {
            int bytesWritten;

            bytesInput = wav_read_short(infile, pcmbuf, samplesInput) * sizeof(short);

            /* call the actual encoding routine */
            bytesWritten = faacEncEncode(hEncoder,
                pcmbuf,
                bytesInput/2,
                bitbuf,
                maxBytesOutput);

	    if (bytesWritten)
      {
	      currentFrame++;
	      showcnt--;
	    }

	    if ((showcnt <= 0) || !bytesWritten)
	    {
	      double timeused;
#ifdef __unix__
	      struct rusage usage;
#endif
#ifdef _WIN32
	      char percent[50];
	      timeused = (GetTickCount() - begin) * 1e-3;
#else
#ifdef __unix__
	      if (getrusage(RUSAGE_SELF, &usage) == 0) {
		timeused = (double)usage.ru_utime.tv_sec +
		  (double)usage.ru_utime.tv_usec * 1e-6;
	      }
	      else
                timeused = 0;
#else
	      timeused = (double)clock() * (1.0 / CLOCKS_PER_SEC);
#endif
#endif
	      if (currentFrame && (timeused > 0.1))
	      {

		showcnt += 50;

		fprintf(stderr,
			"\r%5d/%-5d (%3d%%)| %6.1f/%-6.1f | %8.3f | %.1f ",
			currentFrame, frames, currentFrame*100/frames,
			timeused,
			timeused * frames / currentFrame,
			(1024.0 * currentFrame / sr) / timeused,
			timeused  * (frames - currentFrame) / currentFrame);
		fflush(stderr);
#ifdef _WIN32
		sprintf(percent, "%.2f%% encoding %s",
			100.0 * currentFrame / frames, audioFileName);
            SetConsoleTitle(percent);
#endif
	      }
      }

            /* all done, bail out */
            if (!bytesInput && !bytesWritten)
                break ;

            if (bytesWritten < 0)
            {
                fprintf(stderr, "faacEncEncode() failed\n");
                break ;
            }

            /* write bitstream to aac file */
            fwrite(bitbuf, 1, bytesWritten, outfile);
        }
	fprintf(stderr, "\n\n");

        /* clean up */
        fclose(outfile);
    }

    faacEncClose(hEncoder);

    wav_close(infile);

    if (pcmbuf) free(pcmbuf);
    if (bitbuf) free(bitbuf);

    return 0;
}

/*
$Log: main.c,v $
Revision 1.29  2002/11/23 17:34:59  knik
replaced libsndfile with input.c
improved bandwidth/bitrate calculation formula

Revision 1.28  2002/08/30 16:20:45  knik
misplaced #endif

Revision 1.27  2002/08/19 16:33:54  knik
automatic bitrate setting
more advanced status line

*/