shithub: aacenc

Download patch

ref: eb39814b3ac15e1a25289b557d1c5d03af88c947
parent: 5726e930ecb3c9bbb0d37bc52f90e4f0553be19a
author: knik <knik@users.sourceforge.net>
date: Sun Jul 16 12:33:02 EDT 2017

new mp4 output module written from scratch

--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -1,5 +1,1 @@
-if WITH_MP4V2
-SUBDIRS = mp4v2
-else
 SUBDIRS =
-endif
--- a/configure.ac
+++ b/configure.ac
@@ -8,7 +8,6 @@
 #define CONFIG_H])
 AH_BOTTOM([#endif /* CONFIG_H */])
 
-AC_ARG_WITH( mp4v2,  [  --with-mp4v2            compile libmp4v2],WITHMP4V2=$withval, WITHMP4V2=yes)
 AC_ARG_ENABLE( drm,  [  --enable-drm            Digital Radio Mondiale support], enable_drm=$enableval, enable_drm=no)
 
 AC_DEFUN([MY_DEFINE], [ AC_DEFINE($1, 1, [define if needed]) ])
@@ -30,30 +29,6 @@
 
 AC_CHECK_LIB(gnugetopt, getopt_long)
 
-AM_CONDITIONAL(WITH_MP4V2, false)
-AM_CONDITIONAL(WITH_EXTERNAL_MP4V2, false)
-
-AC_CHECK_DECLS([MP4Create],
-               AC_CHECK_LIB(mp4v2, MP4Create, external_mp4v2=yes,
-                            external_mp4v2=no, -lstdc++),
-               external_mp4v2=no, [#include <mp4v2/mp4v2.h>])
-
-if test x$external_mp4v2 = xyes; then
-  AC_MSG_NOTICE([*** Building with external mp4v2 ***])
-  MY_DEFINE(HAVE_EXTERNAL_LIBMP4V2)
-  AM_CONDITIONAL(WITH_EXTERNAL_MP4V2, true)
-  AC_CHECK_DECLS([MP4TagsAlloc], [], [], [#include <mp4v2/mp4v2.h>])
-else
-  if test x$WITHMP4V2 = xyes; then
-     AC_MSG_NOTICE([*** Building with internal mp4v2 ***])
-     AM_CONDITIONAL(WITH_MP4V2, true)
-     AC_CONFIG_LINKS(common/mp4v2/mpeg4ip_config.h:config.h)
-     MY_DEFINE(HAVE_LIBMP4V2)
-  else
-     AC_MSG_NOTICE([*** Building WITHOUT mp4v2 ***])
-  fi
-fi
-
 dnl Check for DRM mode
 if test "x$enable_drm" = "xyes"; then
     AC_DEFINE(DRM, 1, [Define if you want to encode for DRM])
@@ -87,7 +62,6 @@
 
 AC_OUTPUT([
 common/Makefile
-common/mp4v2/Makefile
 libfaac/Makefile
 frontend/Makefile
 include/Makefile
--- a/frontend/Makefile.am
+++ b/frontend/Makefile.am
@@ -1,20 +1,11 @@
 bin_PROGRAMS = faac
 man_MANS = ../docs/faac.1
 
-faac_SOURCES = main.c input.c
+faac_SOURCES = main.c input.c mp4atom.c
 
-if WITH_MP4V2
-AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/common/mp4v2
-LDADD = $(top_builddir)/libfaac/libfaac.la $(top_srcdir)/common/mp4v2/libmp4v2.a -lm -lstdc++
-else
-AM_CPPFLAGS = -I$(top_srcdir)/include 
-if WITH_EXTERNAL_MP4V2
-LDADD = $(top_builddir)/libfaac/libfaac.la -lm -lmp4v2
-else
+AM_CPPFLAGS = -I$(top_srcdir)/include
 LDADD = $(top_builddir)/libfaac/libfaac.la -lm
-endif
-endif
 
 if MINGW
 LDADD += -lws2_32
-endif
\ No newline at end of file
+endif
--- a/frontend/main.c
+++ b/frontend/main.c
@@ -1,7 +1,7 @@
 /*
  * FAAC - Freeware Advanced Audio Coder
  * Copyright (C) 2001 Menno Bakker
- * Copyright (C) 2002-2004 Krzysztof Nikiel
+ * Copyright (C) 2002-2017 Krzysztof Nikiel
  * Copyright (C) 2004 Dan Villiom P. Christiansen
  *
  * This library is free software; you can redistribute it and/or
@@ -18,24 +18,13 @@
  * 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.90 2017/07/02 17:10:00 knik Exp $
  */
 
-#ifdef _MSC_VER
-# define HAVE_LIBMP4V2  1
-#endif
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#ifdef HAVE_EXTERNAL_LIBMP4V2
-# include <mp4v2/mp4v2.h>
-# define HAVE_LIBMP4V2
-#elif defined(HAVE_LIBMP4V2)
-# include <mp4.h>
-#endif
-
 #define DEFAULT_TNS     0
 
 #ifdef _WIN32
@@ -70,6 +59,8 @@
 # include "getopt.c"
 #endif
 
+#include "mp4atom.h"
+
 #if !defined(HAVE_STRCASECMP) && !defined(_WIN32)
 # define strcasecmp strcmp
 #endif
@@ -83,203 +74,193 @@
 
 #include <faac.h>
 
+enum
+{ FALSE = 0, TRUE = 1 };
+
 const char *usage =
-  "Usage: %s [options] [-o outfile] infiles ...\n"
-  "\n"
-  "\t<infiles> and/or <outfile> can be \"-\", which means stdin/stdout.\n"
-  "\n"
-  "See also:\n"
-  "\t\"%s --help\" for short help on using FAAC\n"
-  "\t\"%s --long-help\" for a description of all options for FAAC.\n"
-  "\t\"%s --license\" for the license terms for FAAC.\n\n";
+    "Usage: %s [options] [-o outfile] infiles ...\n"
+    "\n"
+    "\t<infiles> and/or <outfile> can be \"-\", which means stdin/stdout.\n"
+    "\n"
+    "See also:\n"
+    "\t\"%s --help\" for short help on using FAAC\n"
+    "\t\"%s --long-help\" for a description of all options for FAAC.\n"
+    "\t\"%s --license\" for the license terms for FAAC.\n\n";
 
 const char *short_help =
-  "Usage: %s [options] infiles ...\n"
-  "Options:\n"
-  "  -q <quality>\tSet quantizer quality.\n"
-  "  -b <bitrate>\tSet average bitrate to x kbps. (ABR, lower quality mode)\n"
-  "  -c <freq>\tSet the bandwidth in Hz. (default=automatic)\n"
-  "  -o X\t\tSet output file to X (only for one input file)\n"
-  "  -r\t\tUse RAW AAC output file.\n"
-  "  -P\t\tRaw PCM input mode (default 44100Hz 16bit stereo).\n"
-  "  -R\t\tRaw PCM input rate.\n"
-  "  -B\t\tRaw PCM input sample size (8, 16 (default), 24 or 32bits).\n"
-  "  -C\t\tRaw PCM input channels.\n"
-  "  -X\t\tRaw PCM swap input bytes\n"
-  "  -I <C,LF>\tInput channel config, default is 3,4 (Center third, LF fourth)\n"
-  "  --ignorelength\tIgnore wav length from header (useful with files over 4 GB)\n"
-  "\n"
-  "MP4 specific options:\n"
-#ifdef HAVE_LIBMP4V2
-  "  -w\t\tWrap AAC data in MP4 container. (default for *.mp4 and *.m4a)\n"
-  "  -s\t\tOptimize MP4 container layout after encoding\n"
-  "  --artist X\tSet artist to X\n"
-  "  --writer X\tSet writer to X\n"
-  "  --title X\tSet title to X\n"
-  "  --genre X\tSet genre to X\n"
-  "  --album X\tSet album to X\n"
-  "  --compilation\tSet compilation\n"
-  "  --track X\tSet track to X (number/total)\n"
-  "  --disc X\tSet disc to X (number/total)\n"
-  "  --year X\tSet year to X\n"
-  "  --cover-art X\tRead cover art from file X\n"
-  "  --comment X\tSet comment to X\n"
-#else
-  "  MP4 support unavailable.\n"
-#endif
-  "\n"
-  "Documentation:\n"
-  "  --license\tShow the FAAC license.\n"
-  "  --help\tShow this abbreviated help.\n"
-  "  --long-help\tShow complete help.\n"
-  "\n"
-  "  More tips can be found in the audiocoding.com Knowledge Base at\n"
-  "  <http://www.audiocoding.com/wiki/>\n"
-  "\n";
+    "Usage: %s [options] infiles ...\n"
+    "Options:\n"
+    "  -q <quality>\tSet quantizer quality.\n"
+    "  -b <bitrate>\tSet average bitrate to x kbps. (ABR, lower quality mode)\n"
+    "  -c <freq>\tSet the bandwidth in Hz. (default=automatic)\n"
+    "  -o X\t\tSet output file to X (only for one input file)\n"
+    "  -r\t\tUse RAW AAC output file.\n"
+    "  -P\t\tRaw PCM input mode (default 44100Hz 16bit stereo).\n"
+    "  -R\t\tRaw PCM input rate.\n"
+    "  -B\t\tRaw PCM input sample size (8, 16 (default), 24 or 32bits).\n"
+    "  -C\t\tRaw PCM input channels.\n"
+    "  -X\t\tRaw PCM swap input bytes\n"
+    "  -I <C,LF>\tInput channel config, default is 3,4 (Center third, LF fourth)\n"
+    "  --ignorelength\tIgnore wav length from header (useful with files over 4 GB)\n"
+    "\n"
+    "MP4 specific options:\n"
+    "  -w\t\tWrap AAC data in MP4 container. (default for *.mp4 and *.m4a)\n"
+    "  --artist X\tSet artist to X\n"
+    "  --composer X\tSet composer to X\n"
+    "  --title X\tSet title to X\n"
+    "  --genre X\tSet genre to X\n"
+    "  --album X\tSet album to X\n"
+    "  --compilation\tSet compilation\n"
+    "  --track X\tSet track to X (number/total)\n"
+    "  --disc X\tSet disc to X (number/total)\n"
+    "  --year X\tSet year to X\n"
+    "  --cover-art X\tRead cover art from file X\n"
+    "  --comment X\tSet comment to X\n"
+    "\n"
+    "Documentation:\n"
+    "  --license\tShow the FAAC license.\n"
+    "  --help\tShow this abbreviated help.\n"
+    "  --long-help\tShow complete help.\n"
+    "\n"
+    "  More tips can be found in the audiocoding.com Knowledge Base at\n"
+    "  <http://www.audiocoding.com/wiki/>\n" "\n";
 
 const char *long_help =
-  "Usage: %s [options] infiles ...\n"
-  "\n"
-  "Quality-related options:\n"
-  "  -q <quality>\tSet default variable bitrate (VBR) quantizer quality in percent.\n"
-  "\t\t(default: 100, averages at approx. 120 kbps VBR for a normal\n"
-  "\t\tstereo input file with 16 bit and 44.1 kHz sample rate; max.\n"
-  "\t\tvalue 500, min. 10).\n"
-  "  -b <bitrate>\tSet average bitrate (ABR) to approximately <bitrate> kbps.\n"
-"\t\t(max. value 152 kbps/stereo with a 16 kHz cutoff, can be raised\n"
-  "\t\twith a higher -c setting).\n"
-  "  -c <freq>\tSet the bandwidth in Hz (default: automatic, i.e. adapts\n"
-  "\t\tmaximum value to input sample rate).\n"
-  "\n"
-  "Input/output options:\n"
-  "  -\t\t<stdin/stdout>: If you simply use a hyphen/minus sign instead\n"
-  "\t\tof an input file name, FAAC can encode directly from stdin,\n"
-  "\t\tthus enabling piping from other applications and utilities. The\n"
-  "\t\tsame works for stdout as well, so FAAC can pipe its output to\n"
-  "\t\tother apps such as a server.\n"
-  "  -o X\t\tSet output file to X (only for one input file)\n"
-  "\t\tonly for one input file; you can use *.aac, *.mp4, *.m4a or\n"
-  "\t\t*.m4b as file extension, and the file format will be set\n"
-  "\t\tautomatically to ADTS or MP4).\n"
-  "  -P\t\tRaw PCM input mode (default: off, i.e. expecting a WAV header;\n"
-  "\t\tnecessary for input files or bitstreams without a header; using\n"
-  "\t\tonly -P assumes the default values for -R, -B and -C in the\n"
-  "\t\tinput file).\n"
-  "  -R\t\tRaw PCM input sample rate in Hz (default: 44100 Hz, max. 96 kHz)\n"
-  "  -B\t\tRaw PCM input sample size (default: 16, also possible 8, 24, 32\n"
-  "\t\tbit fixed or float input).\n"
-  "  -C\t\tRaw PCM input channels (default: 2, max. 33 + 1 LFE).\n"
-  "  -X\t\tRaw PCM swap input bytes (default: bigendian).\n"
-  "  -I <C[,LFE]>\tInput multichannel configuration (default: 3,4 which means\n"
-  "\t\tCenter is third and LFE is fourth like in 5.1 WAV, so you only\n"
-  "\t\thave to specify a different position of these two mono channels\n"
-  "\t\tin your multichannel input files if they haven't been reordered\n"
-  "\t\talready).\n"
-  "\n"
-  "MP4 specific options:\n"
-#ifdef HAVE_LIBMP4V2
-  "  -w\t\tWrap AAC data in MP4 container. (default for *.mp4, *.m4a and\n"
-  "\t\t*.m4b)\n"
-  "  -s\t\tOptimize MP4 container layout after encoding.\n"
-  "  --artist X\tSet artist to X\n"
-  "  --writer X\tSet writer/composer to X\n"
-  "  --title X\tSet title/track name to X\n"
-  "  --genre X\tSet genre to X\n"
-  "  --album X\tSet album/performer to X\n"
-  "  --compilation\tMark as compilation\n"
-  "  --track X\tSet track to X (number/total)\n"
-  "  --disc X\tSet disc to X (number/total)\n"
-  "  --year X\tSet year to X\n"
-  "  --cover-art X\tRead cover art from file X\n"
-  "\t\tSupported image formats are GIF, JPEG, and PNG.\n"
-  "  --comment X\tSet comment to X\n"
-#else
-  "  MP4 support unavailable.\n"
-#endif
-  "\n"
-  "Expert options, only for testing purposes:\n"
+    "Usage: %s [options] infiles ...\n"
+    "\n"
+    "Quality-related options:\n"
+    "  -q <quality>\tSet default variable bitrate (VBR) quantizer quality in percent.\n"
+    "\t\t(default: 100, averages at approx. 120 kbps VBR for a normal\n"
+    "\t\tstereo input file with 16 bit and 44.1 kHz sample rate; max.\n"
+    "\t\tvalue 500, min. 10).\n"
+    "  -b <bitrate>\tSet average bitrate (ABR) to approximately <bitrate> kbps.\n"
+    "\t\t(max. value 152 kbps/stereo with a 16 kHz cutoff, can be raised\n"
+    "\t\twith a higher -c setting).\n"
+    "  -c <freq>\tSet the bandwidth in Hz (default: automatic, i.e. adapts\n"
+    "\t\tmaximum value to input sample rate).\n"
+    "\n"
+    "Input/output options:\n"
+    "  -\t\t<stdin/stdout>: If you simply use a hyphen/minus sign instead\n"
+    "\t\tof an input file name, FAAC can encode directly from stdin,\n"
+    "\t\tthus enabling piping from other applications and utilities. The\n"
+    "\t\tsame works for stdout as well, so FAAC can pipe its output to\n"
+    "\t\tother apps such as a server.\n"
+    "  -o X\t\tSet output file to X (only for one input file)\n"
+    "\t\tonly for one input file; you can use *.aac, *.mp4, *.m4a or\n"
+    "\t\t*.m4b as file extension, and the file format will be set\n"
+    "\t\tautomatically to ADTS or MP4).\n"
+    "  -P\t\tRaw PCM input mode (default: off, i.e. expecting a WAV header;\n"
+    "\t\tnecessary for input files or bitstreams without a header; using\n"
+    "\t\tonly -P assumes the default values for -R, -B and -C in the\n"
+    "\t\tinput file).\n"
+    "  -R\t\tRaw PCM input sample rate in Hz (default: 44100 Hz, max. 96 kHz)\n"
+    "  -B\t\tRaw PCM input sample size (default: 16, also possible 8, 24, 32\n"
+    "\t\tbit fixed or float input).\n"
+    "  -C\t\tRaw PCM input channels (default: 2, max. 33 + 1 LFE).\n"
+    "  -X\t\tRaw PCM swap input bytes (default: bigendian).\n"
+    "  -I <C[,LFE]>\tInput multichannel configuration (default: 3,4 which means\n"
+    "\t\tCenter is third and LFE is fourth like in 5.1 WAV, so you only\n"
+    "\t\thave to specify a different position of these two mono channels\n"
+    "\t\tin your multichannel input files if they haven't been reordered\n"
+    "\t\talready).\n"
+    "\n"
+    "MP4 specific options:\n"
+    "  -w\t\tWrap AAC data in MP4 container. (default for *.mp4, *.m4a and\n"
+    "\t\t*.m4b)\n"
+    "  --artist X\tSet artist to X\n"
+    "  --composer X\tSet composer to X\n"
+    "  --title X\tSet title/track name to X\n"
+    "  --genre X\tSet genre to X\n"
+    "  --album X\tSet album/performer to X\n"
+    "  --compilation\tMark as compilation\n"
+    "  --track X\tSet track to X (number/total)\n"
+    "  --disc X\tSet disc to X (number/total)\n"
+    "  --year X\tSet year to X\n"
+    "  --cover-art X\tRead cover art from file X\n"
+    "\t\tSupported image formats are GIF, JPEG, and PNG.\n"
+    "  --comment X\tSet comment to X\n"
+    "\n" "Expert options, only for testing purposes:\n"
 #if !DEFAULT_TNS
-  "  --tns  \tEnable coding of TNS, temporal noise shaping.\n"
+    "  --tns  \tEnable coding of TNS, temporal noise shaping.\n"
 #else
-  "  --no-tns\tDisable coding of TNS, temporal noise shaping.\n"
+    "  --no-tns\tDisable coding of TNS, temporal noise shaping.\n"
 #endif
-  "  --no-midside\tDon\'t use mid/side coding.\n"
-  "  --mpeg-vers X\tForce AAC MPEG version, X can be 2 or 4\n"
-  "  --obj-type X\tAAC object type. (LC (Low Complexity, default), Main or LTP\n"
-  "\t\t(Long Term Prediction)\n"
-  "  --shortctl X\tEnforce block type (0 = both (default); 1 = no short; 2 = no\n"
-  "\t\tlong).\n"
-  "  -r\t\tGenerate raw AAC bitstream (i.e. without any headers).\n"
-  "\t\tNot advised!!!, RAW AAC files are practically useless!!!\n"
-  "\n"
-  "Documentation:\n"
-  "  --license\tShow the FAAC license.\n"
-  "  --help\tShow this abbreviated help.\n"
-  "  --long-help\tShow complete help.\n"
-  "\n"
-  "  More tips can be found in the audiocoding.com Knowledge Base at\n"
-  "  <http://www.audiocoding.com/wiki/>\n"
-  "\n";
+    "  --no-midside\tDon\'t use mid/side coding.\n"
+    "  --mpeg-vers X\tForce AAC MPEG version, X can be 2 or 4\n"
+    "  --obj-type X\tAAC object type. (LC (Low Complexity, default), Main or LTP\n"
+    "\t\t(Long Term Prediction)\n"
+    "  --shortctl X\tEnforce block type (0 = both (default); 1 = no short; 2 = no\n"
+    "\t\tlong).\n"
+    "  -r\t\tGenerate raw AAC bitstream (i.e. without any headers).\n"
+    "\t\tNot advised!!!, RAW AAC files are practically useless!!!\n"
+    "\n"
+    "Documentation:\n"
+    "  --license\tShow the FAAC license.\n"
+    "  --help\tShow this abbreviated help.\n"
+    "  --long-help\tShow complete help.\n"
+    "\n"
+    "  More tips can be found in the audiocoding.com Knowledge Base at\n"
+    "  <http://www.audiocoding.com/wiki/>\n" "\n";
 
 char *license =
-  "\nPlease note that the use of this software may require the payment of patent\n"
-  "royalties. You need to consider this issue before you start building derivative\n"
-  "works. We are not warranting or indemnifying you in any way for patent\n"
-  "royalities! YOU ARE SOLELY RESPONSIBLE FOR YOUR OWN ACTIONS!\n"
-  "\n"
-  "FAAC is based on the ISO MPEG-4 reference code. For this code base the\n"
-  "following license applies:\n"
-  "\n"
-  "This software module was originally developed by\n"
-  "\n"
-  "FirstName LastName (CompanyName)\n"
-  "\n"
-  "and edited by\n"
-  "\n"
-  "FirstName LastName (CompanyName)\n"
-  "FirstName LastName (CompanyName)\n"
-  "\n"
-  "in the course of development of the MPEG-2 NBC/MPEG-4 Audio standard\n"
-  "ISO/IEC 13818-7, 14496-1,2 and 3. This software module is an\n"
-  "implementation of a part of one or more MPEG-2 NBC/MPEG-4 Audio tools\n"
-  "as specified by the MPEG-2 NBC/MPEG-4 Audio standard. ISO/IEC gives\n"
-  "users of the MPEG-2 NBC/MPEG-4 Audio standards free license to this\n"
-  "software module or modifications thereof for use in hardware or\n"
-  "software products claiming conformance to the MPEG-2 NBC/ MPEG-4 Audio\n"
-  "standards. Those intending to use this software module in hardware or\n"
-  "software products are advised that this use may infringe existing\n"
-  "patents. The original developer of this software module and his/her\n"
-  "company, the subsequent editors and their companies, and ISO/IEC have\n"
-  "no liability for use of this software module or modifications thereof\n"
-  "in an implementation. Copyright is not released for non MPEG-2\n"
-  "NBC/MPEG-4 Audio conforming products. The original developer retains\n"
-  "full right to use the code for his/her own purpose, assign or donate\n"
-  "the code to a third party and to inhibit third party from using the\n"
-  "code for non MPEG-2 NBC/MPEG-4 Audio conforming products. This\n"
-  "copyright notice must be included in all copies or derivative works.\n"
-  "\n"
-  "Copyright (c) 1997.\n"
-  "\n"
-  "For the changes made for the FAAC project the GNU Lesser General Public\n"
-  "License (LGPL), version 2 1991 applies:\n"
-  "\n"
-  "FAAC - Freeware Advanced Audio Coder\n"
-  "Copyright (C) 2001-2004 The individual contributors\n"
-  "\n"
-  "This library is free software; you can redistribute it and/or\n"
-  "modify it under the terms of the GNU Lesser General Public\n"
-  "License as published by the Free Software Foundation; either\n"
-  "version 2.1 of the License, or (at your option) any later version.\n"
-  "\n"
-  "This library is distributed in the hope that it will be useful,\n"
-  "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
-  "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
-  "Lesser General Public License for more details.\n"
-  "\n"
-  "You should have received a copy of the GNU Lesser General Public\n"
-  "License along with this library; if not, write to the Free Software\n"
-  "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
-  "\n";
+    "\nPlease note that the use of this software may require the payment of patent\n"
+    "royalties. You need to consider this issue before you start building derivative\n"
+    "works. We are not warranting or indemnifying you in any way for patent\n"
+    "royalities! YOU ARE SOLELY RESPONSIBLE FOR YOUR OWN ACTIONS!\n"
+    "\n"
+    "FAAC is based on the ISO MPEG-4 reference code. For this code base the\n"
+    "following license applies:\n"
+    "\n"
+    "This software module was originally developed by\n"
+    "\n"
+    "FirstName LastName (CompanyName)\n"
+    "\n"
+    "and edited by\n"
+    "\n"
+    "FirstName LastName (CompanyName)\n"
+    "FirstName LastName (CompanyName)\n"
+    "\n"
+    "in the course of development of the MPEG-2 NBC/MPEG-4 Audio standard\n"
+    "ISO/IEC 13818-7, 14496-1,2 and 3. This software module is an\n"
+    "implementation of a part of one or more MPEG-2 NBC/MPEG-4 Audio tools\n"
+    "as specified by the MPEG-2 NBC/MPEG-4 Audio standard. ISO/IEC gives\n"
+    "users of the MPEG-2 NBC/MPEG-4 Audio standards free license to this\n"
+    "software module or modifications thereof for use in hardware or\n"
+    "software products claiming conformance to the MPEG-2 NBC/ MPEG-4 Audio\n"
+    "standards. Those intending to use this software module in hardware or\n"
+    "software products are advised that this use may infringe existing\n"
+    "patents. The original developer of this software module and his/her\n"
+    "company, the subsequent editors and their companies, and ISO/IEC have\n"
+    "no liability for use of this software module or modifications thereof\n"
+    "in an implementation. Copyright is not released for non MPEG-2\n"
+    "NBC/MPEG-4 Audio conforming products. The original developer retains\n"
+    "full right to use the code for his/her own purpose, assign or donate\n"
+    "the code to a third party and to inhibit third party from using the\n"
+    "code for non MPEG-2 NBC/MPEG-4 Audio conforming products. This\n"
+    "copyright notice must be included in all copies or derivative works.\n"
+    "\n"
+    "Copyright (c) 1997.\n"
+    "\n"
+    "For the changes made for the FAAC project the GNU Lesser General Public\n"
+    "License (LGPL), version 2 1991 applies:\n"
+    "\n"
+    "FAAC - Freeware Advanced Audio Coder\n"
+    "Copyright (C) 2001-2004 The individual contributors\n"
+    "\n"
+    "This library is free software; you can redistribute it and/or\n"
+    "modify it under the terms of the GNU Lesser General Public\n"
+    "License as published by the Free Software Foundation; either\n"
+    "version 2.1 of the License, or (at your option) any later version.\n"
+    "\n"
+    "This library is distributed in the hope that it will be useful,\n"
+    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
+    "Lesser General Public License for more details.\n"
+    "\n"
+    "You should have received a copy of the GNU Lesser General Public\n"
+    "License along with this library; if not, write to the Free Software\n"
+    "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
+    "\n";
 
 #ifndef min
 #define min(a,b) ( (a) < (b) ? (a) : (b) )
@@ -286,66 +267,65 @@
 #endif
 
 /* globals */
-char* progName;
+char *progName;
 #ifndef _WIN32
 volatile int running = 1;
 #endif
 
-enum stream_format {
-  RAW_STREAM = 0,
-  ADTS_STREAM = 1,
+enum stream_format
+{
+    RAW_STREAM = 0,
+    ADTS_STREAM = 1,
 };
 
-enum container_format {
-  NO_CONTAINER,
-#ifdef HAVE_LIBMP4V2
-  MP4_CONTAINER,
-#endif
+enum container_format
+{
+    NO_CONTAINER,
+    MP4_CONTAINER,
 };
 
-enum flags {
-  SHORTCTL_FLAG = 300,
-  TNS_FLAG,
-  NO_TNS_FLAG,
-  MPEGVERS_FLAG,
-  OBJTYPE_FLAG,
-  NO_MIDSIDE_FLAG,
-  IGNORELEN_FLAG,
+enum flags
+{
+    SHORTCTL_FLAG = 300,
+    TNS_FLAG,
+    NO_TNS_FLAG,
+    MPEGVERS_FLAG,
+    OBJTYPE_FLAG,
+    NO_MIDSIDE_FLAG,
+    IGNORELEN_FLAG,
 
-#ifdef HAVE_LIBMP4V2
-  ARTIST_FLAG,
-  TITLE_FLAG,
-  GENRE_FLAG,
-  ALBUM_FLAG,
-  COMPILATION_FLAG,
-  TRACK_FLAG,
-  DISC_FLAG,
-  YEAR_FLAG,
-  COVER_ART_FLAG,
-  COMMENT_FLAG,
-  WRITER_FLAG,
-#endif
+    ARTIST_FLAG,
+    TITLE_FLAG,
+    GENRE_FLAG,
+    ALBUM_FLAG,
+    COMPILATION_FLAG,
+    TRACK_FLAG,
+    DISC_FLAG,
+    YEAR_FLAG,
+    COVER_ART_FLAG,
+    COMMENT_FLAG,
+    WRITER_FLAG,
 };
 
 #ifndef _WIN32
-void signal_handler(int signal) {
+void signal_handler(int signal)
+{
     running = 0;
 }
 #endif
 
-#ifdef HAVE_LIBMP4V2
-static int check_image_header(const char *buf) {
-  if (!strncmp(buf, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8))
-    return 1; /* PNG */
-  else if (!strncmp(buf, "\xFF\xD8\xFF\xE0", 4) ||
-       !strncmp(buf, "\xFF\xD8\xFF\xE1", 4))
-    return 1; /* JPEG */
-  else if (!strncmp(buf, "GIF87a", 6) || !strncmp(buf, "GIF89a", 6))
-    return 1; /* GIF */
-  else
-    return 0;
+static int check_image_header(const char *buf)
+{
+    if (!strncmp(buf, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8))
+        return 1;               /* PNG */
+    else if (!strncmp(buf, "\xFF\xD8\xFF\xE0", 4) ||
+             !strncmp(buf, "\xFF\xD8\xFF\xE1", 4))
+        return 1;               /* JPEG */
+    else if (!strncmp(buf, "GIF87a", 6) || !strncmp(buf, "GIF89a", 6))
+        return 1;               /* GIF */
+    else
+        return 0;
 }
-#endif
 
 static int *mkChanMap(int channels, int center, int lf)
 {
@@ -362,12 +342,12 @@
     if (lf > 0)
         lf--;
     else
-        lf = channels - 1; // default AAC position
+        lf = channels - 1;      // default AAC position
 
     if (center > 0)
         center--;
     else
-        center = 0; // default AAC position
+        center = 0;             // default AAC position
 
     map = malloc(channels * sizeof(map[0]));
     memset(map, 0, channels * sizeof(map[0]));
@@ -403,7 +383,7 @@
     faacEncHandle hEncoder;
     pcmfile_t *infile = NULL;
 
-    unsigned long samplesInput, maxBytesOutput, totalBytesWritten=0;
+    unsigned long samplesInput, maxBytesOutput, totalBytesWritten = 0;
 
     faacEncConfigurationPtr myFormat;
     unsigned int mpegVersion = MPEG2;
@@ -430,7 +410,7 @@
     int samplesRead = 0;
     const char *dieMessage = NULL;
 
-    int rawChans = 0; // disabled by default
+    int rawChans = 0;           // disabled by default
     int rawBits = 16;
     int rawRate = 44100;
     int rawEndian = 1;
@@ -439,22 +419,17 @@
 
     FILE *outfile = NULL;
 
-#ifdef HAVE_LIBMP4V2
-    int optimizeFlag = 0;
-    MP4FileHandle MP4hFile = MP4_INVALID_FILE_HANDLE;
-    MP4TrackId MP4track = 0;
     unsigned int ntracks = 0, trackno = 0;
     unsigned int ndiscs = 0, discno = 0;
     u_int8_t compilation = 0;
     const char *artist = NULL, *title = NULL, *album = NULL, *year = NULL,
-      *genre = NULL, *comment = NULL, *writer = NULL;
-    u_int8_t *art = NULL;
+        *genre = NULL, *comment = NULL, *composer = NULL;
+    uint8_t *art = NULL;
     u_int64_t artSize = 0;
     u_int64_t encoded_samples = 0;
     unsigned int delay_samples;
     unsigned int frameSize;
-#endif
-    u_int64_t total_samples = 0;
+    u_int64_t input_samples = 0;
     char *faac_id_string;
     char *faac_copyright_string;
     int ignorelen = FALSE;
@@ -466,9 +441,11 @@
 #endif
 
     // get faac version
-    if (faacEncGetVersion(&faac_id_string, &faac_copyright_string) == FAAC_CFG_VERSION)
+    if (faacEncGetVersion(&faac_id_string, &faac_copyright_string) ==
+        FAAC_CFG_VERSION)
     {
-        fprintf(stderr, "Freeware Advanced Audio Coder\nFAAC %s\n\n", faac_id_string);
+        fprintf(stderr, "Freeware Advanced Audio Coder\nFAAC %s\n\n",
+                faac_id_string);
     }
     else
     {
@@ -478,51 +455,46 @@
 
     /* begin process command line */
     progName = argv[0];
-    while (1) {
+    while (1)
+    {
         static struct option long_options[] = {
-            { "help", 0, 0, 'h'},
-            { "long-help", 0, 0, 'H'},
-            { "raw", 0, 0, 'r'},
-            { "no-midside", 0, 0, NO_MIDSIDE_FLAG},
-            { "cutoff", 1, 0, 'c'},
-            { "quality", 1, 0, 'q'},
-            { "pcmraw", 0, 0, 'P'},
-            { "pcmsamplerate", 1, 0, 'R'},
-            { "pcmsamplebits", 1, 0, 'B'},
-            { "pcmchannels", 1, 0, 'C'},
-            { "shortctl", 1, 0, SHORTCTL_FLAG},
-            { "tns", 0, 0, TNS_FLAG},
-            { "no-tns", 0, 0, NO_TNS_FLAG},
-            { "mpeg-version", 1, 0, MPEGVERS_FLAG},
-            { "obj-type", 1, 0, OBJTYPE_FLAG},
-            { "license", 0, 0, 'L'},
-#ifdef HAVE_LIBMP4V2
-            { "createmp4", 0, 0, 'w'},
-            { "optimize", 0, 0, 's'},
-            { "artist", 1, 0, ARTIST_FLAG},
-            { "title", 1, 0, TITLE_FLAG},
-            { "album", 1, 0, ALBUM_FLAG},
-            { "track", 1, 0, TRACK_FLAG},
-            { "disc", 1, 0, DISC_FLAG},
-            { "genre", 1, 0, GENRE_FLAG},
-            { "year", 1, 0, YEAR_FLAG},
-            { "cover-art", 1, 0, COVER_ART_FLAG},
-            { "comment", 1, 0, COMMENT_FLAG},
-        { "writer", 1, 0, WRITER_FLAG},
-        { "compilation", 0, 0, COMPILATION_FLAG},
-#endif
-        { "pcmswapbytes", 0, 0, 'X'},
-        { "ignorelength", 0, 0, IGNORELEN_FLAG},
-            { 0, 0, 0, 0}
+            {"help", 0, 0, 'h'},
+            {"long-help", 0, 0, 'H'},
+            {"raw", 0, 0, 'r'},
+            {"no-midside", 0, 0, NO_MIDSIDE_FLAG},
+            {"cutoff", 1, 0, 'c'},
+            {"quality", 1, 0, 'q'},
+            {"pcmraw", 0, 0, 'P'},
+            {"pcmsamplerate", 1, 0, 'R'},
+            {"pcmsamplebits", 1, 0, 'B'},
+            {"pcmchannels", 1, 0, 'C'},
+            {"shortctl", 1, 0, SHORTCTL_FLAG},
+            {"tns", 0, 0, TNS_FLAG},
+            {"no-tns", 0, 0, NO_TNS_FLAG},
+            {"mpeg-version", 1, 0, MPEGVERS_FLAG},
+            {"obj-type", 1, 0, OBJTYPE_FLAG},
+            {"license", 0, 0, 'L'},
+            {"createmp4", 0, 0, 'w'},
+            {"artist", 1, 0, ARTIST_FLAG},
+            {"title", 1, 0, TITLE_FLAG},
+            {"album", 1, 0, ALBUM_FLAG},
+            {"track", 1, 0, TRACK_FLAG},
+            {"disc", 1, 0, DISC_FLAG},
+            {"genre", 1, 0, GENRE_FLAG},
+            {"year", 1, 0, YEAR_FLAG},
+            {"cover-art", 1, 0, COVER_ART_FLAG},
+            {"comment", 1, 0, COMMENT_FLAG},
+            {"composer", 1, 0, WRITER_FLAG},
+            {"compilation", 0, 0, COMPILATION_FLAG},
+            {"pcmswapbytes", 0, 0, 'X'},
+            {"ignorelength", 0, 0, IGNORELEN_FLAG},
+            {0, 0, 0, 0}
         };
         int c = -1;
         int option_index = 0;
 
-        c = getopt_long(argc, argv, "Hhb:m:o:rnc:q:PR:B:C:I:X"
-#ifdef HAVE_LIBMP4V2
-                        "ws"
-#endif
-            ,long_options, &option_index);
+        c = getopt_long(argc, argv, "Hhb:m:o:rnc:q:PR:B:C:I:Xw",
+                        long_options, &option_index);
 
         if (c == -1)
             break;
@@ -529,162 +501,171 @@
 
         if (!c)
         {
-          dieMessage = usage;
-          break;
+            dieMessage = usage;
+            break;
         }
 
-        switch (c) {
-    case 'o':
+        switch (c)
         {
-            int l = strlen(optarg);
-        aacFileName = malloc(l+1);
-        memcpy(aacFileName, optarg, l);
-        aacFileName[l] = '\0';
-        aacFileNameGiven = 1;
-        }
-        break;
-        case 'r': {
-            stream = RAW_STREAM;
-            break;
-        }
-        case NO_MIDSIDE_FLAG: {
-            useMidSide = 0;
-            break;
-        }
-        case 'c': {
-            unsigned int i;
-            if (sscanf(optarg, "%u", &i) > 0) {
-                cutOff = i;
+        case 'o':
+            {
+                int l = strlen(optarg);
+                aacFileName = malloc(l + 1);
+                memcpy(aacFileName, optarg, l);
+                aacFileName[l] = '\0';
+                aacFileNameGiven = 1;
             }
             break;
-        }
-        case 'b': {
-            unsigned int i;
-            if (sscanf(optarg, "%u", &i) > 0)
+        case 'r':
             {
-                bitRate = 1000 * i;
+                stream = RAW_STREAM;
+                break;
             }
-            break;
-        }
+        case NO_MIDSIDE_FLAG:
+            {
+                useMidSide = 0;
+                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)
+                {
+                    bitRate = 1000 * i;
+                }
+                break;
+            }
         case 'q':
-        {
-            unsigned int i;
-            if (sscanf(optarg, "%u", &i) > 0)
             {
-                if (i > 0 && i < 1000)
-                    quantqual = i;
+                unsigned int i;
+                if (sscanf(optarg, "%u", &i) > 0)
+                {
+                    if (i > 0 && i < 1000)
+                        quantqual = i;
+                }
+                break;
             }
-            break;
-        }
         case 'I':
             sscanf(optarg, "%d,%d", &chanC, &chanLF);
             break;
         case 'P':
-            rawChans = 2; // enable raw input
+            rawChans = 2;       // enable raw input
             break;
         case 'R':
-        {
-            unsigned int i;
-            if (sscanf(optarg, "%u", &i) > 0)
             {
-                rawRate = i;
-                rawChans = (rawChans > 0) ? rawChans : 2;
+                unsigned int i;
+                if (sscanf(optarg, "%u", &i) > 0)
+                {
+                    rawRate = i;
+                    rawChans = (rawChans > 0) ? rawChans : 2;
+                }
+                break;
             }
-            break;
-        }
         case 'B':
-        {
-            unsigned int i;
-            if (sscanf(optarg, "%u", &i) > 0)
             {
-                if (i > 32)
-                    i = 32;
-                if (i < 8)
-                    i = 8;
-                rawBits = i;
-                rawChans = (rawChans > 0) ? rawChans : 2;
+                unsigned int i;
+                if (sscanf(optarg, "%u", &i) > 0)
+                {
+                    if (i > 32)
+                        i = 32;
+                    if (i < 8)
+                        i = 8;
+                    rawBits = i;
+                    rawChans = (rawChans > 0) ? rawChans : 2;
+                }
+                break;
             }
-            break;
-        }
         case 'C':
-        {
-            unsigned int i;
-            if (sscanf(optarg, "%u", &i) > 0)
-                rawChans = i;
-            break;
-        }
-#ifdef HAVE_LIBMP4V2
+            {
+                unsigned int i;
+                if (sscanf(optarg, "%u", &i) > 0)
+                    rawChans = i;
+                break;
+            }
         case 'w':
-        container = MP4_CONTAINER;
+            container = MP4_CONTAINER;
             break;
-        case 's':
-        optimizeFlag = 1;
+        case ARTIST_FLAG:
+            artist = optarg;
             break;
-    case ARTIST_FLAG:
-        artist = optarg;
-        break;
-    case WRITER_FLAG:
-        writer = optarg;
-        break;
-    case TITLE_FLAG:
-        title = optarg;
-        break;
-    case ALBUM_FLAG:
-        album = optarg;
-        break;
-    case TRACK_FLAG:
-        sscanf(optarg, "%d/%d", &trackno, &ntracks);
-        break;
-    case DISC_FLAG:
-        sscanf(optarg, "%d/%d", &discno, &ndiscs);
-        break;
-    case COMPILATION_FLAG:
-        compilation = 0x1;
-        break;
-    case GENRE_FLAG:
-        genre = optarg;
-        break;
-    case YEAR_FLAG:
-        year = optarg;
-        break;
-    case COMMENT_FLAG:
-        comment = optarg;
-        break;
-    case COVER_ART_FLAG: {
-        FILE *artFile = fopen(optarg, "rb");
+        case WRITER_FLAG:
+            composer = optarg;
+            break;
+        case TITLE_FLAG:
+            title = optarg;
+            break;
+        case ALBUM_FLAG:
+            album = optarg;
+            break;
+        case TRACK_FLAG:
+            sscanf(optarg, "%d/%d", &trackno, &ntracks);
+            break;
+        case DISC_FLAG:
+            sscanf(optarg, "%d/%d", &discno, &ndiscs);
+            break;
+        case COMPILATION_FLAG:
+            compilation = 0x1;
+            break;
+        case GENRE_FLAG:
+            genre = optarg;
+            break;
+        case YEAR_FLAG:
+            year = optarg;
+            break;
+        case COMMENT_FLAG:
+            comment = optarg;
+            break;
+        case COVER_ART_FLAG:
+            {
+                FILE *artFile = fopen(optarg, "rb");
 
-        if(artFile) {
-            u_int64_t r;
+                if (artFile)
+                {
+                    u_int64_t r;
 
-            fseek(artFile, 0, SEEK_END);
-        artSize = ftell(artFile);
+                    fseek(artFile, 0, SEEK_END);
+                    artSize = ftell(artFile);
 
-        art = malloc(artSize);
+                    art = malloc(artSize);
 
-            fseek(artFile, 0, SEEK_SET);
-        clearerr(artFile);
+                    fseek(artFile, 0, SEEK_SET);
+                    clearerr(artFile);
 
-        r = fread(art, artSize, 1, artFile);
+                    r = fread(art, artSize, 1, artFile);
 
-        if (r != 1) {
-            dieMessage = "Error reading cover art file!\n";
-            free(art);
-            art = NULL;
-        } else if (artSize < 12 || !check_image_header(art)) {
-            /* the above expression checks the image signature */
-            dieMessage = "Unsupported cover image file format!\n";
-            free(art);
-            art = NULL;
-        }
+                    if (r != 1)
+                    {
+                        dieMessage = "Error reading cover art file!\n";
+                        free(art);
+                        art = NULL;
+                    }
+                    else if (artSize < 12
+                             || !check_image_header((const char *) art))
+                    {
+                        /* the above expression checks the image signature */
+                        dieMessage = "Unsupported cover image file format!\n";
+                        free(art);
+                        art = NULL;
+                    }
 
-        fclose(artFile);
-        } else {
-            dieMessage = "Error opening cover art file!\n";
-        }
+                    fclose(artFile);
+                }
+                else
+                {
+                    dieMessage = "Error opening cover art file!\n";
+                }
 
-        break;
-    }
-#endif
+                break;
+            }
         case SHORTCTL_FLAG:
             shortctl = atoi(optarg);
             break;
@@ -697,9 +678,9 @@
         case IGNORELEN_FLAG:
             ignorelen = TRUE;
             break;
-    case MPEGVERS_FLAG:
+        case MPEGVERS_FLAG:
             mpegVersion = atoi(optarg);
-            switch(mpegVersion)
+            switch (mpegVersion)
             {
             case 2:
                 mpegVersion = MPEG2;
@@ -708,151 +689,150 @@
                 mpegVersion = MPEG4;
                 break;
             default:
-            dieMessage = "Unrecognised MPEG version!\n";
+                dieMessage = "Unrecognised MPEG version!\n";
             }
             break;
 #if 0
-    case OBJTYPE_FLAG:
-        if (!strcasecmp(optarg, "LC"))
+        case OBJTYPE_FLAG:
+            if (!strcasecmp(optarg, "LC"))
                 objectType = LOW;
-        else if (!strcasecmp(optarg, "Main"))
-            objectType = MAIN;
-        else if (!strcasecmp(optarg, "LTP")) {
-            mpegVersion = MPEG4;
-        objectType = LTP;
-        } else
-            dieMessage = "Unrecognised object type!\n";
-        break;
+            else if (!strcasecmp(optarg, "Main"))
+                objectType = MAIN;
+            else if (!strcasecmp(optarg, "LTP"))
+            {
+                mpegVersion = MPEG4;
+                objectType = LTP;
+            }
+            else
+                dieMessage = "Unrecognised object type!\n";
+            break;
 #endif
         case 'L':
-        fprintf(stderr, "%s", faac_copyright_string);
-        dieMessage = license;
-        break;
-    case 'X':
-      rawEndian = 0;
-      break;
-    case 'H':
-      dieMessage = long_help;
-      break;
-    case 'h':
-          dieMessage = short_help;
-      break;
-    case '?':
+            fprintf(stderr, "%s", faac_copyright_string);
+            dieMessage = license;
+            break;
+        case 'X':
+            rawEndian = 0;
+            break;
+        case 'H':
+            dieMessage = long_help;
+            break;
+        case 'h':
+            dieMessage = short_help;
+            break;
+        case '?':
         default:
-      dieMessage = usage;
-          break;
+            dieMessage = usage;
+            break;
         }
     }
 
     /* check that we have at least one non-option arguments */
     if (!dieMessage && (argc - optind) > 1 && aacFileNameGiven)
-        dieMessage = "Cannot encode several input files to one output file.\n";
+        dieMessage =
+            "Cannot encode several input files to one output file.\n";
 
     if (argc - optind < 1 || dieMessage)
     {
         fprintf(stderr, dieMessage ? dieMessage : usage,
-           progName, progName, progName, progName);
+                progName, progName, progName, progName);
         return 1;
     }
 
-    while (argc - optind > 0) {
+    while (argc - optind > 0)
+    {
+        /* get the input file name */
+        audioFileName = argv[optind++];
+    }
 
-    /* get the input file name */
-    audioFileName = argv[optind++];
-
     /* generate the output file name, if necessary */
-    if (!aacFileNameGiven) {
+    if (!aacFileNameGiven)
+    {
         char *t = strrchr(audioFileName, '.');
-    int l = t ? strlen(audioFileName) - strlen(t) : strlen(audioFileName);
+        int l = t ? strlen(audioFileName) - strlen(t) : strlen(audioFileName);
 
-#ifdef HAVE_LIBMP4V2
-    aacFileExt = container == MP4_CONTAINER ? ".m4a" : ".aac";
-#else
-    aacFileExt = ".aac";
-#endif
+        aacFileExt = container == MP4_CONTAINER ? ".m4a" : ".aac";
 
-    aacFileName = malloc(l+1+4);
-    memcpy(aacFileName, audioFileName, l);
-    memcpy(aacFileName + l, aacFileExt, 4);
-    aacFileName[l+4] = '\0';
-    } else {
+        aacFileName = malloc(l + 1 + 4);
+        memcpy(aacFileName, audioFileName, l);
+        memcpy(aacFileName + l, aacFileExt, 4);
+        aacFileName[l + 4] = '\0';
+    }
+    else
+    {
         aacFileExt = strrchr(aacFileName, '.');
 
-        if (aacFileExt && (!strcmp(".m4a", aacFileExt) || !strcmp(".m4b", aacFileExt) || !strcmp(".mp4", aacFileExt)))
-#ifndef HAVE_LIBMP4V2
-        fprintf(stderr, "WARNING: MP4 support unavailable!\n");
-#else
-        container = MP4_CONTAINER;
-#endif
+        if (aacFileExt
+            && (!strcmp(".m4a", aacFileExt) || !strcmp(".m4b", aacFileExt)
+                || !strcmp(".mp4", aacFileExt)))
+            container = MP4_CONTAINER;
     }
 
     /* open the audio input file */
-    if (rawChans > 0) // use raw input
+    if (rawChans > 0)           // use raw input
     {
         infile = wav_open_read(audioFileName, 1);
-    if (infile)
-    {
-        infile->bigendian = rawEndian;
-        infile->channels = rawChans;
-        infile->samplebytes = rawBits / 8;
-        infile->samplerate = rawRate;
-        infile->samples /= (infile->channels * infile->samplebytes);
+        if (infile)
+        {
+            infile->bigendian = rawEndian;
+            infile->channels = rawChans;
+            infile->samplebytes = rawBits / 8;
+            infile->samplerate = rawRate;
+            infile->samples /= (infile->channels * infile->samplebytes);
+        }
     }
-    }
-    else // header input
+    else                        // header input
         infile = wav_open_read(audioFileName, 0);
 
     if (infile == NULL)
     {
         fprintf(stderr, "Couldn't open input file %s\n", audioFileName);
-    return 1;
+        return 1;
     }
 
-
     /* open the encoder library */
     hEncoder = faacEncOpen(infile->samplerate, infile->channels,
-        &samplesInput, &maxBytesOutput);
+                           &samplesInput, &maxBytesOutput);
 
     if (hEncoder == NULL)
     {
-        fprintf(stderr, "Couldn't open encoder instance for input file %s\n", audioFileName);
+        fprintf(stderr, "Couldn't open encoder instance for input file %s\n",
+                audioFileName);
         wav_close(infile);
         return 1;
     }
 
-#ifdef HAVE_LIBMP4V2
     if (container != MP4_CONTAINER && (ntracks || trackno || artist ||
-                       title ||  album || year || art ||
-                       genre || comment || discno || ndiscs ||
-                       writer || compilation))
+                                       title || album || year || art ||
+                                       genre || comment || discno || ndiscs ||
+                                       composer || compilation))
     {
         fprintf(stderr, "Metadata requires MP4 output!\n");
-    return 1;
+        return 1;
     }
 
     if (container == MP4_CONTAINER)
     {
         mpegVersion = MPEG4;
-    stream = RAW_STREAM;
+        stream = RAW_STREAM;
     }
 
-    frameSize = samplesInput/infile->channels;
-    delay_samples = frameSize; // encoder delay 1024 samples
-#endif
-    pcmbuf = (float *)malloc(samplesInput*sizeof(float));
-    bitbuf = (unsigned char*)malloc(maxBytesOutput*sizeof(unsigned char));
+    frameSize = samplesInput / infile->channels;
+    delay_samples = frameSize;  // encoder delay 1024 samples
+    pcmbuf = (float *) malloc(samplesInput * sizeof(float));
+    bitbuf = (unsigned char *) malloc(maxBytesOutput * sizeof(unsigned char));
     chanmap = mkChanMap(infile->channels, chanC, chanLF);
     if (chanmap)
     {
         fprintf(stderr, "Remapping input channels: Center=%d, LFE=%d\n",
-            chanC, chanLF);
+                chanC, chanLF);
     }
 
     if (cutOff <= 0)
     {
-        if (cutOff < 0) // default
+        if (cutOff < 0)         // default
             cutOff = 0;
-        else // disabled
+        else                    // disabled
             cutOff = infile->samplerate / 2;
     }
     if (cutOff > (infile->samplerate / 2))
@@ -866,13 +846,13 @@
     switch (shortctl)
     {
     case SHORTCTL_NOSHORT:
-      fprintf(stderr, "disabling short blocks\n");
-      myFormat->shortctl = shortctl;
-      break;
+        fprintf(stderr, "disabling short blocks\n");
+        myFormat->shortctl = shortctl;
+        break;
     case SHORTCTL_NOLONG:
-      fprintf(stderr, "disabling long blocks\n");
-      myFormat->shortctl = shortctl;
-      break;
+        fprintf(stderr, "disabling long blocks\n");
+        myFormat->shortctl = shortctl;
+        break;
     }
     if (infile->channels >= 6)
         myFormat->useLfe = 1;
@@ -884,115 +864,34 @@
         myFormat->quantqual = quantqual;
     myFormat->outputFormat = stream;
     myFormat->inputFormat = FAAC_INPUT_FLOAT;
-    if (!faacEncSetConfiguration(hEncoder, myFormat)) {
+    if (!faacEncSetConfiguration(hEncoder, myFormat))
+    {
         fprintf(stderr, "Unsupported output format!\n");
-#ifdef HAVE_LIBMP4V2
-#ifdef MP4_CLOSE_DO_NOT_COMPUTE_BITRATE /* r479 fix */
-        if (container == MP4_CONTAINER) MP4Close(MP4hFile, 0);
-#else
-        if (container == MP4_CONTAINER) MP4Close(MP4hFile);
-#endif
-#endif
         return 1;
     }
 
-#ifdef HAVE_LIBMP4V2
     /* initialize MP4 creation */
-    if (container == MP4_CONTAINER) {
-        unsigned char *ASC = 0;
-        unsigned long ASCLength = 0;
-    char *version_string;
-
-    if (!strcmp(aacFileName, "-"))
+    if (container == MP4_CONTAINER)
     {
-	fprintf(stderr, "cannot encode MP4 to stdout\n");
-        return 1;
-    }
+        if (!strcmp(aacFileName, "-"))
+        {
+            fprintf(stderr, "cannot encode MP4 to stdout\n");
+            return 1;
+        }
 
-#ifdef MP4_DETAILS_ERROR /* r453 fix */
-        MP4hFile = MP4Create(aacFileName, MP4_DETAILS_ERROR, 0);
-#else
-        MP4hFile = MP4Create(aacFileName, 0);
-#endif
-        if (!MP4_IS_VALID_FILE_HANDLE(MP4hFile)) {
+        if (mp4atom_open(aacFileName))
+        {
             fprintf(stderr, "Couldn't create output file %s\n", aacFileName);
             return 1;
         }
+        mp4atom_head();
 
-        MP4SetTimeScale(MP4hFile, 90000);
-        MP4track = MP4AddAudioTrack(MP4hFile, infile->samplerate, MP4_INVALID_DURATION, MP4_MPEG4_AUDIO_TYPE);
-        MP4SetAudioProfileLevel(MP4hFile, 0x0F);
-        faacEncGetDecoderSpecificInfo(hEncoder, &ASC, &ASCLength);
-        MP4SetTrackESConfiguration(MP4hFile, MP4track, ASC, ASCLength);
-    free(ASC);
-
-    /* set metadata */
-#if HAVE_DECL_MP4TAGSALLOC
-    const MP4Tags* tags;
-    tags = MP4TagsAlloc();
-    MP4TagsFetch( tags, MP4hFile );
-#endif
-    version_string = malloc(strlen(faac_id_string) + 6);
-    strcpy(version_string, "FAAC ");
-    strcpy(version_string + 5, faac_id_string);
-#if !HAVE_DECL_MP4TAGSALLOC
-    MP4SetMetadataTool(MP4hFile, version_string);
-#else
-    MP4TagsSetEncodingTool(tags, version_string);
-#endif
-    free(version_string);
-
-#if !HAVE_DECL_MP4TAGSALLOC
-    if (artist) MP4SetMetadataArtist(MP4hFile, artist);
-    if (writer) MP4SetMetadataWriter(MP4hFile, writer);
-    if (title) MP4SetMetadataName(MP4hFile, title);
-    if (album) MP4SetMetadataAlbum(MP4hFile, album);
-    if (trackno > 0) MP4SetMetadataTrack(MP4hFile, trackno, ntracks);
-    if (discno > 0) MP4SetMetadataDisk(MP4hFile, discno, ndiscs);
-    if (compilation) MP4SetMetadataCompilation(MP4hFile, compilation);
-    if (year) MP4SetMetadataYear(MP4hFile, year);
-    if (genre) MP4SetMetadataGenre(MP4hFile, genre);
-    if (comment) MP4SetMetadataComment(MP4hFile, comment);
-        if (artSize) {
-        MP4SetMetadataCoverArt(MP4hFile, art, artSize);
-#else
-    if (artist) MP4TagsSetArtist(tags, artist);
-    if (writer) MP4TagsSetComposer(tags, writer);
-    if (title) MP4TagsSetName(tags, title);
-    if (album) MP4TagsSetAlbum(tags, album);
-    if (trackno > 0) {
-        MP4TagTrack tt;
-        tt.index = trackno;
-        tt.total = ntracks;
-        MP4TagsSetTrack(tags, &tt);
+        mp4config.samplerate = infile->samplerate;
+        mp4config.channels = infile->channels;
+        mp4config.bits = infile->samplebytes * 8;
     }
-    if (discno > 0) {
-        MP4TagDisk td;
-        td.index = discno;
-        td.total = ndiscs;
-        MP4TagsSetDisk(tags, &td);
-    }
-    if (compilation) MP4TagsSetCompilation(tags, compilation);
-    if (year) MP4TagsSetReleaseDate(tags, year);
-    if (genre) MP4TagsSetGenre(tags, genre);
-    if (comment) MP4TagsSetComments(tags, comment);
-    if (artSize) {
-        MP4TagArtwork mp4art;
-        mp4art.data = art;
-        mp4art.size = artSize;
-        mp4art.type = MP4_ART_UNDEFINED; // delegate typing to libmp4v2
-        MP4TagsAddArtwork( tags, &mp4art );
-#endif
-        free(art);
-    }
-#if HAVE_DECL_MP4TAGSALLOC
-    MP4TagsStore( tags, MP4hFile );
-    MP4TagsFree( tags );
-#endif
-    }
     else
     {
-#endif
         /* open the aac output file */
         if (!strcmp(aacFileName, "-"))
         {
@@ -1007,20 +906,18 @@
             fprintf(stderr, "Couldn't create output file %s\n", aacFileName);
             return 1;
         }
-#ifdef HAVE_LIBMP4V2
     }
-#endif
 
     cutOff = myFormat->bandWidth;
     quantqual = myFormat->quantqual;
     bitRate = myFormat->bitRate;
     if (bitRate)
-      fprintf(stderr, "Average bitrate: %d kbps\n",
-          (bitRate + 500)/1000*infile->channels);
+        fprintf(stderr, "Average bitrate: %d kbps\n",
+                (bitRate + 500) / 1000 * infile->channels);
     fprintf(stderr, "Quantization quality: %ld\n", quantqual);
     fprintf(stderr, "Bandwidth: %d Hz\n", cutOff);
     fprintf(stderr, "Object type: ");
-    switch(objectType)
+    switch (objectType)
     {
     case LOW:
         fprintf(stderr, "Low Complexity");
@@ -1040,433 +937,220 @@
     fprintf(stderr, "\n");
 
     fprintf(stderr, "Container format: ");
-    switch(container)
+    switch (container)
     {
     case NO_CONTAINER:
-      switch(stream)
-    {
-    case RAW_STREAM:
-      fprintf(stderr, "Headerless AAC (RAW)\n");
-      break;
-    case ADTS_STREAM:
-      fprintf(stderr, "Transport Stream (ADTS)\n");
-      break;
-    }
+        switch (stream)
+        {
+        case RAW_STREAM:
+            fprintf(stderr, "Headerless AAC (RAW)\n");
+            break;
+        case ADTS_STREAM:
+            fprintf(stderr, "Transport Stream (ADTS)\n");
+            break;
+        }
         break;
-#ifdef HAVE_LIBMP4V2
     case MP4_CONTAINER:
         fprintf(stderr, "MPEG-4 File Format (MP4)\n");
         break;
-#endif
     }
 
-    if (outfile
-#ifdef HAVE_LIBMP4V2
-        || MP4hFile != MP4_INVALID_FILE_HANDLE
-#endif
-       )
-    {
-        int showcnt = 0;
+    int showcnt = 0;
 #ifdef _WIN32
-        long begin = GetTickCount();
+    long begin = GetTickCount();
 #endif
-        if (infile->samples)
-            frames = ((infile->samples + 1023) / 1024) + 1;
-        else
-            frames = 0;
-        currentFrame = 0;
+    if (infile->samples)
+        frames = ((infile->samples + 1023) / 1024) + 1;
+    else
+        frames = 0;
+    currentFrame = 0;
 
-        fprintf(stderr, "Encoding %s to %s\n", audioFileName, aacFileName);
-        if (frames != 0)
-            fprintf(stderr, "   frame          | bitrate | elapsed/estim | "
-            "play/CPU | ETA\n");
-        else
-            fprintf(stderr, " frame | elapsed | play/CPU\n");
+    fprintf(stderr, "Encoding %s to %s\n", audioFileName, aacFileName);
+    if (frames != 0)
+        fprintf(stderr, "   frame          | bitrate | elapsed/estim | "
+                "play/CPU | ETA\n");
+    else
+        fprintf(stderr, " frame | elapsed | play/CPU\n");
 
-        /* encoding loop */
+    /* encoding loop */
 #ifdef _WIN32
     for (;;)
 #else
-        while (running)
+    while (running)
 #endif
-        {
-            int bytesWritten;
+    {
+        int bytesWritten;
 
-          if (!ignorelen)
-          {
-            if (total_samples < infile->samples || infile->samples == 0)
-                samplesRead = wav_read_float32(infile, pcmbuf, samplesInput,
-                                               chanmap);
+        if (!ignorelen)
+        {
+            if (input_samples < infile->samples || infile->samples == 0)
+                samplesRead =
+                    wav_read_float32(infile, pcmbuf, samplesInput, chanmap);
             else
                 samplesRead = 0;
 
-            if (total_samples + (samplesRead / infile->channels) > infile->samples && infile->samples != 0)
-                samplesRead = (infile->samples - total_samples) * infile->channels;
-          }
-          else
-            samplesRead = wav_read_float32(infile, pcmbuf, samplesInput, chanmap);
+            if (input_samples + (samplesRead / infile->channels) >
+                infile->samples && infile->samples != 0)
+                samplesRead =
+                    (infile->samples - input_samples) * infile->channels;
+        }
+        else
+            samplesRead =
+                wav_read_float32(infile, pcmbuf, samplesInput, chanmap);
 
-            total_samples += samplesRead / infile->channels;
+        input_samples += samplesRead / infile->channels;
 
-            /* call the actual encoding routine */
-            bytesWritten = faacEncEncode(hEncoder,
-                (int32_t *)pcmbuf,
-                samplesRead,
-                bitbuf,
-                maxBytesOutput);
+        /* call the actual encoding routine */
+        bytesWritten = faacEncEncode(hEncoder,
+                                     (int32_t *) pcmbuf,
+                                     samplesRead, bitbuf, maxBytesOutput);
 
-            if (bytesWritten)
-            {
-                currentFrame++;
-                showcnt--;
-        totalBytesWritten += bytesWritten;
-            }
+        if (bytesWritten)
+        {
+            currentFrame++;
+            showcnt--;
+            totalBytesWritten += bytesWritten;
+        }
 
-            if ((showcnt <= 0) || !bytesWritten)
-            {
-                double timeused;
+        if ((showcnt <= 0) || !bytesWritten)
+        {
+            double timeused;
 #ifdef __unix__
-                struct rusage usage;
+            struct rusage usage;
 #endif
 #ifdef _WIN32
-                char percent[MAX_PATH + 20];
-                timeused = (GetTickCount() - begin) * 1e-3;
+            char percent[MAX_PATH + 20];
+            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;
+            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);
+            timeused = (double) clock() * (1.0 / CLOCKS_PER_SEC);
 #endif
 #endif
-                if (currentFrame && (timeused > 0.1))
-                {
-                    showcnt += 50;
+            if (currentFrame && (timeused > 0.1))
+            {
+                showcnt += 50;
 
-                    if (frames != 0)
-                        fprintf(stderr,
+                if (frames != 0)
+                    fprintf(stderr,
                             "\r%5d/%-5d (%3d%%)|  %5.1f  | %6.1f/%-6.1f | %7.2fx | %.1f ",
-                            currentFrame, frames, currentFrame*100/frames,
-                ((double)totalBytesWritten * 8.0 / 1000.0) /
-                ((double)infile->samples / infile->samplerate * currentFrame / frames),
-                            timeused,
+                            currentFrame, frames, currentFrame * 100 / frames,
+                            ((double) totalBytesWritten * 8.0 / 1000.0) /
+                            ((double) infile->samples / infile->samplerate *
+                             currentFrame / frames), timeused,
                             timeused * frames / currentFrame,
-                            (1024.0 * currentFrame / infile->samplerate) / timeused,
-                            timeused  * (frames - currentFrame) / currentFrame);
-                    else
-                        fprintf(stderr,
+                            (1024.0 * currentFrame / infile->samplerate) /
+                            timeused,
+                            timeused * (frames -
+                                        currentFrame) / currentFrame);
+                else
+                    fprintf(stderr,
                             "\r %5d |  %6.1f | %7.2fx ",
                             currentFrame,
                             timeused,
-                            (1024.0 * currentFrame / infile->samplerate) / timeused);
+                            (1024.0 * currentFrame / infile->samplerate) /
+                            timeused);
 
-                    fflush(stderr);
+                fflush(stderr);
 #ifdef _WIN32
-                    if (frames != 0)
-                    {
-                        sprintf(percent, "%.2f%% encoding %s",
+                if (frames != 0)
+                {
+                    sprintf(percent, "%.2f%% encoding %s",
                             100.0 * currentFrame / frames, audioFileName);
-                        SetConsoleTitle(percent);
-                    }
-#endif
+                    SetConsoleTitle(percent);
                 }
+#endif
             }
+        }
 
-            /* all done, bail out */
-            if (!samplesRead && !bytesWritten)
-                break ;
+        /* all done, bail out */
+        if (!samplesRead && !bytesWritten)
+            break;
 
-            if (bytesWritten < 0)
-            {
-                fprintf(stderr, "faacEncEncode() failed\n");
-                break ;
-            }
-
-            if (bytesWritten > 0)
-            {
-#ifdef HAVE_LIBMP4V2
-                u_int64_t samples_left = total_samples - encoded_samples + delay_samples;
-                MP4Duration dur = samples_left > frameSize ? frameSize : samples_left;
-                MP4Duration ofs = encoded_samples > 0 ? 0 : delay_samples;
-
-                if (container == MP4_CONTAINER)
-                {
-                    /* write bitstream to mp4 file */
-                    MP4WriteSample(MP4hFile, MP4track, bitbuf, bytesWritten, dur, ofs, 1);
-                }
-                else
-                {
-#endif
-                    /* write bitstream to aac file */
-                    fwrite(bitbuf, 1, bytesWritten, outfile);
-#ifdef HAVE_LIBMP4V2
-                }
-
-                encoded_samples += dur;
-#endif
-            }
+        if (bytesWritten < 0)
+        {
+            fprintf(stderr, "faacEncEncode() failed\n");
+            break;
         }
 
-#ifdef HAVE_LIBMP4V2
-        /* clean up */
-        if (container == MP4_CONTAINER)
+        if (bytesWritten > 0)
         {
-#ifdef MP4_CLOSE_DO_NOT_COMPUTE_BITRATE /* r479 fix */
-            MP4Close(MP4hFile, 0);
-#else
-            MP4Close(MP4hFile);
-#endif
-            if (optimizeFlag == 1)
-            {
-                fprintf(stderr, "\n\nMP4 format optimization... ");
-#ifdef MP4_DETAILS_ERROR /* r453 fix */
-                MP4Optimize(aacFileName, NULL, 0);
-#else
-                MP4Optimize(aacFileName, NULL);
-#endif
-                fprintf(stderr, "Done!");
-            }
-        } else
-#endif
-            fclose(outfile);
+            u_int64_t frame_samples = input_samples - encoded_samples;
+            if (frame_samples > delay_samples)
+                frame_samples = delay_samples;
 
-        fprintf(stderr, "\n\n");
-    }
+            if (container == MP4_CONTAINER)
+                mp4atom_frame(bitbuf, bytesWritten, frame_samples);
+            else
+                fwrite(bitbuf, 1, bytesWritten, outfile);
 
-    faacEncClose(hEncoder);
-
-    wav_close(infile);
-
-    if (pcmbuf) free(pcmbuf);
-    if (bitbuf) free(bitbuf);
-    if (aacFileNameGiven) free(aacFileName);
-
+            encoded_samples += frame_samples;
+        }
     }
 
-    return 0;
-}
+    if (container == MP4_CONTAINER)
+    {
+        char *version_string = malloc(strlen(faac_id_string) + 6);
 
-/*
-$Log: main.c,v $
-Revision 1.90  2017/07/02 17:10:00  knik
-exit when trying to encode mp4 to stdin
+        faacEncGetDecoderSpecificInfo(hEncoder,
+                                      &mp4config.asc.data,
+                                      &mp4config.asc.size);
+        strcpy(version_string, "FAAC ");
+        strcpy(version_string + 5, faac_id_string);
 
-Revision 1.89  2017/07/01 08:52:27  knik
-fixed CVE-2017-9130 (crash with improper .wav input)
+        mp4config.tag.encoder = version_string;
 
-Revision 1.88  2015/11/26 14:27:05  knik
-bugfix by Sebastian Wilhelmi: faac exits immediately when encoding raw wav file
+#define SETTAG(x) if(x)mp4config.tag.x=x
+        SETTAG(artist);
+        SETTAG(composer);
+        SETTAG(title);
+        SETTAG(album);
+#if 0
+        // fixme: those aren't right yet
+        SETTAG(trackno);
+        SETTAG(discno);
+#endif
+        SETTAG(compilation);
+        SETTAG(year);
+        SETTAG(genre);
+        SETTAG(comment);
+        // fixme: add cover-art option
 
-Revision 1.87  2015/06/09 10:58:00  knik
-fixed compilation without limbp4v2
+        mp4atom_tail();
+        mp4atom_close();
 
-Revision 1.86  2012/02/25 17:34:01  knik
-Fix format string security error.
+        free(version_string);
 
-Revision 1.85  2012/02/23 13:26:45  knik
-Support for libmp4v2 r479; Port faac to the iTMF Generic and Tags API.
-Authors: Jaakko Perttilä, Sebastien NOEL, Fabian Greffrath
+        fprintf(stderr, "%d frames\n", mp4config.numframes);
+        fprintf(stderr, "%llu input samples\n", input_samples);
+        fprintf(stderr, "%du output samples\n", mp4config.samples);
+        fprintf(stderr, "max bitrate: %d\n", mp4config.bitratemax);
+        fprintf(stderr, "avg bitrate: %d\n", mp4config.bitrateavg);
+        fprintf(stderr, "max bufsize: %d\n", mp4config.buffersize);
+    }
+    else
+    {
+        fclose(outfile);
+        fprintf(stderr, "\n");
+    }
 
-Revision 1.84  2010/09/27 10:32:17  knik
-Patch by Arthur Yarwood: read correct number of samples from data chunk
+    faacEncClose(hEncoder);
 
-Revision 1.83  2009/07/27 18:12:38  menno
-FAAC now able to use external updated libmp4v2
+    wav_close(infile);
 
-Revision 1.82  2009/01/24 01:10:20  menno
-Made JPEG detection less restrictive
+    if (pcmbuf)
+        free(pcmbuf);
+    if (bitbuf)
+        free(bitbuf);
+    if (aacFileNameGiven)
+        free(aacFileName);
 
-Revision 1.81  2009/01/24 00:15:12  menno
-Added -s option for output of optimized mp4 layout
-
-Revision 1.80  2007/03/19 19:57:40  menno
-Made faacgui buildable again
-Made stdout as output possible (use - as output filename)
-Disabled MAIN and LTP encoding
-Increase version number
-
-Revision 1.79  2006/09/25 19:53:36  menno
-Fixed track and disk number reading from command line
-
-Revision 1.78  2004/12/08 11:07:17  menno
-Make long help work again
-
-Revision 1.77  2004/08/19 15:33:30  menno
-typo
-it's not bad to have this option, but people should be warned that they can get severe playback problems with RAW AAC files (anything other then 44100 will not be decoded properly unless you know that it has that samplerate). Seeking is also not possible on these files.
-
-Revision 1.76  2004/08/19 13:18:44  menno
-Removed stupid comment in help of FAAC. RAW AAC files are USELESS, it seems that already some people encoded their collection using the -r option.
-
-Revision 1.75  2004/08/06 19:33:19  danchr
-TNS is no longer enabled by default (reported by guruboolez)
-documentation fixes in frontend
-default to mp4 for *.m4b as well
-
-Revision 1.74  2004/08/03 00:08:51  danchr
-fix --shortctl documentation
-
-Revision 1.73  2004/08/02 20:53:23  danchr
-*BSD portability fix
-
-Revision 1.72  2004/08/02 20:41:59  danchr
-NetBSD portability fix + fixing metadata bugs w/ sscanf()
-
-Revision 1.71  2004/07/28 08:18:21  danchr
-Darwin portability fixes, should help on Linux too
-
-Revision 1.70  2004/05/03 11:39:05  danchr
-fix documentation bugs (per Hans-J�rgen's suggestions)
-enable (preliminary) multiple output file support
-
-Revision 1.69  2004/04/22 14:07:14  danchr
-set copyright notice to my full name
-
-Revision 1.68  2004/04/16 14:51:10  danchr
-don't use stderr on Windows
-
-Revision 1.67  2004/04/16 09:49:10  danchr
-change -a <kbps/channel> to -b <kbps>
-Darwin portability fixes
-Make LTP imply MPEG-4 AAC
-silence a few warnings
-
-Revision 1.66  2004/04/13 13:47:05  danchr
-compilation and composer patch by Jordan Breeding
-undocumented single-letter switches removed
-numerous bug-fixes
-
-Revision 1.65  2004/04/03 17:47:40  danchr
-fix typo + add GIF support
-
-Revision 1.64  2004/04/03 15:54:48  danchr
-make TNS default
-
-Revision 1.63  2004/04/03 15:50:05  danchr
-non-backwards compatible revamp of the FAAC command line interface
-cover art metadata support based on patch by Jordan Breeding (jordan breeding (a) mac com)
-
-Revision 1.62  2004/03/29 14:02:04  danchr
-MP4 bug fixes by Jordan Breeding (jordan breeding (a) mac com)
-Document long options for metadata - they are much more intuitive.
-
-Revision 1.61  2004/03/27 13:44:24  danchr
-minor compile-time bugfix for Win32
-
-Revision 1.60  2004/03/24 15:44:08  danchr
-fixing WIN32 -> _WIN32
-
-Revision 1.59  2004/03/24 11:09:06  danchr
-prettify the way stream format is handled - this just *might* fix a bug
-
-Revision 1.58  2004/03/24 11:00:40  danchr
-silence a few warnings and fix a few mem. leaks
-make it possible to disable stripping (needed for profiling and debugging)
-
-Revision 1.57  2004/03/17 13:32:13  danchr
-- New signal handler. Disabled on Windows, although it *should* work.
-- Separated handling of stream format and output format.
-- Bitrate + file format displayed on stderr.
-- knik and myself added to the copyright header.
-
-Revision 1.56  2004/03/15 20:15:48  knik
-improved MP4 support by Dan Christiansen
-
-Revision 1.55  2004/03/03 15:54:50  knik
-libmp4v2 autoconf detection and mp4 metadata support by Dan Christiansen
-
-Revision 1.54  2004/02/14 10:31:23  knik
-Print help and exit when unknown option is specified.
-
-Revision 1.53  2003/12/20 04:32:48  stux
-i've added sms00's OSX patch to faac
-
-Revision 1.52  2003/12/14 12:25:44  ca5e
-Gapless MP4 handling method changed again...
-
-Revision 1.51  2003/12/13 21:58:35  ca5e
-Improved gapless encoding
-
-Revision 1.50  2003/11/24 18:11:14  knik
-using new version info interface
-
-Revision 1.49  2003/11/13 18:30:19  knik
-raw input bugfix
-
-Revision 1.48  2003/10/17 17:11:18  knik
-fixed raw input
-
-Revision 1.47  2003/10/12 14:30:29  knik
-more accurate average bitrate control
-
-Revision 1.46  2003/09/24 16:30:34  knik
-Added option to enforce block type.
-
-Revision 1.45  2003/09/08 16:28:21  knik
-conditional libmp4v2 compilation
-
-Revision 1.44  2003/09/07 17:44:36  ca5e
-length calculations/silence padding changed to match current libfaac behavior
-changed tabs to spaces, fixes to indentation
-
-Revision 1.43  2003/08/17 19:38:15  menno
-fixes to MP4 files by Case
-
-Revision 1.41  2003/08/15 11:43:14  knik
-Option to add a number of silent frames at the end of output.
-Small TNS option fix.
-
-Revision 1.40  2003/08/07 11:28:06  knik
-fixed win32 crash with long filenames
-
-Revision 1.39  2003/07/21 16:33:49  knik
-Fixed LFE channel mapping.
-
-Revision 1.38  2003/07/13 08:34:43  knik
-Fixed -o, -m and -I option.
-Print object type setting.
-
-Revision 1.37  2003/07/10 19:19:32  knik
-Input channel remapping and 24-bit support.
-
-Revision 1.36  2003/06/26 19:40:53  knik
-TNS disabled by default.
-Copyright info moved to library.
-Print help to standard output.
-
-Revision 1.35  2003/06/21 08:59:31  knik
-raw input support moved to input.c
-
-Revision 1.34  2003/05/10 09:40:35  knik
-added approximate ABR option
-
-Revision 1.33  2003/04/13 08:39:28  knik
-removed psymodel setting
-
-Revision 1.32  2003/03/27 17:11:06  knik
-updated library interface
--b bitrate option replaced with -q quality option
-TNS enabled by default
-
-Revision 1.31  2002/12/23 19:02:43  knik
-added some headers
-
-Revision 1.30  2002/12/15 15:16:55  menno
-Some portability changes
-
-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
-
-*/
+    return 0;
+}
--- /dev/null
+++ b/frontend/mp4atom.c
@@ -1,0 +1,791 @@
+/****************************************************************************
+    MP4 output module
+
+    Copyright (C) 2017 Krzysztof Nikiel
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#ifndef WORDS_BIGENDIAN
+//#include <byteswap.h>
+#endif
+#include <string.h>
+#include <sys/time.h>
+
+enum ATOM_TYPE
+{
+    ATOM_STOP = 0 /* end of atoms */ ,
+    ATOM_NAME /* plain atom */ ,
+    ATOM_DESCENT,               /* starts group of children */
+    ATOM_ASCENT,                /* ends group */
+    ATOM_DATA,
+};
+typedef struct
+{
+    uint16_t opcode;
+    void *data;
+} creator_t;
+
+#include "mp4atom.h"
+
+mp4config_t mp4config = { 0 };
+
+static FILE *g_fout = NULL;
+
+static inline uint32_t bswap32(uint32_t u32)
+{
+#ifndef WORDS_BIGENDIAN
+    //return __bswap_32(u32);
+    return __builtin_bswap32(u32);
+#endif
+}
+
+static inline uint16_t bswap16(uint16_t u16)
+{
+#ifndef WORDS_BIGENDIAN
+    //return __bswap_16(u16);
+    return __builtin_bswap16(u16);
+#endif
+}
+
+static int dataout(const void *data, int size)
+{
+    if (fwrite(data, 1, size, g_fout) != size)
+    {
+        perror("mp4out");
+        return -1;
+    }
+    return size;
+}
+
+static int stringout(const char *txt)
+{
+    return dataout(txt, strlen(txt));
+}
+
+static int u32out(uint32_t u32)
+{
+    u32 = bswap32(u32);
+    return dataout(&u32, 4);
+}
+
+static int u16out(uint16_t u16)
+{
+    u16 = bswap16(u16);
+    return dataout(&u16, 2);
+}
+
+static int u8out(uint8_t u8)
+{
+    if (fwrite(&u8, 1, 1, g_fout) != 1)
+    {
+        perror("mp4 out");
+        return 0;
+    }
+    return 1;
+}
+
+static int ftypout(void)
+{
+    int size = 0;
+
+    size += stringout("isom");
+    size += u32out(0);
+    //size += stringout("isommp42");
+    size += stringout("mp41mp42");
+
+    return size;
+}
+
+enum
+{ SECSINDAY = 24 * 60 * 60 };
+uint32_t mp4time(void)
+{
+    int y;
+    struct timeval t;
+
+    gettimeofday(&t, NULL);
+
+    // add some time from the start of 1904 to the start of 1970
+    for (y = 1904; y < 1970; y++)
+    {
+        t.tv_sec += 365 * SECSINDAY;
+        if (!(y & 3))
+            t.tv_sec += SECSINDAY;
+    }
+
+    return t.tv_sec;
+}
+
+static int mvhdout(void)
+{
+    int size = 0;
+    int cnt;
+
+    // version
+    size += u8out(0);
+    // flags
+    size += u8out(0);
+    size += u16out(0);
+    // Creation time
+    size += u32out(mp4time());
+    // Modification time
+    size += u32out(mp4time());
+    // Time scale (samplerate)
+    size += u32out(mp4config.samplerate);
+    // Duration
+    size += u32out(mp4config.samples);
+    // rate
+    size += u32out(0x00010000);
+    // volume
+    size += u16out(0x0100);
+    // reserved
+    size += u16out(0);
+    size += u32out(0);
+    size += u32out(0);
+    // matrix
+    size += u32out(0x00010000);
+    size += u32out(0);
+    size += u32out(0);
+    size += u32out(0);
+    size += u32out(0x00010000);
+    size += u32out(0);
+    size += u32out(0);
+    size += u32out(0);
+    size += u32out(0x40000000);
+
+    for (cnt = 0; cnt < 6; cnt++)
+        size += u32out(0);
+    // Next track ID
+    size += u32out(2);
+
+    return size;
+};
+
+static int tkhdout(void)
+{
+    int size = 0;
+
+    // version
+    size += u8out(0);
+    // flags
+    // bits 8-23
+    size += u16out(0);
+    // bits 0-7
+    size += u8out(1 /*track enabled */ );
+    // Creation time
+    size += u32out(mp4time());
+    // Modification time
+    size += u32out(mp4time());
+    // Track ID
+    size += u32out(1);
+    // Reserved
+    size += u32out(0);
+    // Duration
+    size += u32out(mp4config.samples);
+    // Reserved
+    size += u32out(0);
+    size += u32out(0);
+    // Layer
+    size += u16out(0);
+    // Alternate group
+    size += u16out(0);
+    // Volume
+    size += u16out(0x0100);
+    // Reserved
+    size += u16out(0);
+    // matrix
+    size += u32out(0x00010000);
+    size += u32out(0);
+    size += u32out(0);
+    size += u32out(0);
+    size += u32out(0x00010000);
+    size += u32out(0);
+    size += u32out(0);
+    size += u32out(0);
+    size += u32out(0x40000000);
+
+    // Track width
+    size += u32out(0);
+    // Track height
+    size += u32out(0);
+
+    return size;
+};
+
+static int mdhdout(void)
+{
+    int size = 0;
+
+    // version/flags
+    size += u32out(0);
+    // Creation time
+    size += u32out(mp4time());
+    // Modification time
+    size += u32out(mp4time());
+    // Time scale
+    size += u32out(mp4config.samplerate);
+    // Duration
+    size += u32out(mp4config.samples);
+    // Language
+    size += u16out(0 /*0=English */ );
+    // pre_defined
+    size += u16out(0);
+
+    return size;
+};
+
+
+static int hdlrout(void)
+{
+    int size = 0;
+
+    // version/flags
+    size += u32out(0);
+    // pre_defined
+    size += u32out(0);
+    // Component subtype
+    size += stringout("soun");
+    // reserved
+    size += u32out(0);
+    size += u32out(0);
+    size += u32out(0);
+    // name
+    // null terminate
+    size += u8out(0);
+
+    return size;
+};
+
+static int smhdout(void)
+{
+    int size = 0;
+
+    // version/flags
+    size += u32out(0);
+    // Balance
+    size += u16out(0 /*center */ );
+    // Reserved
+    size += u16out(0);
+
+    return size;
+};
+
+static int drefout(void)
+{
+    int size = 0;
+
+    // version/flags
+    size += u32out(0);
+    // Number of entries
+    size += u32out(1 /*url reference */ );
+
+    return size;
+};
+
+static int urlout(void)
+{
+    int size = 0;
+
+    size += u32out(1);
+
+    return size;
+};
+
+static int stsdout(void)
+{
+    int size = 0;
+
+    // version/flags
+    size += u32out(0);
+    // Number of entries(one 'mp4a')
+    size += u32out(1);
+
+    return size;
+};
+
+static int mp4aout(void)
+{
+    int size = 0;
+    // Reserved (6 bytes)
+    size += u32out(0);
+    size += u16out(0);
+    // Data reference index
+    size += u16out(1);
+    // Version
+    size += u16out(0);
+    // Revision level
+    size += u16out(0);
+    // Vendor
+    size += u32out(0);
+    // Number of channels
+    size += u16out(mp4config.channels);
+    // Sample size (bits)
+    size += u16out(mp4config.bits);
+    // Compression ID
+    size += u16out(0);
+    // Packet size
+    size += u16out(0);
+    // Sample rate (16.16)
+    // rate integer part
+    size += u16out(mp4config.samplerate);
+    // rate reminder part
+    size += u16out(0);
+
+    return size;
+}
+
+static int esdsout(void)
+{
+    int size = 0;
+    // descriptor definitions:
+    // systems/mp4_file_format/libisomediafile/src/MP4Descriptors.h
+    // systems/mp4_file_format/libisomediafile/src/MP4Descriptors.c
+    //
+    // descriptor tree:
+    // MP4ES_Descriptor
+    //   MP4DecoderConfigDescriptor
+    //      MP4DecSpecificInfoDescriptor
+    //   MP4SLConfigDescriptor
+    struct
+    {
+        int es;
+        int dc;                 // DecoderConfig
+        int dsi;                // DecSpecificInfo
+        int sl;                 // SLConfig
+    } dsize;
+
+    enum
+    { TAG_ES = 3, TAG_DC = 4, TAG_DSI = 5, TAG_SLC = 6 };
+
+    // calc sizes
+#define DESCSIZE(x) (x + 2/*.tag+.size*/)
+    dsize.sl = 1;
+    dsize.dsi = mp4config.asc.size;
+    dsize.dc = 13 + DESCSIZE(dsize.dsi);
+    dsize.es = 3 + DESCSIZE(dsize.dc) + DESCSIZE(dsize.sl);
+
+    // output esds atom data
+    // version/flags ?
+    size += u32out(0);
+    // mp4es
+    size += u8out(TAG_ES);
+    size += u8out(dsize.es);
+    // ESID
+    size += u16out(0);
+    // flags(url(bit 6); ocr(5); streamPriority (0-4)):
+    size += u8out(0);
+
+    size += u8out(TAG_DC);
+    size += u8out(dsize.dc);
+    size += u8out(0x40 /*MPEG-4 audio */ );
+    // DC flags: upstream(bit 1); streamType(2-7)
+    // Stream type, is this even used and how?
+    //size += u8out(0x15/*???*/);
+    size += u8out(1 /*AAC main? */  << 2);
+    // buffer size (24 bits)
+    size += u16out(mp4config.buffersize >> 8);
+    size += u8out(mp4config.buffersize && 0xff);
+    // bitrate
+    size += u32out(mp4config.bitratemax);
+    size += u32out(mp4config.bitrateavg);
+
+    size += u8out(TAG_DSI);
+    size += u8out(dsize.dsi);
+    // AudioSpecificConfig
+    size += dataout(mp4config.asc.data, mp4config.asc.size);
+
+    size += u8out(TAG_SLC);
+    size += u8out(dsize.sl);
+    // "predefined" (no idea)
+    size += u8out(2);
+
+    return size;
+}
+
+static int sttsout(void)
+{
+    int size = 0;
+
+    // version/flags
+    size += u32out(0);
+    // Number of entries
+    size += u32out(1);
+    // only one entry
+    // Sample count (number of frames)
+    size += u32out(mp4config.numframes);
+    // Sample duration (samples per frame)
+    size += u32out(1024);
+
+    return size;
+}
+
+static int stszout(void)
+{
+    int size = 0;
+    int cnt;
+
+    // version/flags
+    size += u32out(0);
+    // Sample size
+    size += u32out(0 /*i.e. variable size */ );
+    // Number of entries
+    if (!mp4config.numframes)
+        return size;
+    if (!mp4config.frame)
+        return size;
+
+    size += u32out(mp4config.numframes);
+    for (cnt = 0; cnt < mp4config.numframes; cnt++)
+        size += u32out(mp4config.frame[cnt]);
+
+    return size;
+}
+
+static int stscout(void)
+{
+    int size = 0;
+
+    // version/flags
+    size += u32out(0);
+    // Number of entries
+    size += u32out(2);
+    // 1st entry
+    // first chunk
+    size += u32out(1);
+    // frames per chunks (256 for simplicity)
+    size += u32out(0x100);
+    // sample id
+    size += u32out(1);
+    // 2nd entry
+    // last chunk
+    size += u32out((mp4config.numframes >> 8) + 1);
+    // frames in last chunk
+    size += u32out(mp4config.numframes & 0xff);
+
+    // sample id
+    size += u32out(1);
+
+    return size;
+}
+
+static int stcoout(void)
+{
+    int size = 0;
+    int chunks = (mp4config.numframes >> 8) + 1;
+    int cnt;
+    uint32_t ofs = mp4config.mdatofs;
+
+    // version/flags
+    size += u32out(0);
+    // Number of entries
+    size += u32out(chunks);
+    // Chunk offset table
+    if (!mp4config.numframes)
+        return size;
+    if (!mp4config.frame)
+        return size;
+    for (cnt = 0; cnt < mp4config.numframes; cnt++)
+    {
+        if (!(cnt & 0xff))
+            size += u32out(ofs);
+        ofs += mp4config.frame[cnt];
+    }
+
+    return size;
+}
+
+static int tagtxt(char *tagname, const char *tagtxt)
+{
+    int txtsize = strlen(tagtxt);
+    int size = 0;
+    int datasize = txtsize + 16;
+
+    size += u32out(datasize + 8);
+    size += dataout(tagname, 4);
+    size += u32out(datasize);
+    size += dataout("data", 4);
+    size += u32out(1);
+    size += u32out(0);
+    size += dataout(tagtxt, txtsize);
+
+    return size;
+}
+
+static int tagu32(char *tagname, uint32_t n)
+{
+    int numsize = 4;
+    int size = 0;
+    int datasize = numsize + 16;
+
+    size += u32out(datasize + 8);
+    size += dataout(tagname, 4);
+    size += u32out(datasize);
+    size += dataout("data", 4);
+    size += u32out(0);
+    size += u32out(0);
+    size += u32out(n);
+
+    return size;
+}
+
+static int metaout(void)
+{
+    int size = 0;
+
+    // version/flags
+    size += u32out(0);
+    // Predefined
+    size += u32out(0);
+    // Handler type
+    size += stringout("mdir");
+    size += stringout("appl");
+    // Reserved
+    size += u32out(0);
+    size += u32out(0);
+    // null terminator
+    size += u8out(0);
+
+    return size;
+};
+
+static int ilstout(void)
+{
+    int size = 0;
+
+    size += tagtxt("\xa9" "too", mp4config.tag.encoder);
+    if (mp4config.tag.artist)
+        size += tagtxt("\xa9" "ART", mp4config.tag.artist);
+    if (mp4config.tag.composer)
+        size += tagtxt("\xa9" "wrt", mp4config.tag.composer);
+    if (mp4config.tag.title)
+        size += tagtxt("\xa9" "nam", mp4config.tag.title);
+    if (mp4config.tag.genre)
+        size += tagtxt("gnre", mp4config.tag.genre);
+    if (mp4config.tag.album)
+        size += tagtxt("\xa9" "alb", mp4config.tag.album);
+    if (mp4config.tag.compilation)
+        size += tagu32("cpil", mp4config.tag.compilation);
+    if (mp4config.tag.trackno)
+        size += tagu32("trkn", mp4config.tag.trackno);
+    if (mp4config.tag.discno)
+        size += tagu32("disk", mp4config.tag.discno);
+    if (mp4config.tag.year)
+        size += tagtxt("\xa9" "day", mp4config.tag.year);
+#if 0
+    if (mp4config.tag.cover)
+        size += tagtxt("\xa9" "covr", mp4config.tag.cover);
+#endif
+    if (mp4config.tag.comment)
+        size += tagtxt("\xa9" "cmt", mp4config.tag.comment);
+
+    return size;
+};
+
+static creator_t g_head[] = {
+    {ATOM_NAME, "ftyp"},
+    {ATOM_DATA, ftypout},
+    {ATOM_NAME, "free"},
+    {ATOM_NAME, "mdat"},
+    {0}
+};
+
+static creator_t g_tail[] = {
+    {ATOM_NAME, "moov"},
+    {ATOM_DESCENT},
+    {ATOM_NAME, "mvhd"},
+    {ATOM_DATA, mvhdout},
+    {ATOM_NAME, "trak"},
+    {ATOM_DESCENT},
+    {ATOM_NAME, "tkhd"},
+    {ATOM_DATA, tkhdout},
+    {ATOM_NAME, "mdia"},
+    {ATOM_DESCENT},
+    {ATOM_NAME, "mdhd"},
+    {ATOM_DATA, mdhdout},
+    {ATOM_NAME, "hdlr"},
+    {ATOM_DATA, hdlrout},
+    {ATOM_NAME, "minf"},
+    {ATOM_DESCENT},
+    {ATOM_NAME, "smhd"},
+    {ATOM_DATA, smhdout},
+    {ATOM_NAME, "dinf"},
+    {ATOM_DESCENT},
+    {ATOM_NAME, "dref"},
+    {ATOM_DATA, drefout},
+    {ATOM_DESCENT},
+    {ATOM_NAME, "url "},
+    {ATOM_DATA, urlout},
+    {ATOM_ASCENT},
+    {ATOM_ASCENT},
+    {ATOM_NAME, "stbl"},
+    {ATOM_DESCENT},
+    {ATOM_NAME, "stsd"},
+    {ATOM_DATA, stsdout},
+    {ATOM_DESCENT},
+    {ATOM_NAME, "mp4a"},
+    {ATOM_DATA, mp4aout},
+    {ATOM_DESCENT},
+    {ATOM_NAME, "esds"},
+    {ATOM_DATA, esdsout},
+    {ATOM_ASCENT},
+    {ATOM_ASCENT},
+    {ATOM_NAME, "stts"},
+    {ATOM_DATA, sttsout},
+    {ATOM_NAME, "stsz"},
+    {ATOM_DATA, stszout},
+    {ATOM_NAME, "stsc"},
+    {ATOM_DATA, stscout},
+    {ATOM_NAME, "stco"},
+    {ATOM_DATA, stcoout},
+    {ATOM_ASCENT},
+    {ATOM_ASCENT},
+    {ATOM_ASCENT},
+    {ATOM_ASCENT},
+    {ATOM_NAME, "udta"},
+    {ATOM_DESCENT},
+    {ATOM_NAME, "meta"},
+    {ATOM_DESCENT},
+    {ATOM_NAME, "hdlr"},
+    {ATOM_DATA, metaout},
+    {ATOM_NAME, "ilst"},
+    {ATOM_DATA, ilstout},
+    {0}
+};
+
+static creator_t *g_atom = 0;
+static int create(void)
+{
+    long apos = ftell(g_fout);;
+    int size;
+    static int level = 0;
+
+    if (g_atom->opcode != ATOM_NAME)
+    {
+        static int fail = 0;
+        if (++fail > 10)
+            exit(1);
+        printf("internal error: create: not a 'name' opcode\n");
+        return 0;
+    }
+
+    size = u32out(8);
+    size += dataout(g_atom->data, 4);
+
+    g_atom++;
+    if (g_atom->opcode == ATOM_DATA)
+    {
+        size += ((int (*)(void)) g_atom->data) ();
+        g_atom++;
+    }
+    if (g_atom->opcode == ATOM_DESCENT)
+    {
+        level++;
+        g_atom++;
+        while (g_atom->opcode != ATOM_STOP)
+        {
+            if (g_atom->opcode == ATOM_ASCENT)
+            {
+                g_atom++;
+                break;
+            }
+            size += create();
+        }
+        level--;
+    }
+
+    fseek(g_fout, apos, SEEK_SET);
+    u32out(size);
+    fseek(g_fout, apos + size, SEEK_SET);
+
+    return size;
+}
+
+int mp4atom_frame(uint8_t * buf, int size, int samples)
+{
+    if (mp4config.framesamples <= samples)
+    {
+        int bitrate = 8.0 * size * mp4config.samplerate / samples;
+
+        if (mp4config.bitratemax < bitrate)
+            mp4config.bitratemax = bitrate;
+
+        mp4config.framesamples = samples;
+    }
+    if (mp4config.buffersize < size)
+        mp4config.buffersize = size;
+    mp4config.samples += samples;
+    mp4config.mdatsize += dataout(buf, size);
+    // fixme: check *frame size and realloc
+    mp4config.frame[mp4config.numframes++] = size;
+
+    return 0;
+}
+
+int mp4atom_close(void)
+{
+    if (g_fout)
+    {
+        fseek(g_fout, mp4config.mdatofs - 8, SEEK_SET);
+        u32out(mp4config.mdatsize + 8);
+        fclose(g_fout);
+        g_fout = 0;
+    }
+    if (mp4config.frame)
+    {
+        free(mp4config.frame);
+        mp4config.frame = 0;
+    }
+    return 0;
+}
+
+int mp4atom_open(char *name)
+{
+    mp4atom_close();
+
+    g_fout = fopen(name, "wb");
+    if (!g_fout)
+        return 1;
+
+    mp4config.mdatsize = 0;
+    mp4config.frame = malloc(0x10000);  // fixme
+
+    return 0;
+}
+
+
+int mp4atom_head(void)
+{
+    g_atom = g_head;
+    while (g_atom->opcode != ATOM_STOP)
+        create();
+    mp4config.mdatofs = ftell(g_fout);
+
+    return 0;
+}
+
+int mp4atom_tail(void)
+{
+    mp4config.bitrateavg = 8.0 * mp4config.mdatsize
+        * mp4config.samplerate / mp4config.samples;
+
+    g_atom = g_tail;
+    while (g_atom->opcode != ATOM_STOP)
+        create();
+
+    return 0;
+}
--- /dev/null
+++ b/frontend/mp4atom.h
@@ -1,0 +1,70 @@
+/****************************************************************************
+    MP4 output module
+
+    Copyright (C) 2017 Krzysztof Nikiel
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+****************************************************************************/
+
+#include <stdint.h>
+
+typedef struct
+{
+    uint32_t samplerate;
+    // total sound samples
+    uint32_t samples;
+    uint32_t channels;
+    // sample depth
+    uint32_t bits;
+    // buffer config
+    uint16_t buffersize;
+    uint32_t bitratemax;
+    uint32_t bitrateavg;
+    uint32_t framesamples;
+    uint32_t numframes;
+    uint16_t *frame;
+    // AudioSpecificConfig data:
+    struct
+    {
+        uint8_t *data;
+        unsigned long size;
+    } asc;
+    uint32_t mdatofs;
+    uint32_t mdatsize;
+
+    struct
+    {
+        // meta fields
+        const char *encoder;
+        const char *artist;
+        const char *composer;
+        const char *title;
+        const char *genre;
+        const char *album;
+        uint8_t compilation;
+        uint32_t trackno;
+        uint32_t discno;
+        const char *year;
+        const char *cover;      // cover filename
+        const char *comment;
+    } tag;
+} mp4config_t;
+
+extern mp4config_t mp4config;
+
+int mp4atom_open(char *name);
+int mp4atom_head(void);
+int mp4atom_tail(void);
+int mp4atom_frame(uint8_t * bitbuf, int bytesWritten, int frame_samples);
+int mp4atom_close(void);