"Fossies" - the Fresh Open Source Software Archive

Member "faac-1_30/frontend/main.c" (16 Oct 2019, 36821 Bytes) of package /linux/misc/faac-1_30.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "main.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes reports: 1.28_vs_1.29.9.2 or 1.29.9_vs_1.29.9.2.

    1 /*
    2  * FAAC - Freeware Advanced Audio Coder
    3  * Copyright (C) 2001 Menno Bakker
    4  * Copyright (C) 2002-2017 Krzysztof Nikiel
    5  * Copyright (C) 2004 Dan Villiom P. Christiansen
    6  *
    7  * This library is free software; you can redistribute it and/or
    8  * modify it under the terms of the GNU Lesser General Public
    9  * License as published by the Free Software Foundation; either
   10  * version 2.1 of the License, or (at your option) any later version.
   11  *
   12  * This library is distributed in the hope that it will be useful,
   13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15  * Lesser General Public License for more details.
   16 
   17  * You should have received a copy of the GNU Lesser General Public
   18  * License along with this library; if not, write to the Free Software
   19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   20  *
   21  */
   22 
   23 
   24 #ifdef HAVE_CONFIG_H
   25 #include "config.h"
   26 #endif
   27 
   28 #ifdef _WIN32
   29 #include <windows.h>
   30 #include <fcntl.h>
   31 #else
   32 #include <signal.h>
   33 #endif
   34 
   35 /* the BSD derivatives don't define __unix__ */
   36 #if defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
   37 #define __unix__
   38 #endif
   39 
   40 #ifdef __unix__
   41 #include <time.h>
   42 #include <sys/time.h>
   43 #include <sys/resource.h>
   44 #include <unistd.h>
   45 #endif
   46 
   47 #include <stdio.h>
   48 #include <stdlib.h>
   49 #include <ctype.h>
   50 #include <math.h>
   51 #include <string.h>
   52 
   53 #ifdef HAVE_GETOPT_H
   54 # include <getopt.h>
   55 #else
   56 # include "getopt.h"
   57 # include "getopt.c"
   58 #endif
   59 
   60 #include "mp4write.h"
   61 
   62 #if !defined(HAVE_STRCASECMP) && !defined(_WIN32)
   63 # define strcasecmp strcmp
   64 #endif
   65 
   66 #ifdef _WIN32
   67 # undef stderr
   68 # define stderr stdout
   69 #endif
   70 
   71 #include "input.h"
   72 
   73 #include <faac.h>
   74 
   75 #define FALSE 0
   76 #define TRUE 1
   77 
   78 enum flags
   79 {
   80     SHORTCTL_FLAG = 300,
   81     MPEGVERS_FLAG,
   82     ARTIST_FLAG,
   83     TITLE_FLAG,
   84     GENRE_FLAG,
   85     ALBUM_FLAG,
   86     TRACK_FLAG,
   87     DISC_FLAG,
   88     YEAR_FLAG,
   89     COVER_ART_FLAG,
   90     COMMENT_FLAG,
   91     WRITER_FLAG,
   92     TAG_FLAG,
   93     HELP_QUAL,
   94     HELP_IO,
   95     HELP_MP4,
   96     HELP_ADVANCED,
   97     OPT_JOINT,
   98     OPT_PNS
   99 };
  100 
  101 typedef struct {
  102     char *shorthelp;
  103     char *longhelp;
  104 } help_t;
  105 
  106 const char *usage =
  107     "Usage: %s [options] infile\n\n";
  108 
  109 static help_t help_qual[] = {
  110     {"-q <quality>\tSet encoding quality.\n",
  111     "\t\tSet default variable bitrate (VBR) quantizer quality in percent.\n"
  112     "\t\tmax. 5000, min. 10.\n"
  113     "\t\tdefault: 100, averages at approx. 120 kbps VBR for a normal\n"
  114     "\t\tstereo input file with 16 bit and 44.1 kHz sample rate\n"
  115     },
  116     {"-b <bitrate>\tSet average bitrate to x kbps. (ABR)\n",
  117     "\t\tSet average bitrate (ABR) to approximately <bitrate> kbps.\n"
  118     "\t\tmax. ~500 (stereo)\n"},
  119     {"-c <freq>\tSet the bandwidth in Hz.\n",
  120     "\t\tThe actual frequency is adjusted to maximize upper spectral band\n"
  121     "\t\tusage.\n"},
  122     {0}
  123 };
  124 
  125 static help_t help_io[] = {
  126     {"-o <filename>\tSet output file to X (only for one input file)\n",
  127     "\t\tonly for one input file; you can use *.aac, *.mp4, *.m4a or\n"
  128     "\t\t*.m4b as file extension, and the file format will be set\n"
  129     "\t\tautomatically to ADTS or MP4).\n"},
  130     {"-\t\tUse stdin/stdout\n",
  131     "\t\tIf you simply use a hyphen/minus sign instead\n"
  132     "\t\tof a filename, FAAC can encode directly from stdin,\n"
  133     "\t\tthus enabling piping from other applications and utilities. The\n"
  134     "\t\tsame works for stdout as well, so FAAC can pipe its output to\n"
  135     "\t\tother apps such as a server.\n"},
  136     {"-v <verbose>\t\tverbosity level (-v0 is quiet mode)\n"},
  137     {"-r\t\tUse RAW AAC output file.\n",
  138     "\t\tGenerate raw AAC bitstream (i.e. without any headers).\n"
  139     "\t\tNot advised!!!, RAW AAC files are practically useless!!!\n"},
  140     {"-P\t\tRaw PCM input mode (default 44100Hz 16bit stereo).\n",
  141     "\t\tRaw PCM input mode (default: off, i.e. expecting a WAV header;\n"
  142     "\t\tnecessary for input files or bitstreams without a header; using\n"
  143     "\t\tonly -P assumes the default values for -R, -B and -C in the\n"
  144     "\t\tinput file).\n"},
  145     {"-R <samplerate>\tRaw PCM input rate.\n",
  146     "\t\tRaw PCM input sample rate in Hz (default: 44100 Hz, max. 96 kHz)\n"},
  147     {"-B <samplebits>\tRaw PCM input sample size (8, 16 (default), 24 or 32bits).\n",
  148     "\t\tRaw PCM input sample size (default: 16, also possible 8, 24, 32\n"
  149     "\t\tbit fixed or float input).\n"},
  150     {"-C <channels>\tRaw PCM input channels.\n",
  151     "\t\tRaw PCM input channels (default: 2, max. 33 + 1 LFE).\n"},
  152     {"-X\t\tRaw PCM swap input bytes\n",
  153     "\t\tRaw PCM swap input bytes (default: bigendian).\n"},
  154     {"-I <C[,LFE]>\tInput channel config, default is 3,4 (Center third, LF fourth)\n",
  155     "\t\tInput multichannel configuration (default: 3,4 which means\n"
  156     "\t\tCenter is third and LFE is fourth like in 5.1 WAV, so you only\n"
  157     "\t\thave to specify a different position of these two mono channels\n"
  158     "\t\tin your multichannel input files if they haven't been reordered\n"
  159     "\t\talready).\n"},
  160     {"--ignorelength\tIgnore wav length from header (useful with files over 4 GB)\n"},
  161     {"--overwrite\t\tOverwrite existing output file"},
  162     {0}
  163 };
  164 
  165 static help_t help_mp4[] = {
  166     {"-w\t\tWrap AAC data in MP4 container. (default for *.mp4 and *.m4a)\n",
  167     "\t\tWrap AAC data in MP4 container. (default for *.mp4, *.m4a and\n"
  168     "\t\t*.m4b)\n"},
  169     {"--tag <tagname,tagvalue> Add named tag (iTunes '----')\n"},
  170     {"--artist <name>\tSet artist name\n"},
  171     {"--composer <name>\tSet composer name\n"},
  172     {"--title <name>\tSet title/track name\n"},
  173     {"--genre <number>\tSet genre number\n"},
  174     {"--album <name>\tSet album/performer\n"},
  175     {"--compilation\tMark as compilation\n"},
  176     {"--track <number/total>\tSet track number\n"},
  177     {"--disc <number/total>\tSet disc number\n"},
  178     {"--year <number>\tSet year\n"},
  179     {"--cover-art <filename>\tRead cover art from file X\n",
  180     "\t\tSupported image formats are GIF, JPEG, and PNG.\n"},
  181     {"--comment <string>\tSet comment\n"},
  182     {0}
  183 };
  184 
  185 static help_t help_advanced[] = {
  186     {"--tns  \tEnable coding of TNS, temporal noise shaping.\n"},
  187     {"--no-tns\tDisable coding of TNS, temporal noise shaping.\n"},
  188     {"--joint 0\tDisable joint stereo coding.\n"},
  189     {"--joint 1\tUse Mid/Side coding.\n"},
  190     {"--joint 2\tUse Intensity Stereo coding.\n"},
  191     {"--pns <0 .. 10>\tPNS level; 0=disabled.\n"},
  192     {"--mpeg-vers X\tForce AAC MPEG version, X can be 2 or 4\n"},
  193     {"--shortctl X\tEnforce block type (0 = both (default); 1 = no short; 2 = no\n"
  194     "\t\tlong).\n"},
  195     {0}
  196 };
  197 
  198 static struct {
  199     int id;
  200     char *name;
  201     char *option;
  202     help_t *help;
  203 } g_help[] = {
  204     {HELP_QUAL, "Quality-related options", "--help-qual", help_qual},
  205     {HELP_IO, "Input/output options", "--help-io", help_io},
  206     {HELP_MP4, "MP4 specific options", "--help-mp4", help_mp4},
  207     {HELP_ADVANCED, "Advanced options, only for testing purposes", "--help-advanced", help_advanced},
  208     {0}
  209 };
  210 
  211 char *license =
  212     "\nPlease note that the use of this software may require the payment of patent\n"
  213     "royalties. You need to consider this issue before you start building derivative\n"
  214     "works. We are not warranting or indemnifying you in any way for patent\n"
  215     "royalities! YOU ARE SOLELY RESPONSIBLE FOR YOUR OWN ACTIONS!\n"
  216     "\n"
  217     "FAAC is based on the ISO MPEG-4 reference code. For this code base the\n"
  218     "following license applies:\n"
  219     "\n"
  220     "This software module was originally developed by\n"
  221     "\n"
  222     "FirstName LastName (CompanyName)\n"
  223     "\n"
  224     "and edited by\n"
  225     "\n"
  226     "FirstName LastName (CompanyName)\n"
  227     "FirstName LastName (CompanyName)\n"
  228     "\n"
  229     "in the course of development of the MPEG-2 NBC/MPEG-4 Audio standard\n"
  230     "ISO/IEC 13818-7, 14496-1,2 and 3. This software module is an\n"
  231     "implementation of a part of one or more MPEG-2 NBC/MPEG-4 Audio tools\n"
  232     "as specified by the MPEG-2 NBC/MPEG-4 Audio standard. ISO/IEC gives\n"
  233     "users of the MPEG-2 NBC/MPEG-4 Audio standards free license to this\n"
  234     "software module or modifications thereof for use in hardware or\n"
  235     "software products claiming conformance to the MPEG-2 NBC/ MPEG-4 Audio\n"
  236     "standards. Those intending to use this software module in hardware or\n"
  237     "software products are advised that this use may infringe existing\n"
  238     "patents. The original developer of this software module and his/her\n"
  239     "company, the subsequent editors and their companies, and ISO/IEC have\n"
  240     "no liability for use of this software module or modifications thereof\n"
  241     "in an implementation. Copyright is not released for non MPEG-2\n"
  242     "NBC/MPEG-4 Audio conforming products. The original developer retains\n"
  243     "full right to use the code for his/her own purpose, assign or donate\n"
  244     "the code to a third party and to inhibit third party from using the\n"
  245     "code for non MPEG-2 NBC/MPEG-4 Audio conforming products. This\n"
  246     "copyright notice must be included in all copies or derivative works.\n"
  247     "\n"
  248     "Copyright (c) 1997.\n"
  249     "\n"
  250     "For the changes made for the FAAC project the GNU Lesser General Public\n"
  251     "License (LGPL), version 2 1991 applies:\n"
  252     "\n"
  253     "FAAC - Freeware Advanced Audio Coder\n"
  254     "Copyright (C) 2001-2004 The individual contributors\n"
  255     "\n"
  256     "This library is free software; you can redistribute it and/or\n"
  257     "modify it under the terms of the GNU Lesser General Public\n"
  258     "License as published by the Free Software Foundation; either\n"
  259     "version 2.1 of the License, or (at your option) any later version.\n"
  260     "\n"
  261     "This library is distributed in the hope that it will be useful,\n"
  262     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
  263     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
  264     "Lesser General Public License for more details.\n"
  265     "\n"
  266     "You should have received a copy of the GNU Lesser General Public\n"
  267     "License along with this library; if not, write to the Free Software\n"
  268     "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
  269     "\n";
  270 
  271 #ifndef min
  272 #define min(a,b) ( (a) < (b) ? (a) : (b) )
  273 #endif
  274 
  275 /* globals */
  276 char *progName;
  277 #ifndef _WIN32
  278 volatile int running = 1;
  279 #endif
  280 
  281 enum container_format
  282 {
  283     NO_CONTAINER,
  284     MP4_CONTAINER,
  285 };
  286 
  287 #ifndef _WIN32
  288 void signal_handler(int signal)
  289 {
  290     running = 0;
  291 }
  292 #endif
  293 
  294 static void help0(help_t *h, int l)
  295 {
  296     int cnt;
  297 
  298     for (cnt = 0; h[cnt].shorthelp; cnt++)
  299     {
  300         printf("    %s", h[cnt].shorthelp);
  301         if (l && h[cnt].longhelp)
  302             printf("%s", h[cnt].longhelp);
  303     }
  304     printf("\n\n");
  305 }
  306 
  307 static void help(int mode)
  308 {
  309     int cnt;
  310     static const char *name = "faac";
  311 
  312     printf(usage, name);
  313     switch (mode)
  314     {
  315     case '?':
  316     case 'h':
  317     case 'H':
  318         printf("Help options:\n"
  319                 "\t-h\t\tShort help on using FAAC\n"
  320                 "\t-H\t\tDescription of all options for FAAC.\n"
  321                 "\t--license\tLicense terms for FAAC.\n");
  322         for (cnt = 0; g_help[cnt].id; cnt++)
  323             printf("\t%s\t%s\n", g_help[cnt].option, g_help[cnt].name);
  324         if (mode == 'h')
  325         {
  326         for (cnt = 0; cnt < 2; cnt++)
  327         {
  328             printf("%s:\n", g_help[cnt].name);
  329             help0(g_help[cnt].help, 0);
  330         }
  331         }
  332         if (mode == 'H')
  333         {
  334         for (cnt = 0; cnt < g_help[cnt].id; cnt++)
  335         {
  336             printf("%s:\n", g_help[cnt].name);
  337             help0(g_help[cnt].help, 1);
  338         }
  339         }
  340         break;
  341     default:
  342         for (cnt = 0; g_help[cnt].id; cnt++)
  343             if (g_help[cnt].id == mode)
  344             {
  345                 printf("%s:\n", g_help[cnt].name);
  346                 help0(g_help[cnt].help, 1);
  347                 break;
  348             }
  349         break;
  350     }
  351 }
  352 
  353 static int check_image_header(const char *buf)
  354 {
  355     if (!strncmp(buf, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8))
  356         return 1;               /* PNG */
  357     else if (!strncmp(buf, "\xFF\xD8\xFF\xE0", 4) ||
  358              !strncmp(buf, "\xFF\xD8\xFF\xE1", 4))
  359         return 1;               /* JPEG */
  360     else if (!strncmp(buf, "GIF87a", 6) || !strncmp(buf, "GIF89a", 6))
  361         return 1;               /* GIF */
  362     else
  363         return 0;
  364 }
  365 
  366 static int *mkChanMap(int channels, int center, int lf)
  367 {
  368     int *map;
  369     int inpos;
  370     int outpos;
  371 
  372     if (!center && !lf)
  373         return NULL;
  374 
  375     if (channels < 3)
  376         return NULL;
  377 
  378     if (lf > 0)
  379         lf--;
  380     else
  381         lf = channels - 1;      // default AAC position
  382 
  383     if (center > 0)
  384         center--;
  385     else
  386         center = 0;             // default AAC position
  387 
  388     map = malloc(channels * sizeof(map[0]));
  389     memset(map, 0, channels * sizeof(map[0]));
  390 
  391     outpos = 0;
  392     if ((center >= 0) && (center < channels))
  393         map[outpos++] = center;
  394 
  395     inpos = 0;
  396     for (; outpos < (channels - 1); inpos++)
  397     {
  398         if (inpos == center)
  399             continue;
  400         if (inpos == lf)
  401             continue;
  402 
  403         map[outpos++] = inpos;
  404     }
  405     if (outpos < channels)
  406     {
  407         if ((lf >= 0) && (lf < channels))
  408             map[outpos] = lf;
  409         else
  410             map[outpos] = inpos;
  411     }
  412 
  413     return map;
  414 }
  415 
  416 #define fprintf if(verbose)fprintf
  417 
  418 int main(int argc, char *argv[])
  419 {
  420     int frames, currentFrame;
  421     faacEncHandle hEncoder;
  422     pcmfile_t *infile = NULL;
  423 
  424     unsigned long samplesInput, maxBytesOutput, totalBytesWritten = 0;
  425 
  426     faacEncConfigurationPtr myFormat;
  427     unsigned int mpegVersion = MPEG2;
  428     unsigned int objectType = LOW;
  429     int jointmode = -1;
  430     int pnslevel = -1;
  431     static int useTns = 0;
  432     enum container_format container = NO_CONTAINER;
  433     enum stream_format stream = ADTS_STREAM;
  434     int cutOff = -1;
  435     int bitRate = 0;
  436     unsigned long quantqual = 0;
  437     int chanC = 3;
  438     int chanLF = 4;
  439 
  440     char *audioFileName = NULL;
  441     char *aacFileName = NULL;
  442     char *aacFileExt = NULL;
  443     int aacFileNameGiven = 0;
  444 
  445     float *pcmbuf;
  446     int *chanmap = NULL;
  447 
  448     unsigned char *bitbuf;
  449     int samplesRead = 0;
  450     const char *dieMessage = NULL;
  451 
  452     int rawChans = 0;           // disabled by default
  453     int rawBits = 16;
  454     int rawRate = 44100;
  455     int rawEndian = 1;
  456 
  457     int shortctl = SHORTCTL_NORMAL;
  458 
  459     FILE *outfile = NULL;
  460 
  461     unsigned int ntracks = 0, trackno = 0;
  462     unsigned int ndiscs = 0, discno = 0;
  463     static int compilation = 0;
  464     const char *artist = NULL, *title = NULL, *album = NULL, *year = NULL,
  465         *comment = NULL, *composer = NULL, *tagname = 0, *tagval = 0;
  466     int genre = 0;
  467     uint8_t *artData = NULL;
  468     uint64_t artSize = 0;
  469     uint64_t encoded_samples = 0;
  470     unsigned int delay_samples;
  471     unsigned int frameSize;
  472     uint64_t input_samples = 0;
  473     char *faac_id_string;
  474     char *faac_copyright_string;
  475     static int ignorelen = 0;
  476     int verbose = 1;
  477     static int overwrite = 0;
  478 
  479 #ifndef _WIN32
  480     // install signal handler
  481     signal(SIGINT, signal_handler);
  482     signal(SIGTERM, signal_handler);
  483 #endif
  484 
  485     // get faac version
  486     if (faacEncGetVersion(&faac_id_string, &faac_copyright_string) ==
  487         FAAC_CFG_VERSION)
  488     {
  489         fprintf(stderr, "Freeware Advanced Audio Coder\nFAAC %s\n\n",
  490                 faac_id_string);
  491     }
  492     else
  493     {
  494         fprintf(stderr, __FILE__ "(%d): wrong libfaac version\n", __LINE__);
  495         return 1;
  496     }
  497 
  498     /* begin process command line */
  499     progName = argv[0];
  500     if (argc < 2)
  501     {
  502         help('?');
  503         return 1;
  504     }
  505     while (1)
  506     {
  507         static struct option long_options[] = {
  508             {"help", 0, 0, 'h'},
  509             {"help-qual", 0, 0, HELP_QUAL},
  510             {"help-io", 0, 0, HELP_IO},
  511             {"help-mp4", 0, 0, HELP_MP4},
  512             {"help-advanced", 0, 0, HELP_ADVANCED},
  513             {"raw", 0, 0, 'r'},
  514             {"joint", required_argument, 0, OPT_JOINT},
  515             {"pns", required_argument, 0, OPT_PNS},
  516             {"cutoff", 1, 0, 'c'},
  517             {"quality", 1, 0, 'q'},
  518             {"pcmraw", 0, 0, 'P'},
  519             {"pcmsamplerate", 1, 0, 'R'},
  520             {"pcmsamplebits", 1, 0, 'B'},
  521             {"pcmchannels", 1, 0, 'C'},
  522             {"shortctl", 1, 0, SHORTCTL_FLAG},
  523             {"tns", 0, &useTns, 1},
  524             {"no-tns", 0, &useTns, 0},
  525             {"mpeg-version", 1, 0, MPEGVERS_FLAG},
  526             {"license", 0, 0, 'L'},
  527             {"createmp4", 0, 0, 'w'},
  528             {"artist", 1, 0, ARTIST_FLAG},
  529             {"title", 1, 0, TITLE_FLAG},
  530             {"album", 1, 0, ALBUM_FLAG},
  531             {"track", 1, 0, TRACK_FLAG},
  532             {"disc", 1, 0, DISC_FLAG},
  533             {"genre", 1, 0, GENRE_FLAG},
  534             {"year", 1, 0, YEAR_FLAG},
  535             {"cover-art", 1, 0, COVER_ART_FLAG},
  536             {"comment", 1, 0, COMMENT_FLAG},
  537             {"composer", 1, 0, WRITER_FLAG},
  538             {"compilation", 0, &compilation, 1},
  539             {"pcmswapbytes", 0, 0, 'X'},
  540             {"ignorelength", 0, &ignorelen, 1},
  541             {"tag", 1, 0, TAG_FLAG},
  542             {"overwrite", 0, &overwrite, 1},
  543             {0, 0, 0, 0}
  544         };
  545         int c = -1;
  546         int option_index = 0;
  547 
  548         c = getopt_long(argc, argv, "Hhb:m:o:rnc:q:PR:B:C:I:Xwv:",
  549                         long_options, &option_index);
  550 
  551         if (c == -1)
  552             break;
  553 
  554         if (!c)
  555             continue;
  556 
  557         switch (c)
  558         {
  559         case 'o':
  560             {
  561                 int l = strlen(optarg);
  562                 aacFileName = malloc(l + 1);
  563                 memcpy(aacFileName, optarg, l);
  564                 aacFileName[l] = '\0';
  565                 aacFileNameGiven = 1;
  566             }
  567             break;
  568         case 'r':
  569             {
  570                 stream = RAW_STREAM;
  571                 break;
  572             }
  573         case 'c':
  574             {
  575                 unsigned int i;
  576                 if (sscanf(optarg, "%u", &i) > 0)
  577                 {
  578                     cutOff = i;
  579                 }
  580                 break;
  581             }
  582         case 'b':
  583             {
  584                 unsigned int i;
  585                 if (sscanf(optarg, "%u", &i) > 0)
  586                 {
  587                     bitRate = 1000 * i;
  588                 }
  589                 break;
  590             }
  591         case 'q':
  592             {
  593                 unsigned int i;
  594                 if (sscanf(optarg, "%u", &i) > 0)
  595                 {
  596                     if (i > 0)
  597                         quantqual = i;
  598                 }
  599                 break;
  600             }
  601         case 'I':
  602             sscanf(optarg, "%d,%d", &chanC, &chanLF);
  603             break;
  604         case 'P':
  605             rawChans = 2;       // enable raw input
  606             break;
  607         case 'R':
  608             {
  609                 unsigned int i;
  610                 if (sscanf(optarg, "%u", &i) > 0)
  611                 {
  612                     rawRate = i;
  613                     rawChans = (rawChans > 0) ? rawChans : 2;
  614                 }
  615                 break;
  616             }
  617         case 'B':
  618             {
  619                 unsigned int i;
  620                 if (sscanf(optarg, "%u", &i) > 0)
  621                 {
  622                     if (i > 32)
  623                         i = 32;
  624                     if (i < 8)
  625                         i = 8;
  626                     rawBits = i;
  627                     rawChans = (rawChans > 0) ? rawChans : 2;
  628                 }
  629                 break;
  630             }
  631         case 'C':
  632             {
  633                 unsigned int i;
  634                 if (sscanf(optarg, "%u", &i) > 0)
  635                     rawChans = i;
  636                 break;
  637             }
  638         case 'w':
  639             container = MP4_CONTAINER;
  640             break;
  641         case ARTIST_FLAG:
  642             artist = optarg;
  643             break;
  644         case WRITER_FLAG:
  645             composer = optarg;
  646             break;
  647         case TITLE_FLAG:
  648             title = optarg;
  649             break;
  650         case ALBUM_FLAG:
  651             album = optarg;
  652             break;
  653         case TRACK_FLAG:
  654             if (sscanf(optarg, "%d/%d", &trackno, &ntracks) < 1)
  655                 dieMessage = "Wrong track number.\n";
  656             break;
  657         case DISC_FLAG:
  658             if (sscanf(optarg, "%d/%d", &discno, &ndiscs) < 1)
  659                 dieMessage = "Wrong disc number.\n";
  660             break;
  661         case GENRE_FLAG:
  662             genre = atoi(optarg);
  663             if ((genre < 0) || (genre > 146))
  664                 dieMessage = "Genre number out of range.\n";
  665             genre++;
  666             break;
  667         case YEAR_FLAG:
  668             year = optarg;
  669             break;
  670         case COMMENT_FLAG:
  671             comment = optarg;
  672             break;
  673         case TAG_FLAG:
  674             tagname = optarg;
  675             if (!(tagval = strchr(optarg, ',')))
  676                 dieMessage = "Missing tag value.\n";
  677             else
  678                 *(char *)tagval++ = 0;
  679             mp4tag_add(tagname, tagval);
  680             break;
  681         case COVER_ART_FLAG:
  682             {
  683                 FILE *artFile = fopen(optarg, "rb");
  684 
  685                 if (artFile)
  686                 {
  687                     uint64_t r;
  688 
  689                     fseek(artFile, 0, SEEK_END);
  690                     artSize = ftell(artFile);
  691 
  692                     artData = malloc(artSize);
  693 
  694                     fseek(artFile, 0, SEEK_SET);
  695                     clearerr(artFile);
  696 
  697                     r = fread(artData, artSize, 1, artFile);
  698 
  699                     if (r != 1)
  700                     {
  701                         dieMessage = "Error reading cover art file!\n";
  702                         free(artData);
  703                         artData = NULL;
  704                     }
  705                     else if (artSize < 12
  706                              || !check_image_header((const char *) artData))
  707                     {
  708                         /* the above expression checks the image signature */
  709                         dieMessage = "Unsupported cover image file format!\n";
  710                         free(artData);
  711                         artData = NULL;
  712                     }
  713 
  714                     fclose(artFile);
  715                 }
  716                 else
  717                 {
  718                     dieMessage = "Error opening cover art file!\n";
  719                 }
  720 
  721                 break;
  722             }
  723         case SHORTCTL_FLAG:
  724             shortctl = atoi(optarg);
  725             break;
  726         case MPEGVERS_FLAG:
  727             mpegVersion = atoi(optarg);
  728             switch (mpegVersion)
  729             {
  730             case 2:
  731                 mpegVersion = MPEG2;
  732                 break;
  733             case 4:
  734                 mpegVersion = MPEG4;
  735                 break;
  736             default:
  737                 dieMessage = "Unrecognised MPEG version!\n";
  738             }
  739             break;
  740         case 'L':
  741             fprintf(stderr, "%s", faac_copyright_string);
  742             dieMessage = license;
  743             break;
  744         case 'X':
  745             rawEndian = 0;
  746             break;
  747         case 'v':
  748             verbose = atoi(optarg);
  749             break;
  750         case HELP_QUAL:
  751         case HELP_IO:
  752         case HELP_MP4:
  753         case HELP_ADVANCED:
  754         case 'H':
  755         case 'h':
  756             help(c);
  757             return 1;
  758             break;
  759         case OPT_JOINT:
  760             jointmode = atoi(optarg);
  761             break;
  762         case OPT_PNS:
  763             pnslevel = atoi(optarg);
  764             break;
  765         case '?':
  766         default:
  767             help('?');
  768             return 1;
  769             break;
  770         }
  771     }
  772 
  773     /* check that we have at least one non-option arguments */
  774     if (!dieMessage && (argc - optind) > 1 && aacFileNameGiven)
  775         dieMessage =
  776             "Cannot encode several input files to one output file.\n";
  777 
  778     if (argc - optind < 1 || dieMessage)
  779     {
  780         fprintf(stderr, dieMessage, progName, progName, progName, progName);
  781         return 1;
  782     }
  783 
  784     while (argc - optind > 0)
  785     {
  786         /* get the input file name */
  787         audioFileName = argv[optind++];
  788     }
  789 
  790     /* generate the output file name, if necessary */
  791     if (!aacFileNameGiven)
  792     {
  793         char *t = strrchr(audioFileName, '.');
  794         int l = t ? strlen(audioFileName) - strlen(t) : strlen(audioFileName);
  795 
  796         aacFileExt = container == MP4_CONTAINER ? ".m4a" : ".aac";
  797 
  798         aacFileName = malloc(l + 1 + 4);
  799         memcpy(aacFileName, audioFileName, l);
  800         memcpy(aacFileName + l, aacFileExt, 4);
  801         aacFileName[l + 4] = '\0';
  802     }
  803     else
  804     {
  805         aacFileExt = strrchr(aacFileName, '.');
  806 
  807         if (aacFileExt
  808             && (!strcmp(".m4a", aacFileExt) || !strcmp(".m4b", aacFileExt)
  809                 || !strcmp(".mp4", aacFileExt)))
  810             container = MP4_CONTAINER;
  811     }
  812 
  813     /* open the audio input file */
  814     if (rawChans > 0)           // use raw input
  815     {
  816         infile = wav_open_read(audioFileName, 1);
  817         if (infile)
  818         {
  819             infile->bigendian = rawEndian;
  820             infile->channels = rawChans;
  821             infile->samplebytes = rawBits / 8;
  822             infile->samplerate = rawRate;
  823             infile->samples /= (infile->channels * infile->samplebytes);
  824         }
  825     }
  826     else                        // header input
  827         infile = wav_open_read(audioFileName, 0);
  828 
  829     if (infile == NULL)
  830     {
  831         fprintf(stderr, "Couldn't open input file %s\n", audioFileName);
  832         return 1;
  833     }
  834 
  835     /* open the encoder library */
  836     hEncoder = faacEncOpen(infile->samplerate, infile->channels,
  837                            &samplesInput, &maxBytesOutput);
  838 
  839     if (hEncoder == NULL)
  840     {
  841         fprintf(stderr, "Couldn't open encoder instance for input file %s\n",
  842                 audioFileName);
  843         wav_close(infile);
  844         return 1;
  845     }
  846 
  847     if (container != MP4_CONTAINER && (ntracks || trackno || artist ||
  848                                        title || album || year || artData ||
  849                                        genre || comment || discno || ndiscs ||
  850                                        composer || compilation))
  851     {
  852         fprintf(stderr, "Metadata requires MP4 output!\n");
  853         return 1;
  854     }
  855 
  856     if (container == MP4_CONTAINER)
  857     {
  858         mpegVersion = MPEG4;
  859         stream = RAW_STREAM;
  860     }
  861 
  862     frameSize = samplesInput / infile->channels;
  863     delay_samples = frameSize;  // encoder delay 1024 samples
  864     pcmbuf = (float *) malloc(samplesInput * sizeof(float));
  865     bitbuf = (unsigned char *) malloc(maxBytesOutput * sizeof(unsigned char));
  866     chanmap = mkChanMap(infile->channels, chanC, chanLF);
  867     if (chanmap)
  868     {
  869         fprintf(stderr, "Remapping input channels: Center=%d, LFE=%d\n",
  870                 chanC, chanLF);
  871     }
  872 
  873     if (cutOff <= 0)
  874     {
  875         if (cutOff < 0)         // default
  876             cutOff = 0;
  877         else                    // disabled
  878             cutOff = infile->samplerate / 2;
  879     }
  880     if (cutOff > (infile->samplerate / 2))
  881         cutOff = infile->samplerate / 2;
  882 
  883     /* put the options in the configuration struct */
  884     myFormat = faacEncGetCurrentConfiguration(hEncoder);
  885     myFormat->aacObjectType = objectType;
  886     myFormat->mpegVersion = mpegVersion;
  887     myFormat->useTns = useTns;
  888     switch (shortctl)
  889     {
  890     case SHORTCTL_NOSHORT:
  891         fprintf(stderr, "disabling short blocks\n");
  892         myFormat->shortctl = shortctl;
  893         break;
  894     case SHORTCTL_NOLONG:
  895         fprintf(stderr, "disabling long blocks\n");
  896         myFormat->shortctl = shortctl;
  897         break;
  898     }
  899     if (infile->channels >= 6)
  900         myFormat->useLfe = 1;
  901     if (jointmode >= 0)
  902         myFormat->jointmode = jointmode;
  903     if (pnslevel >= 0)
  904         myFormat->pnslevel = pnslevel;
  905     if (quantqual > 0)
  906     {
  907         myFormat->quantqual = quantqual;
  908         myFormat->bitRate = 0;
  909     }
  910     if (bitRate)
  911         myFormat->bitRate = bitRate / infile->channels;
  912     myFormat->bandWidth = cutOff;
  913     myFormat->outputFormat = stream;
  914     myFormat->inputFormat = FAAC_INPUT_FLOAT;
  915     if (!faacEncSetConfiguration(hEncoder, myFormat))
  916     {
  917         fprintf(stderr, "Unsupported output format!\n");
  918         return 1;
  919     }
  920 
  921     /* initialize MP4 creation */
  922     if (container == MP4_CONTAINER)
  923     {
  924         if (!strcmp(aacFileName, "-"))
  925         {
  926             fprintf(stderr, "cannot encode MP4 to stdout\n");
  927             return 1;
  928         }
  929 
  930         if (mp4atom_open(aacFileName, overwrite))
  931         {
  932             fprintf(stderr, "Couldn't create output file %s\n", aacFileName);
  933             return 1;
  934         }
  935         mp4atom_head();
  936 
  937         mp4config.samplerate = infile->samplerate;
  938         mp4config.channels = infile->channels;
  939         mp4config.bits = infile->samplebytes * 8;
  940     }
  941     else
  942     {
  943         /* open the aac output file */
  944         if (!strcmp(aacFileName, "-"))
  945         {
  946             outfile = stdout;
  947         }
  948         else
  949         {
  950             outfile = fopen(aacFileName, "wb");
  951         }
  952         if (!outfile)
  953         {
  954             fprintf(stderr, "Couldn't create output file %s\n", aacFileName);
  955             return 1;
  956         }
  957     }
  958 
  959     cutOff = myFormat->bandWidth;
  960     quantqual = myFormat->quantqual;
  961     bitRate = myFormat->bitRate;
  962     if (bitRate)
  963     {
  964         fprintf(stderr, "Initial quantization quality: %ld\n", quantqual);
  965         fprintf(stderr, "Average bitrate: %d kbps/channel\n",
  966                 (bitRate + 500) / 1000);
  967     }
  968     else
  969         fprintf(stderr, "Quantization quality: %ld\n", quantqual);
  970     fprintf(stderr, "Bandwidth: %d Hz\n", cutOff);
  971     if (myFormat->pnslevel > 0)
  972         fprintf(stderr, "PNS level: %d\n", myFormat->pnslevel);
  973     fprintf(stderr, "Object type: ");
  974     switch (objectType)
  975     {
  976     case LOW:
  977         fprintf(stderr, "Low Complexity");
  978         break;
  979     case MAIN:
  980         fprintf(stderr, "Main");
  981         break;
  982     case LTP:
  983         fprintf(stderr, "LTP");
  984         break;
  985     }
  986     fprintf(stderr, "(MPEG-%d)", (mpegVersion == MPEG4) ? 4 : 2);
  987     if (myFormat->useTns)
  988         fprintf(stderr, " + TNS");
  989 
  990     switch(myFormat->jointmode) {
  991     case JOINT_MS:
  992         fprintf(stderr, " + M/S");
  993         break;
  994     case JOINT_IS:
  995         fprintf(stderr, " + IS");
  996         break;
  997     }
  998     if (myFormat->pnslevel > 0)
  999         fprintf(stderr, " + PNS");
 1000     fprintf(stderr, "\n");
 1001 
 1002     fprintf(stderr, "Container format: ");
 1003     switch (container)
 1004     {
 1005     case NO_CONTAINER:
 1006         switch (stream)
 1007         {
 1008         case RAW_STREAM:
 1009             fprintf(stderr, "Headerless AAC (RAW)\n");
 1010             break;
 1011         case ADTS_STREAM:
 1012             fprintf(stderr, "Transport Stream (ADTS)\n");
 1013             break;
 1014         }
 1015         break;
 1016     case MP4_CONTAINER:
 1017         fprintf(stderr, "MPEG-4 File Format (MP4)\n");
 1018         break;
 1019     }
 1020 
 1021     int showcnt = 0;
 1022 #ifdef _WIN32
 1023     long begin = GetTickCount();
 1024 #endif
 1025     if (infile->samples)
 1026         frames = ((infile->samples + 1023) / 1024) + 1;
 1027     else
 1028         frames = 0;
 1029     currentFrame = 0;
 1030 
 1031     fprintf(stderr, "Encoding %s to %s\n", audioFileName, aacFileName);
 1032     if (frames != 0)
 1033     {
 1034         fprintf(stderr, "   frame          | bitrate | elapsed/estim | "
 1035                 "play/CPU | ETA\n");
 1036     }
 1037     else
 1038     {
 1039         fprintf(stderr, " frame | elapsed | play/CPU\n");
 1040     }
 1041 
 1042     /* encoding loop */
 1043 #ifdef _WIN32
 1044     for (;;)
 1045 #else
 1046     while (running)
 1047 #endif
 1048     {
 1049         int bytesWritten;
 1050 
 1051         if (!ignorelen)
 1052         {
 1053             if (input_samples < infile->samples || infile->samples == 0)
 1054                 samplesRead =
 1055                     wav_read_float32(infile, pcmbuf, samplesInput, chanmap);
 1056             else
 1057                 samplesRead = 0;
 1058 
 1059             if (input_samples + (samplesRead / infile->channels) >
 1060                 infile->samples && infile->samples != 0)
 1061                 samplesRead =
 1062                     (infile->samples - input_samples) * infile->channels;
 1063         }
 1064         else
 1065             samplesRead =
 1066                 wav_read_float32(infile, pcmbuf, samplesInput, chanmap);
 1067 
 1068         input_samples += samplesRead / infile->channels;
 1069 
 1070         /* call the actual encoding routine */
 1071         bytesWritten = faacEncEncode(hEncoder,
 1072                                      (int32_t *) pcmbuf,
 1073                                      samplesRead, bitbuf, maxBytesOutput);
 1074 
 1075         if (bytesWritten)
 1076         {
 1077             currentFrame++;
 1078             showcnt--;
 1079             totalBytesWritten += bytesWritten;
 1080         }
 1081 
 1082         if ((showcnt <= 0) || !bytesWritten)
 1083         {
 1084             double timeused;
 1085 #ifdef __unix__
 1086             struct rusage usage;
 1087 #endif
 1088 #ifdef _WIN32
 1089             char percent[MAX_PATH + 20];
 1090             timeused = (GetTickCount() - begin) * 1e-3;
 1091 #else
 1092 #ifdef __unix__
 1093             if (getrusage(RUSAGE_SELF, &usage) == 0)
 1094             {
 1095                 timeused = (double) usage.ru_utime.tv_sec +
 1096                     (double) usage.ru_utime.tv_usec * 1e-6;
 1097             }
 1098             else
 1099                 timeused = 0;
 1100 #else
 1101             timeused = (double) clock() * (1.0 / CLOCKS_PER_SEC);
 1102 #endif
 1103 #endif
 1104             if (currentFrame && (timeused > 0.1))
 1105             {
 1106                 showcnt += 50;
 1107 
 1108                 if (frames != 0)
 1109                 {
 1110                     fprintf(stderr,
 1111                             "\r%5d/%-5d (%3d%%)|  %5.1f  | %6.1f/%-6.1f | %7.2fx | %.1f ",
 1112                             currentFrame, frames, currentFrame * 100 / frames,
 1113                             ((double) totalBytesWritten * 8.0 / 1000.0) /
 1114                             ((double) infile->samples / infile->samplerate *
 1115                              currentFrame / frames), timeused,
 1116                             timeused * frames / currentFrame,
 1117                             (1024.0 * currentFrame / infile->samplerate) /
 1118                             timeused,
 1119                             timeused * (frames -
 1120                                         currentFrame) / currentFrame);
 1121                 }
 1122                 else
 1123                 {
 1124                     fprintf(stderr,
 1125                             "\r %5d |  %6.1f | %7.2fx ",
 1126                             currentFrame,
 1127                             timeused,
 1128                             (1024.0 * currentFrame / infile->samplerate) /
 1129                             timeused);
 1130                 }
 1131 
 1132                 fflush(stderr);
 1133 #ifdef _WIN32
 1134                 if (frames != 0)
 1135                 {
 1136                     sprintf(percent, "%.2f%% encoding %s",
 1137                             100.0 * currentFrame / frames, audioFileName);
 1138                     SetConsoleTitle(percent);
 1139                 }
 1140 #endif
 1141             }
 1142         }
 1143 
 1144         /* all done, bail out */
 1145         if (!samplesRead && !bytesWritten)
 1146             break;
 1147 
 1148         if (bytesWritten < 0)
 1149         {
 1150             fprintf(stderr, "faacEncEncode() failed\n");
 1151             break;
 1152         }
 1153 
 1154         if (bytesWritten > 0)
 1155         {
 1156             uint64_t frame_samples = input_samples - encoded_samples;
 1157             if (frame_samples > delay_samples)
 1158                 frame_samples = delay_samples;
 1159 
 1160             if (container == MP4_CONTAINER)
 1161                 mp4atom_frame(bitbuf, bytesWritten, frame_samples);
 1162             else
 1163                 fwrite(bitbuf, 1, bytesWritten, outfile);
 1164 
 1165             encoded_samples += frame_samples;
 1166         }
 1167     }
 1168     fprintf(stderr, "\n");
 1169 
 1170     if (container == MP4_CONTAINER)
 1171     {
 1172         char *version_string = malloc(strlen(faac_id_string) + 6);
 1173 
 1174         faacEncGetDecoderSpecificInfo(hEncoder,
 1175                                       &mp4config.asc.data,
 1176                                       &mp4config.asc.size);
 1177         strcpy(version_string, "FAAC ");
 1178         strcpy(version_string + 5, faac_id_string);
 1179 
 1180         mp4config.tag.encoder = version_string;
 1181 
 1182 #define SETTAG(x) if(x)mp4config.tag.x=x
 1183         SETTAG(artist);
 1184         SETTAG(composer);
 1185         SETTAG(title);
 1186         SETTAG(album);
 1187         SETTAG(trackno);
 1188         SETTAG(ntracks);
 1189         SETTAG(discno);
 1190         SETTAG(ndiscs);
 1191         SETTAG(compilation);
 1192         SETTAG(year);
 1193         SETTAG(genre);
 1194         SETTAG(comment);
 1195         if (artData && artSize)
 1196         {
 1197             mp4config.tag.cover.data = artData;
 1198             mp4config.tag.cover.size = artSize;
 1199         }
 1200 
 1201         mp4atom_tail();
 1202         mp4atom_close();
 1203 
 1204         free(version_string);
 1205 
 1206         if (verbose >= 2)
 1207         {
 1208             fprintf(stderr, "%u frames\n", mp4config.frame.ents);
 1209             fprintf(stderr, "%u output samples\n", mp4config.samples);
 1210             fprintf(stderr, "max bitrate: %u\n", mp4config.bitrate.max);
 1211             fprintf(stderr, "avg bitrate: %u\n", mp4config.bitrate.avg);
 1212             fprintf(stderr, "max frame size: %u\n", mp4config.buffersize);
 1213         }
 1214     }
 1215     else
 1216     {
 1217         fclose(outfile);
 1218     }
 1219 
 1220     faacEncClose(hEncoder);
 1221 
 1222     wav_close(infile);
 1223 
 1224     if (artData)
 1225         free(artData);
 1226     if (pcmbuf)
 1227         free(pcmbuf);
 1228     if (bitbuf)
 1229         free(bitbuf);
 1230     if (aacFileNameGiven)
 1231         free(aacFileName);
 1232 
 1233     return 0;
 1234 }