1
0
mirror of https://github.com/nu774/fdkaac.git synced 2025-06-05 23:29:14 +02:00

51 Commits

Author SHA1 Message Date
a79a11ef99 win32compat: fix aacenc_printf() not to write junk characters 2014-07-30 14:09:12 +09:00
70554c0791 write INSTALL 2014-05-12 16:46:49 +09:00
a854b113ae update COPYING (patch from darealshinji) 2014-03-14 11:10:15 +09:00
f7a24bf87b update ChangeLog 2014-02-17 13:58:54 +09:00
5063c6dce1 bump version 2014-02-17 13:55:08 +09:00
57aa91419d fix: CAF chan chunk using channel bitmap was not correctly handled 2014-02-17 13:51:20 +09:00
b3dcf08647 update ChangeLog 2014-01-18 17:47:03 +09:00
a7c4895534 bump version 2014-01-18 17:44:51 +09:00
209130e887 fix reading of caf file without chan chunk
Since channel map was not initialized, first channel was copied to every
other channel.
2014-01-18 17:41:57 +09:00
b6ab92a9e7 Merge pull request #9 from rbrito/fix-typo
README: Fix typo in bandwidth to match CLI options.
2013-11-17 22:02:43 -08:00
e18fe91a40 man: Regen manpage with hyphens escaped.
Otherwise, automated verification programs like Debian's lintian complain
about them.

Signed-off-by: Rogério Brito <rbrito@ime.usp.br>
2013-11-18 02:55:18 -02:00
472e82e42f README: Remove trailing whitespaces that end up in the manpages.
Signed-off-by: Rogério Brito <rbrito@ime.usp.br>
2013-11-18 02:52:35 -02:00
ce0833f8e5 README: Fix typo in bandwidth to match CLI options.
Signed-off-by: Rogério Brito <rbrito@ime.usp.br>
2013-11-18 02:48:39 -02:00
661f883dce add genman.sh, update fdkaac.1 2013-11-08 23:18:20 +09:00
b815f858d0 update ChangeLog 2013-11-08 12:49:19 +09:00
5d6ea58e92 bump version 2013-11-08 12:48:14 +09:00
71e4764062 fix to use libFDKAAC signaling mode 1
It turned out that mode 1 is explicit, backward compatible signaling.
We don't have to implement it on our side.
2013-11-08 12:23:52 +09:00
a26e3cf3e8 fix README 2013-11-05 15:45:08 +09:00
c6e18ebec1 rename README.md -> README 2013-11-04 22:53:28 +09:00
c1db26327a Update README -> README.md, generate groff manpage from README.md 2013-11-04 15:33:01 +09:00
1c1d1931cb update ChangeLog 2013-11-04 12:19:36 +09:00
2ecae04c89 update git2changelog to accept non-ascii output 2013-11-04 12:18:27 +09:00
30c77dfb6f add manpage 2013-11-04 12:15:09 +09:00
ed646ccf79 fix gcc warnings 2013-11-03 22:40:26 +09:00
8009f87dca Merge pull request #7 from rbrito/misc-fixes
gitignore: Add list of files to ignore.
2013-11-03 05:26:02 -08:00
d09acb7283 gitignore: Add list of files to ignore.
All of these files are generated by autotools or by the compilation and they
do not belong in a version control.

Signed-off-by: Rogério Brito <rbrito@ime.usp.br>
2013-11-03 10:45:51 -02:00
8ac221b853 update ChangeLog 2013-11-03 18:13:59 +09:00
2c116b15d5 bump version 2013-11-03 18:12:43 +09:00
e1adc17835 add --sbr-ratio to support AACENC_SBR_RATIO appeared on libFDK 3.4.12 2013-11-03 18:09:56 +09:00
3c0f152d39 support 7.1 channel mode added on FDK 3.4.12 2013-11-03 18:08:46 +09:00
5732f1f6c5 update ChangeLog 2013-10-30 19:05:13 +09:00
a3271927b8 bump version 2013-10-30 19:02:00 +09:00
3de0e22dcc use tell() to obtain data chunk offset 2013-10-30 14:27:28 +09:00
d533c8e002 rename aacenc_result_t -> aacenc_frame_t, simplify write_sample() 2013-10-30 11:58:30 +09:00
c5eec15549 prepend 1 sample zero padding in case of SBR and enc_delay is odd
This is required because odd enc_delay cannot be exactly expressed in
downsampled scale, and HE-AACv2 FDK encoder actually has odd enc_delay.
2013-10-30 02:09:23 +09:00
3b518efd31 cleanup interface of aac_encode_frame() 2013-10-30 02:09:23 +09:00
556a3db11b add some copyright notice 2013-10-30 02:09:23 +09:00
4d48b091d4 smart padding for better gapless playback
Taken smart padding code using LPC extrapolation from vorbis/opus.
Padding is done on both beginning and ending, but enc_delay and padding
remains the same (we discard extra padding frame introduced on our side
after encoding).
2013-10-30 02:09:08 +09:00
d11b044131 fix unused variable warning 2013-10-29 19:36:22 +09:00
6709cf694c fix warning: cast size_t as sprintf() arg to int 2013-10-29 19:36:22 +09:00
7259767b09 fix vcxproj 2013-10-29 19:24:29 +09:00
3aa2787e34 fix pcm_seek() to inline 2013-10-29 19:24:29 +09:00
b159a7b095 bump version 2013-10-27 22:43:18 +09:00
be234dc464 add --include-sbr-delay 2013-10-27 22:40:42 +09:00
c9ac59e8d3 fix help message: show -I as shorthand for --ignorelength 2013-10-27 21:32:42 +09:00
9b8f9915c2 remove --sbr-signaling
Instead, we always use explicit/backward compatible SBR signaling by
ASC extension in case of m4a, which is not supported by FDK library
(so we do it on our side).
For LOAS, we use explicit hierarchical signaling.
2013-10-27 21:15:12 +09:00
5ccbfaa710 re-fix #ifdef cond for lrint() 2013-10-26 11:29:30 +09:00
8f05e0751b tag mapping: add recorded date and tempo, remove performer->artist 2013-10-26 01:38:58 +09:00
053279541b fix MSVC12 build issue 2013-10-25 17:04:26 +09:00
f48bf1294c fix build issue on platform where fileno is a naive macro 2013-10-25 10:25:33 +09:00
8896249ac5 update ChangeLog 2013-10-25 00:09:27 +09:00
29 changed files with 1793 additions and 607 deletions

22
.gitignore vendored Normal file
View File

@ -0,0 +1,22 @@
*.o
*~
Makefile
Makefile.in
aclocal.m4
autom4te.cache
compile
config.guess
config.h
config.h.in
config.log
config.status
config.sub
configure
depcomp
install-sh
missing
missings/.deps/
src/.deps/
src/.dirstamp
stamp-h1
fdkaac

119
COPYING
View File

@ -1,17 +1,108 @@
Copyright (C) 2013 nu774 Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: fdkaac
Upstream-Contact: nu774 <honeycomb77@gmail.com>
Source: https://github.com/nu774/fdkaac
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, Files: *
including commercial applications, and to alter it and redistribute it Copyright: 2013-2014 nu774 <honeycomb77@gmail.com>
freely, subject to the following restrictions: License: Zlib
1. The origin of this software must not be misrepresented; you must not Files: missings/getopt.c
claim that you wrote the original software. If you use this software Copyright: 2002 Todd C. Miller <Todd.Miller@courtesan.com>
in a product, an acknowledgment in the product documentation would be 2000 The NetBSD Foundation, Inc.
appreciated but is not required. License: BSD-4-clause
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. Files: missings/getopt.h
3. This notice may not be removed or altered from any source distribution. Copyright: 2000 The NetBSD Foundation, Inc.
License: BSD-4-clause
Files: src/parson.*
Copyright: 2012 Krzysztof Gabis
License: MIT
Files: src/lpc.h
Copyright: 1994-2007 the Xiph.Org Foundation
License: BSD
Files: src/lpc.c
Copyright: 1994-2007 the Xiph.Org Foundation
1992, 1993, 1994 Jutta Degener and Carsten Bormann, Technische Universität Berlin
License: BSD-style
License: Zlib
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
.
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
License: MIT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
License: BSD-4-clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by the NetBSD
Foundation, Inc. and its contributors.
4. Neither the name of The NetBSD Foundation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
.
THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
License: BSD-style
Any use of this software is permitted provided that this notice is not
removed and that neither the authors nor the Technische Universita"t
Berlin are deemed to have made any representations as to the
suitability of this software for any purpose nor are held responsible
for any defects of this software. THERE IS ABSOLUTELY NO WARRANTY FOR
THIS SOFTWARE.

144
ChangeLog
View File

@ -1,6 +1,148 @@
2014-02-17 nu774 <honeycomb77@gmail.com>
* update ChangeLog [HEAD]
* bump version [v0.5.3]
* fix: CAF chan chunk using channel bitmap was not correctly handled
2014-01-18 nu774 <honeycomb77@gmail.com>
* update ChangeLog [origin/master]
* bump version [v0.5.2]
* fix reading of caf file without chan chunk
2013-11-17 nu774 <honeycomb77@gmail.com>
* Merge pull request #9 from rbrito/fix-typo
2013-11-18 Rogério Brito <rbrito@ime.usp.br>
* man: Regen manpage with hyphens escaped.
* README: Remove trailing whitespaces that end up in the manpages.
* README: Fix typo in bandwidth to match CLI options.
2013-11-08 nu774 <honeycomb77@gmail.com>
* add genman.sh, update fdkaac.1
* update ChangeLog
* bump version [v0.5.1]
* fix to use libFDKAAC signaling mode 1
2013-11-05 nu774 <honeycomb77@gmail.com>
* fix README
2013-11-04 nu774 <honeycomb77@gmail.com>
* rename README.md -> README
* Update README -> README.md, generate groff manpage from README.md
* update ChangeLog
* update git2changelog to accept non-ascii output
* add manpage
2013-11-03 nu774 <honeycomb77@gmail.com>
* fix gcc warnings
* Merge pull request #7 from rbrito/misc-fixes
2013-11-03 Rogério Brito <rbrito@ime.usp.br>
* gitignore: Add list of files to ignore.
2013-11-03 nu774 <honeycomb77@gmail.com>
* update ChangeLog
* bump version [v0.5.0]
* add --sbr-ratio to support AACENC_SBR_RATIO appeared on libFDK 3.4.12
* support 7.1 channel mode added on FDK 3.4.12
2013-10-30 nu774 <honeycomb77@gmail.com>
* update ChangeLog
* bump version [v0.4.2]
* use tell() to obtain data chunk offset
* rename aacenc_result_t -> aacenc_frame_t, simplify write_sample()
* prepend 1 sample zero padding in case of SBR and enc_delay is odd
* cleanup interface of aac_encode_frame()
* add some copyright notice
2013-10-29 nu774 <honeycomb77@gmail.com>
* smart padding for better gapless playback
* fix unused variable warning
* fix warning: cast size_t as sprintf() arg to int
* fix vcxproj
* fix pcm_seek() to inline
2013-10-27 nu774 <honeycomb77@gmail.com>
* bump version [v0.4.1]
* add --include-sbr-delay
* fix help message: show -I as shorthand for --ignorelength
* remove --sbr-signaling
2013-10-26 nu774 <honeycomb77@gmail.com>
* re-fix #ifdef cond for lrint() [old]
* tag mapping: add recorded date and tempo, remove performer->artist
2013-10-25 nu774 <honeycomb77@gmail.com>
* fix MSVC12 build issue
* fix build issue on platform where fileno is a naive macro
* update ChangeLog
* bump version [v0.4.0]
* update README
2013-10-24 nu774 <honeycomb77@gmail.com>
* caf input support
* refactor pcm io routines
2013-10-23 nu774 <honeycomb77@gmail.com>
* cleanup metadata handling
* --tag-from-json: properly support number/total format in json track field
2013-10-22 nu774 <honeycomb77@gmail.com> 2013-10-22 nu774 <honeycomb77@gmail.com>
* bump version [HEAD] * bump version [v0.3.3]
* fixed bogus sgpd written on --gapless-mode=1 and 2 * fixed bogus sgpd written on --gapless-mode=1 and 2

386
INSTALL
View File

@ -1,370 +1,32 @@
Installation Instructions Prerequiste
************************* -----------
Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation, To build fdkaac, you need the followings:
Inc. - libfdk-aac (https://github.com/mstorsjo/fdk-aac)
- GNU autoconf, GNU automake
- GNU gettext (for iconv.m4)
Copying and distribution of this file, with or without modification, libfdk-aac is always required, and probably you have to build it yourself.
are permitted in any medium without royalty provided the copyright Others are required only when you build by configure and make on Unix-like
notice and this notice are preserved. This file is offered as-is, enviromnent (including Cygwin or MinGW), and usually you can install them
without warranty of any kind. through package manager of your system if they are not already present.
Basic Installation Unix-like environment
================== ---------------------
Briefly, the shell commands `./configure; make; make install' should You can build and install libfdkaac and fdkaac in the following step.
configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this
`INSTALL' file but do not implement all of the features documented
below. The lack of an optional feature in a given package is not
necessarily a bug. More recommendations for GNU packages can be found
in *note Makefile Conventions: (standards)Makefile Conventions.
The `configure' shell script attempts to guess correct values for 1) extract the source, and cd to the source directory
various system-dependent variables used during compilation. It uses 2) autoreconf -i
those values to create a `Makefile' in each directory of the package. 3) ./configure
It may also create one or more `.h' files containing system-dependent 4) make
definitions. Finally, it creates a shell script `config.status' that 5) sudo make install
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache' Depending on your requirements, you might want to add some extra arguments to
and enabled with `--cache-file=config.cache' or simply `-C') that saves configure script.
the results of its tests to speed up reconfiguring. Caching is You have to install libfdk-aac first, and do the same for fdkaac.
disabled by default to prevent problems with accidental use of stale
cache files.
If you need to do unusual things to compile the package, please try Windows, MSVC
to figure out how `configure' could check whether to do them, and mail -------------
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You need `configure.ac' if
you want to change it or regenerate `configure' using a newer version
of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system.
Running `configure' might take a while. While running, it prints
some messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package, generally using the just-built uninstalled binaries.
4. Type `make install' to install the programs and any data files and
documentation. When installing into a prefix owned by root, it is
recommended that the package be configured and built as a regular
user, and only the `make install' phase executed with root
privileges.
5. Optionally, type `make installcheck' to repeat any self-tests, but
this time using the binaries in their final installed location.
This target does not install anything. Running this target as a
regular user, particularly if the prior `make install' required
root privileges, verifies that the installation completed
correctly.
6. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
7. Often, you can also type `make uninstall' to remove the installed
files again. In practice, not all packages have tested that
uninstallation works correctly, even though it is required by the
GNU Coding Standards.
8. Some packages, particularly those that use Automake, provide `make
distcheck', which can by used by developers to test that all other
targets like `make install' and `make uninstall' work correctly.
This target is generally not run by end users.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'. This
is known as a "VPATH" build.
With a non-GNU `make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before
reconfiguring for another architecture.
On MacOS X 10.5 and later systems, you can create libraries and
executables that work on multiple system types--known as "fat" or
"universal" binaries--by specifying multiple `-arch' options to the
compiler but only a single `-arch' option to the preprocessor. Like
this:
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CPP="gcc -E" CXXCPP="g++ -E"
This is not guaranteed to produce working output in all cases, you
may have to build one architecture at a time and combine the results
using the `lipo' tool if you have problems.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX', where PREFIX must be an
absolute file name.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them. In general, the
default for these options is expressed in terms of `${prefix}', so that
specifying just `--prefix' will affect all of the other directory
specifications that were not explicitly provided.
The most portable way to affect installation locations is to pass the
correct locations to `configure'; however, many packages provide one or
both of the following shortcuts of passing variable assignments to the
`make install' command line to change installation locations without
having to reconfigure or recompile.
The first method involves providing an override variable for each
affected directory. For example, `make install
prefix=/alternate/directory' will choose an alternate location for all
directory configuration variables that were expressed in terms of
`${prefix}'. Any directories that were specified during `configure',
but not in terms of `${prefix}', must each be overridden at install
time for the entire installation to be relocated. The approach of
makefile variable overrides for each directory variable is required by
the GNU Coding Standards, and ideally causes no recompilation.
However, some platforms have known limitations with the semantics of
shared libraries that end up requiring recompilation when using this
method, particularly noticeable in packages that use GNU Libtool.
The second method involves providing the `DESTDIR' variable. For
example, `make install DESTDIR=/alternate/directory' will prepend
`/alternate/directory' before all installation names. The approach of
`DESTDIR' overrides is not required by the GNU Coding Standards, and
does not work on platforms that have drive letters. On the other hand,
it does better at avoiding recompilation issues, and works well even
when some directory options were not specified in terms of `${prefix}'
at `configure' time.
Optional Features
=================
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Some packages offer the ability to configure how verbose the
execution of `make' will be. For these packages, running `./configure
--enable-silent-rules' sets the default to minimal output, which can be
overridden with `make V=1'; while running `./configure
--disable-silent-rules' sets the default to verbose, which can be
overridden with `make V=0'.
Particular systems
==================
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
CC is not installed, it is recommended to use the following options in
order to use an ANSI C compiler:
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
HP-UX `make' updates targets which have the same time stamps as
their prerequisites, which makes it generally unusable when shipped
generated files such as `configure' are involved. Use GNU `make'
instead.
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
a workaround. If GNU CC is not installed, it is therefore recommended
to try
./configure CC="cc"
and if that doesn't work, try
./configure CC="cc -nodtk"
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
directory contains several dysfunctional programs; working variants of
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
in your `PATH', put it _after_ `/usr/bin'.
On Haiku, software installed for all users goes in `/boot/common',
not `/usr/local'. It is recommended to use the following options:
./configure --prefix=/boot/common
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS
KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf bug. Until the bug is fixed you can use this workaround:
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of all of the options to `configure', and exit.
`--help=short'
`--help=recursive'
Print a summary of the options unique to this package's
`configure', and exit. The `short' variant lists options used
only in the top level, while the `recursive' variant lists options
also present in any nested packages.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--prefix=DIR'
Use DIR as the installation prefix. *note Installation Names::
for more details, including other options available for fine-tuning
the installation locations.
`--no-create'
`-n'
Run the configure checks, but stop before creating any output
files.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.
Extract libfdk-aac under fdkaac directory, and open MSVC/fdkaac.sln.

View File

@ -98,6 +98,8 @@ copy ..\fdk-aac\libSYS\include\machine_type.h include\fdk-aac\ </Command>
<ClCompile Include="..\src\aacenc.c" /> <ClCompile Include="..\src\aacenc.c" />
<ClCompile Include="..\src\caf_reader.c" /> <ClCompile Include="..\src\caf_reader.c" />
<ClCompile Include="..\src\compat_win32.c" /> <ClCompile Include="..\src\compat_win32.c" />
<ClCompile Include="..\src\extrapolater.c" />
<ClCompile Include="..\src\lpc.c" />
<ClCompile Include="..\src\lpcm.c" /> <ClCompile Include="..\src\lpcm.c" />
<ClCompile Include="..\src\m4af.c" /> <ClCompile Include="..\src\m4af.c" />
<ClCompile Include="..\src\main.c" /> <ClCompile Include="..\src\main.c" />
@ -111,7 +113,10 @@ copy ..\fdk-aac\libSYS\include\machine_type.h include\fdk-aac\ </Command>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\missings\getopt.h" /> <ClInclude Include="..\missings\getopt.h" />
<ClInclude Include="..\src\aacenc.h" /> <ClInclude Include="..\src\aacenc.h" />
<ClInclude Include="..\src\caf_reader.h" />
<ClInclude Include="..\src\catypes.h" />
<ClInclude Include="..\src\compat.h" /> <ClInclude Include="..\src\compat.h" />
<ClInclude Include="..\src\lpc.h" />
<ClInclude Include="..\src\lpcm.h" /> <ClInclude Include="..\src\lpcm.h" />
<ClInclude Include="..\src\m4af.h" /> <ClInclude Include="..\src\m4af.h" />
<ClInclude Include="..\src\m4af_endian.h" /> <ClInclude Include="..\src\m4af_endian.h" />

View File

@ -24,6 +24,12 @@
<ClCompile Include="..\src\compat_win32.c"> <ClCompile Include="..\src\compat_win32.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\src\extrapolater.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\lpc.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\lpcm.c"> <ClCompile Include="..\src\lpcm.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -62,6 +68,9 @@
<ClInclude Include="..\src\compat.h"> <ClInclude Include="..\src\compat.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\src\lpc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\lpcm.h"> <ClInclude Include="..\src\lpcm.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>

View File

@ -6,6 +6,8 @@ bin_PROGRAMS = fdkaac
fdkaac_SOURCES = \ fdkaac_SOURCES = \
src/aacenc.c \ src/aacenc.c \
src/caf_reader.c \ src/caf_reader.c \
src/extrapolater.c \
src/lpc.c \
src/lpcm.c \ src/lpcm.c \
src/m4af.c \ src/m4af.c \
src/main.c \ src/main.c \
@ -16,6 +18,8 @@ fdkaac_SOURCES = \
src/progress.c \ src/progress.c \
src/wav_reader.c src/wav_reader.c
dist_man_MANS = man/fdkaac.1
fdkaac_LDADD = \ fdkaac_LDADD = \
@LIBICONV@ -lfdk-aac -lm @LIBICONV@ -lfdk-aac -lm

412
README
View File

@ -1,122 +1,332 @@
========================================================================== % FDKAAC(1)
fdkaac - command line frontend encoder for libfdk-aac % nu774 <honeycomb77@gmail.com>
========================================================================== % November, 2013
Prerequisites NAME
------------- ====
You need libfdk-aac.
On Posix environment, you will also need GNU gettext (for iconv.m4) and
GNU autoconf/automake.
How to build on Posix environment fdkaac - command line frontend for libfdk-aac encoder
---------------------------------
First, you need to build libfdk-aac and install on your system.
Once you have done it, the following will do the task.
(MinGW build can be done the same way, and doesn't require gettext/iconv)
$ autoreconf -i SYNOPSIS
$ ./configure && make && make install ========
How to build on MSVC **fdkaac** [OPTIONS] [FILE]
--------------------
First you have to extract libfdk-aac source here, so that directory tree will
look like the following:
+- fdk-aac ---+-documentation
| +-libAACdec
| +-libAACenc
| :
+- m4
+- missings
+- MSVC
+- src
MSVC solution for Visual Studio 2010 is under MSVC directory. DESCRIPTION
===========
Available input format **fdkaac** reads linear PCM audio in either WAV, raw PCM, or CAF format,
---------------------- and encodes it into either M4A / AAC file.
WAV, RF64, CAF, RAW, upto 32bit int / 64bit float format is supported.
Metadata in CAF info chunk can be read and copied to the resulting m4a.
This is especially useful and works well when you pipe from ffmpeg via CAF.
For example, you can copy tag from original "foo.flac" to "foo.m4a"
through the following pipeline:
$ ffmpeg -i foo.flac -f caf - | fdkaac -m3 - -o foo.m4a If the input file is "-", data is read from stdin. Likewise, if the
output file is "-", data is written to stdout if one of streamable AAC
transport formats are selected by **-f**.
Since FDK AAC encoder is implemented based on fixed point integer, When CAF input and M4A output is used, tags in CAF file are copied into
encoder itself handles 16bit input only. the resulting M4A.
Therefore, when feeding non-integer input, be careful so that input doesn't
exceed 0dBFS to avoid hard clips.
You might also want to apply dither/noise shape beforehand when your input
has higher resolution.
Note that fdkaac doesn't automatically resample for you OPTIONS
when input samplerate is not supported by AAC spec. =======
Tagging Options -h, --help
--------------- : Show command help
Generic tagging options like --tag, --tag-from-file, --long-tag allows you
to set arbitrary tags.
Available tags and their fcc (four char code) for --tag and --tag-from-file
can be found at http://code.google.com/p/mp4v2/wiki/iTunesMetadata
For tags such as Artist where first char of fcc is copyright sign, -o \<FILE\>
you can skip first char and just say like --tag="ART:Foo Bar" or : Output filename.
--tag-from-file=lyr:/path/to/your/lyrics.txt
Currently, --tag-from-file just stores file contents into m4a without any -p, --profile \<n\>
character encoding / line terminater conversion. : Target profile (MPEG4 audio object type, AOT)
Therefore, only use UTF-8 (without BOM) when setting text tags by this option.
On the other hand, --tag / --long-tag (and other command line arguments) are 2
converted from locale character encoding to UTF-8 on Posix environment. : MPEG-4 AAC LC (default)
On Windows, command line arguments are always treated as Unicode.
Tagging using JSON 5
------------------ : MPEG-4 HE-AAC (SBR)
With --tag-from-json, fdkaac can read JSON file and set tags from it.
By default, tags are assumed to be in the root object(dictionary) like this:
{ 29
"title": "No Expectations", : MPEG-4 HE-AAC v2 (SBR+PS)
"artist": "The Rolling Stones",
"album": "Beggars Banquet",
"track": 2
}
In this case, you can simply specify the filename like: 23
--tag-from-json=/path/to/json : MPEG-4 AAC LD
If the object containing tags is placed somewhere else, you can optionally 39
specify the path of the object with dotted notation. : MPEG-4 AAC ELD
{ 129
"format" : { : MPEG-2 AAC LC
"filename" : "Middle Curse.flac",
"nb_streams" : 1,
"format_name" : "flac",
"format_long_name" : "raw FLAC",
"start_time" : "N/A",
"duration" : "216.146667",
"size" : "11851007.000000",
"bit_rate" : "438628.000000",
"tags" : {
"ALBUM" : "Scary World Theory",
"ARTIST" : "Lali Puna",
"DATE" : "2001",
"DISCID" : "9208CC0A",
"TITLE" : "Middle Curse",
"TRACKTOTAL" : "10",
"track" : "2"
}
}
}
In this example, tags are placed under the object "format.tags". 132
("format" is a child of the root, and "tags" is a child of the "format"). : MPEG-2 HE-AAC (SBR)
In this case, you can say:
--tag-from-json=/path/to/json?format.tags
For your information, ffprobe of ffmpeg project (or avprobe of libav) can 156
output media information/metadata in json format like this. : MPEG-2 HE-AAC v2 (SBR+PS)
-b, --bitrate \<n\>
: Target bitrate (for CBR)
-m, --bitrate-mode \<n\>
: Bitrate configuration mode. Available VBR quality value depends on
other parameters such as profile, sample rate, or number of
channels.
0
: CBR (default)
1-5
: VBR (higher value -\> higher bitrate)
-w, --bandwidth \<n\>
: Frequency bandwidth (lowpass cut-off frequency) in Hz. Available on
AAC LC only.
-a, --afterburner \<n\>
: Configure afterburner mode. When enabled, quality is increased at
the expense of additional computational workload.
0
: Off
1
: On (default)
-L, --lowdelay-sbr \<n\>
: Configure SBR activity on AAC ELD.
-1
: Use ELD SBR auto configuration
0
: Disable SBR on ELD (default)
1
: Enable SBR on ELD
-s, --sbr-ratio \<n\>
: Controls activation of downsampled SBR.
0
: Use lib default (default)
1
: Use downsampled SBR (default for ELD+SBR)
2
: Use dual-rate SBR (default for HE-AAC)
Dual-rate SBR is what is normally used for HE-AAC, where AAC is
encoded at half the sample rate of SBR, hence "dual rate". On the
other hand, downsampled SBR uses same sample rate for both of AAC
and SBR (single rate), therefore downsampled SBR typically consumes
more bitrate.
Downsampled SBR is newly introduced feature in FDK encoder library
version 3.4.12. When libfdk-aac in the system doesn't support this,
dual-rate SBR will be used. When available, dual-rate SBR is the
default for HE-AAC and downsampled SBR is the default for ELD+SBR.
Note that downsampled HE-AAC is not so common as dual-rate one. When
downsampled HE-AAC is selected, **fdkaac** is forced to choose
explicit hierarchical SBR signaling, which (at least) iTunes doesn't
accept.
-f, --transport-format \<n\>
: Transport format. Tagging and gapless playback is only available on
M4A. Streaming to stdout is only available on others.
0
: M4A (default)
1
: ADIF
2
: ADTS
6
: LATM MCP=1
7
: LATM MCP=0
10
: LOAS/LATM (LATM within LOAS)
-C, --adts-crc-check
: Add CRC protection on ADTS header.
-h, --header-period \<n\>
: StreamMuxConfig/PCE repetition period in the transport layer.
-G, --gapless-mode \<n\>
: Method to declare amount of encoder delay (and padding) in M4A
container. These values are mandatory for proper gapless playback on
player side.
0
: iTunSMPB (default)
1
: ISO standard (edts and sgpd)
2
: Both
--include-sbr-delay
: When specified, count SBR decoder delay in encoder delay.
This is not iTunes compatible and will lead to gapless playback
issue on LC only decoder, but this is the default behavior of FDK
library.
Whether counting SBR decoder delay in encoder delay or not result in
incompatibility in gapless playback. You should pick which one will
work for your favorite player.
However, it's better not to choose SBR at all if you want gapless
playback. LC doesn't have such issues.
-I, --ignorelength
: Ignore length field of data chunk in input WAV file.
-S, --silent
: Don't print progress messages.
--moov-before-mdat
: Place moov box before mdat box in M4A container. This option might
be important for some hardware players, that are known to refuse
moov box placed after mdat box.
-R, --raw
: Regard input as raw PCM.
--raw-channels \<n\>
: Specify number of channels of raw input (default: 2)
--raw-rate \<n\>
: Specify sample rate of raw input (default: 44100)
--raw-format \<spec\>
: Specify sample format of raw input (default: "S16L"). **Spec** is as
the following (case insensitive):
1st char -- type of sample
: **S** (igned) | **U** (nsigned) | **F** (loat)
2nd part (in digits)
: bits per channel
Last char -- endianness (can be omitted)
: **L** (ittle, default) | **B** (ig)
--title \<string\>
: Set title tag.
--artist \<string\>
: Set artist tag.
--album \<string\>
: Set album tag.
--genre \<string\>
: Set genre tag.
--date \<string\>
: Set date tag.
--composer \<string\>
: Set composer tag.
--grouping \<string\>
: Set grouping tag.
--comment \<string\>
: Set comment tag.
--album-artist \<string\>
: Set album artist tag.
--track \<number[/total]\>
: Set track tag, with or without number of total tracks.
--disk \<number[/total]\>
: Set disk tag, with or without number of total discs.
--tempo \<n\>
: Set tempo (BPM) tag.
--tag \<fcc\>:\<value\>
: Set iTunes predefined tag with explicit fourcc key and value. See
[https://code.google.com/p/mp4v2/wiki/iTunesMetadata](https://code.google.com/p/mp4v2/wiki/iTunesMetadata)
for known predefined keys. You can omit first char of **fcc** when
it is the copyright sign.
--tag-from-file \<fcc\>:\<filename\>
: Same as --tag, but set content of file as tag value.
--long-tag \<name\>:\<value\>
: Set arbitrary tag as iTunes custom metadata. Stored in
com.apple.iTunes field.
--tag-from-json \<filename[?dot\_notation]\>
: Read tags from JSON. By default, tags are assumed to be direct
children of the root object in JSON. Optionally you can specify
arbitrary dot notation to locate the object containing tags.
EXAMPLES
========
Encode WAV file into a M4A file. MPEG4 AAC LC, VBR quality 3:
fdkaac -m3 foo.wav
Encode WAV file into a M4A file. MPEG4 HE-AAC, bitrate 64kbps:
fdkaac -p5 -b64 foo.wav
Piping from **ffmpeg** (you need version supporting CAF output):
ffmpeg -i foo.flac -f caf - | fdkaac -b128 - -o foo.m4a
Import tags via json:
ffprobe -v 0 -of json -show_format foo.flac >foo.json
flac -dc foo.flac | \
fdkaac - -ox.m4a -m2 --import-tag-from-json=foo.json?format.tags
NOTES
=====
Upto 32bit integer or 64bit floating point format is supported as input.
However, FDK library is implemented based on fixed point math and only
supports 16bit integer PCM. Therefore, be wary of clipping. You might
want to dither/noise shape beforehand when your input has higher
resolution.
Following channel layouts are supported by the encoder.
1ch
: C
2ch
: L R
3ch
: C L R
4ch
: C L R Cs
5ch
: C L R Ls Rs
5.1ch
: C L R Ls Rs LFE
7.1ch (front)
: C Lc Rc L R Ls Rs LFE
7.1ch (rear)
: C L R Ls Rs Rls Rrs LFE
Note that not all tags can be read/written this way.

2
genman.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
pandoc -s -f markdown -t man README >fdkaac.1 && mv -f fdkaac.1 man/fdkaac.1

View File

@ -39,6 +39,6 @@ with Popen(GITLOG_CMD, shell=False, stdout=PIPE).stdout as pipe:
commits = parse_gitlog(pipe) commits = parse_gitlog(pipe)
commits_by_date_author = groupby(commits, key=lambda x: (x.date, x.author)) commits_by_date_author = groupby(commits, key=lambda x: (x.date, x.author))
for (date, author), commits in commits_by_date_author: for (date, author), commits in commits_by_date_author:
output('{0} {1}\n\n'.format(date, author)) output(u'{0} {1}\n\n'.format(date, author).encode('utf-8'))
for c in commits: for c in commits:
output(' * {0}{1}\n\n'.format(c.subject, c.ref)) output(u' * {0}{1}\n\n'.format(c.subject, c.ref).encode('utf-8'))

493
man/fdkaac.1 Normal file
View File

@ -0,0 +1,493 @@
.TH FDKAAC 1 "November, 2013"
.SH NAME
.PP
fdkaac \- command line frontend for libfdk\-aac encoder
.SH SYNOPSIS
.PP
\f[B]fdkaac\f[] [OPTIONS][FILE]
.SH DESCRIPTION
.PP
\f[B]fdkaac\f[] reads linear PCM audio in either WAV, raw PCM, or CAF
format, and encodes it into either M4A / AAC file.
.PP
If the input file is "\-", data is read from stdin.
Likewise, if the output file is "\-", data is written to stdout if one
of streamable AAC transport formats are selected by \f[B]\-f\f[].
.PP
When CAF input and M4A output is used, tags in CAF file are copied into
the resulting M4A.
.SH OPTIONS
.TP
.B \-h, \-\-help
Show command help
.RS
.RE
.TP
.B \-o <FILE>
Output filename.
.RS
.RE
.TP
.B \-p, \-\-profile <n>
Target profile (MPEG4 audio object type, AOT)
.RS
.TP
.B 2
MPEG\-4 AAC LC (default)
.RS
.RE
.TP
.B 5
MPEG\-4 HE\-AAC (SBR)
.RS
.RE
.TP
.B 29
MPEG\-4 HE\-AAC v2 (SBR+PS)
.RS
.RE
.TP
.B 23
MPEG\-4 AAC LD
.RS
.RE
.TP
.B 39
MPEG\-4 AAC ELD
.RS
.RE
.TP
.B 129
MPEG\-2 AAC LC
.RS
.RE
.TP
.B 132
MPEG\-2 HE\-AAC (SBR)
.RS
.RE
.TP
.B 156
MPEG\-2 HE\-AAC v2 (SBR+PS)
.RS
.RE
.RE
.TP
.B \-b, \-\-bitrate <n>
Target bitrate (for CBR)
.RS
.RE
.TP
.B \-m, \-\-bitrate\-mode <n>
Bitrate configuration mode.
Available VBR quality value depends on other parameters such as profile,
sample rate, or number of channels.
.RS
.TP
.B 0
CBR (default)
.RS
.RE
.TP
.B 1\-5
VBR (higher value \-> higher bitrate)
.RS
.RE
.RE
.TP
.B \-w, \-\-bandwidth <n>
Frequency bandwidth (lowpass cut\-off frequency) in Hz.
Available on AAC LC only.
.RS
.RE
.TP
.B \-a, \-\-afterburner <n>
Configure afterburner mode.
When enabled, quality is increased at the expense of additional
computational workload.
.RS
.TP
.B 0
Off
.RS
.RE
.TP
.B 1
On (default)
.RS
.RE
.RE
.TP
.B \-L, \-\-lowdelay\-sbr <n>
Configure SBR activity on AAC ELD.
.RS
.TP
.B \-1
Use ELD SBR auto configuration
.RS
.RE
.TP
.B 0
Disable SBR on ELD (default)
.RS
.RE
.TP
.B 1
Enable SBR on ELD
.RS
.RE
.RE
.TP
.B \-s, \-\-sbr\-ratio <n>
Controls activation of downsampled SBR.
.RS
.TP
.B 0
Use lib default (default)
.RS
.RE
.TP
.B 1
Use downsampled SBR (default for ELD+SBR)
.RS
.RE
.TP
.B 2
Use dual\-rate SBR (default for HE\-AAC)
.RS
.RE
.PP
Dual\-rate SBR is what is normally used for HE\-AAC, where AAC is
encoded at half the sample rate of SBR, hence "dual rate".
On the other hand, downsampled SBR uses same sample rate for both of AAC
and SBR (single rate), therefore downsampled SBR typically consumes more
bitrate.
.PP
Downsampled SBR is newly introduced feature in FDK encoder library
version 3.4.12.
When libfdk\-aac in the system doesn\[aq]t support this, dual\-rate SBR
will be used.
When available, dual\-rate SBR is the default for HE\-AAC and
downsampled SBR is the default for ELD+SBR.
.PP
Note that downsampled HE\-AAC is not so common as dual\-rate one.
When downsampled HE\-AAC is selected, \f[B]fdkaac\f[] is forced to
choose explicit hierarchical SBR signaling, which (at least) iTunes
doesn\[aq]t accept.
.RE
.TP
.B \-f, \-\-transport\-format <n>
Transport format.
Tagging and gapless playback is only available on M4A.
Streaming to stdout is only available on others.
.RS
.TP
.B 0
M4A (default)
.RS
.RE
.TP
.B 1
ADIF
.RS
.RE
.TP
.B 2
ADTS
.RS
.RE
.TP
.B 6
LATM MCP=1
.RS
.RE
.TP
.B 7
LATM MCP=0
.RS
.RE
.TP
.B 10
LOAS/LATM (LATM within LOAS)
.RS
.RE
.RE
.TP
.B \-C, \-\-adts\-crc\-check
Add CRC protection on ADTS header.
.RS
.RE
.TP
.B \-h, \-\-header\-period <n>
StreamMuxConfig/PCE repetition period in the transport layer.
.RS
.RE
.TP
.B \-G, \-\-gapless\-mode <n>
Method to declare amount of encoder delay (and padding) in M4A
container.
These values are mandatory for proper gapless playback on player side.
.RS
.TP
.B 0
iTunSMPB (default)
.RS
.RE
.TP
.B 1
ISO standard (edts and sgpd)
.RS
.RE
.TP
.B 2
Both
.RS
.RE
.RE
.TP
.B \-\-include\-sbr\-delay
When specified, count SBR decoder delay in encoder delay.
.RS
.PP
This is not iTunes compatible and will lead to gapless playback issue on
LC only decoder, but this is the default behavior of FDK library.
.PP
Whether counting SBR decoder delay in encoder delay or not result in
incompatibility in gapless playback.
You should pick which one will work for your favorite player.
.PP
However, it\[aq]s better not to choose SBR at all if you want gapless
playback.
LC doesn\[aq]t have such issues.
.RE
.TP
.B \-I, \-\-ignorelength
Ignore length field of data chunk in input WAV file.
.RS
.RE
.TP
.B \-S, \-\-silent
Don\[aq]t print progress messages.
.RS
.RE
.TP
.B \-\-moov\-before\-mdat
Place moov box before mdat box in M4A container.
This option might be important for some hardware players, that are known
to refuse moov box placed after mdat box.
.RS
.RE
.TP
.B \-R, \-\-raw
Regard input as raw PCM.
.RS
.RE
.TP
.B \-\-raw\-channels <n>
Specify number of channels of raw input (default: 2)
.RS
.RE
.TP
.B \-\-raw\-rate <n>
Specify sample rate of raw input (default: 44100)
.RS
.RE
.TP
.B \-\-raw\-format <spec>
Specify sample format of raw input (default: "S16L").
\f[B]Spec\f[] is as the following (case insensitive):
.RS
.TP
.B 1st char \-\- type of sample
\f[B]S\f[] (igned) | \f[B]U\f[] (nsigned) | \f[B]F\f[] (loat)
.RS
.RE
.TP
.B 2nd part (in digits)
bits per channel
.RS
.RE
.TP
.B Last char \-\- endianness (can be omitted)
\f[B]L\f[] (ittle, default) | \f[B]B\f[] (ig)
.RS
.RE
.RE
.TP
.B \-\-title <string>
Set title tag.
.RS
.RE
.TP
.B \-\-artist <string>
Set artist tag.
.RS
.RE
.TP
.B \-\-album <string>
Set album tag.
.RS
.RE
.TP
.B \-\-genre <string>
Set genre tag.
.RS
.RE
.TP
.B \-\-date <string>
Set date tag.
.RS
.RE
.TP
.B \-\-composer <string>
Set composer tag.
.RS
.RE
.TP
.B \-\-grouping <string>
Set grouping tag.
.RS
.RE
.TP
.B \-\-comment <string>
Set comment tag.
.RS
.RE
.TP
.B \-\-album\-artist <string>
Set album artist tag.
.RS
.RE
.TP
.B \-\-track <number[/total]>
Set track tag, with or without number of total tracks.
.RS
.RE
.TP
.B \-\-disk <number[/total]>
Set disk tag, with or without number of total discs.
.RS
.RE
.TP
.B \-\-tempo <n>
Set tempo (BPM) tag.
.RS
.RE
.TP
.B \-\-tag <fcc>:<value>
Set iTunes predefined tag with explicit fourcc key and value.
See <https://code.google.com/p/mp4v2/wiki/iTunesMetadata> for known
predefined keys.
You can omit first char of \f[B]fcc\f[] when it is the copyright sign.
.RS
.RE
.TP
.B \-\-tag\-from\-file <fcc>:<filename>
Same as \-\-tag, but set content of file as tag value.
.RS
.RE
.TP
.B \-\-long\-tag <name>:<value>
Set arbitrary tag as iTunes custom metadata.
Stored in com.apple.iTunes field.
.RS
.RE
.TP
.B \-\-tag\-from\-json <filename[?dot_notation]>
Read tags from JSON.
By default, tags are assumed to be direct children of the root object in
JSON.
Optionally you can specify arbitrary dot notation to locate the object
containing tags.
.RS
.RE
.SH EXAMPLES
.PP
Encode WAV file into a M4A file.
MPEG4 AAC LC, VBR quality 3:
.IP
.nf
\f[C]
fdkaac\ \-m3\ foo.wav
\f[]
.fi
.PP
Encode WAV file into a M4A file.
MPEG4 HE\-AAC, bitrate 64kbps:
.IP
.nf
\f[C]
fdkaac\ \-p5\ \-b64\ foo.wav
\f[]
.fi
.PP
Piping from \f[B]ffmpeg\f[] (you need version supporting CAF output):
.IP
.nf
\f[C]
ffmpeg\ \-i\ foo.flac\ \-f\ caf\ \-\ |\ fdkaac\ \-b128\ \-\ \-o\ foo.m4a
\f[]
.fi
.PP
Import tags via json:
.IP
.nf
\f[C]
ffprobe\ \-v\ 0\ \-of\ json\ \-show_format\ foo.flac\ >foo.json
flac\ \-dc\ foo.flac\ |\ \\
fdkaac\ \-\ \-ox.m4a\ \-m2\ \-\-import\-tag\-from\-json=foo.json?format.tags
\f[]
.fi
.SH NOTES
.PP
Upto 32bit integer or 64bit floating point format is supported as input.
However, FDK library is implemented based on fixed point math and only
supports 16bit integer PCM.
Therefore, be wary of clipping.
You might want to dither/noise shape beforehand when your input has
higher resolution.
.PP
Following channel layouts are supported by the encoder.
.TP
.B 1ch
C
.RS
.RE
.TP
.B 2ch
L R
.RS
.RE
.TP
.B 3ch
C L R
.RS
.RE
.TP
.B 4ch
C L R Cs
.RS
.RE
.TP
.B 5ch
C L R Ls Rs
.RS
.RE
.TP
.B 5.1ch
C L R Ls Rs LFE
.RS
.RE
.TP
.B 7.1ch (front)
C Lc Rc L R Ls Rs LFE
.RS
.RE
.TP
.B 7.1ch (rear)
C L R Ls Rs Rls Rrs LFE
.RS
.RE
.SH AUTHORS
nu774 <honeycomb77@gmail.com>.

View File

@ -10,8 +10,20 @@
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "aacenc.h" #include "aacenc.h"
int aacenc_is_sbr_ratio_available()
{
#if AACENCODER_LIB_VL0 < 3 || (AACENCODER_LIB_VL0==3 && AACENCODER_LIB_VL1<4)
return 0;
#else
LIB_INFO lib_info;
aacenc_get_lib_info(&lib_info);
return lib_info.version > 0x03040000;
#endif
}
int aacenc_is_sbr_active(const aacenc_param_t *params) int aacenc_is_sbr_active(const aacenc_param_t *params)
{ {
switch (params->profile) { switch (params->profile) {
@ -25,15 +37,42 @@ int aacenc_is_sbr_active(const aacenc_param_t *params)
return 0; return 0;
} }
int aacenc_is_dual_rate_sbr(const aacenc_param_t *params)
{
if (params->profile == AOT_PS || params->profile == AOT_MP2_PS)
return 1;
else if (params->profile == AOT_SBR || params->profile == AOT_MP2_SBR)
return params->sbr_ratio == 0 || params->sbr_ratio == 2;
else if (params->profile == AOT_ER_AAC_ELD && params->lowdelay_sbr)
return params->sbr_ratio == 2;
return 0;
}
void aacenc_get_lib_info(LIB_INFO *info)
{
LIB_INFO *lib_info = 0;
lib_info = calloc(FDK_MODULE_LAST, sizeof(LIB_INFO));
if (aacEncGetLibInfo(lib_info) == AACENC_OK) {
int i;
for (i = 0; i < FDK_MODULE_LAST; ++i) {
if (lib_info[i].module_id == FDK_AACENC) {
memcpy(info, &lib_info[i], sizeof(LIB_INFO));
break;
}
}
}
free(lib_info);
}
static static
int aacenc_channel_mode(const pcm_sample_description_t *format) int aacenc_channel_mode(const pcm_sample_description_t *format)
{ {
uint32_t chanmask = format->channel_mask; uint32_t chanmask = format->channel_mask;
if (format->channels_per_frame > 6) if (format->channels_per_frame > 8)
return 0; return 0;
if (!chanmask) { if (!chanmask) {
static uint32_t defaults[] = { 0x4, 0x3, 0x7, 0, 0x37, 0x3f }; static uint32_t defaults[] = { 0x4, 0x3, 0x7, 0, 0x37, 0x3f, 0, 0x63f };
chanmask = defaults[format->channels_per_frame - 1]; chanmask = defaults[format->channels_per_frame - 1];
} }
switch (chanmask) { switch (chanmask) {
@ -45,6 +84,10 @@ int aacenc_channel_mode(const pcm_sample_description_t *format)
case 0x107: return MODE_1_2_1; case 0x107: return MODE_1_2_1;
case 0x607: return MODE_1_2_2; case 0x607: return MODE_1_2_2;
case 0x60f: return MODE_1_2_2_1; case 0x60f: return MODE_1_2_2_1;
#if AACENCODER_LIB_VL0 > 3 || (AACENCODER_LIB_VL0==3 && AACENCODER_LIB_VL1>=4)
case 0xff: return MODE_1_2_2_2_1;
case 0x63f: return MODE_7_1_REAR_SURROUND;
#endif
} }
return 0; return 0;
} }
@ -55,8 +98,11 @@ int aacenc_init(HANDLE_AACENCODER *encoder, const aacenc_param_t *params,
{ {
int channel_mode; int channel_mode;
int aot; int aot;
LIB_INFO lib_info;
*encoder = 0; *encoder = 0;
aacenc_get_lib_info(&lib_info);
if ((channel_mode = aacenc_channel_mode(format)) == 0) { if ((channel_mode = aacenc_channel_mode(format)) == 0) {
fprintf(stderr, "ERROR: unsupported channel layout\n"); fprintf(stderr, "ERROR: unsupported channel layout\n");
goto FAIL; goto FAIL;
@ -82,13 +128,21 @@ int aacenc_init(HANDLE_AACENCODER *encoder, const aacenc_param_t *params,
fprintf(stderr, "ERROR: unsupported sample rate\n"); fprintf(stderr, "ERROR: unsupported sample rate\n");
goto FAIL; goto FAIL;
} }
aacEncoder_SetParam(*encoder, AACENC_CHANNELMODE, channel_mode); if (aacEncoder_SetParam(*encoder, AACENC_CHANNELMODE,
channel_mode) != AACENC_OK) {
fprintf(stderr, "ERROR: unsupported channel mode\n");
goto FAIL;
}
aacEncoder_SetParam(*encoder, AACENC_BANDWIDTH, params->bandwidth); aacEncoder_SetParam(*encoder, AACENC_BANDWIDTH, params->bandwidth);
aacEncoder_SetParam(*encoder, AACENC_CHANNELORDER, 1); aacEncoder_SetParam(*encoder, AACENC_CHANNELORDER, 1);
aacEncoder_SetParam(*encoder, AACENC_AFTERBURNER, !!params->afterburner); aacEncoder_SetParam(*encoder, AACENC_AFTERBURNER, !!params->afterburner);
if (aot == AOT_ER_AAC_ELD && params->lowdelay_sbr) aacEncoder_SetParam(*encoder, AACENC_SBR_MODE, params->lowdelay_sbr);
aacEncoder_SetParam(*encoder, AACENC_SBR_MODE, 1);
#if AACENCODER_LIB_VL0 > 3 || (AACENCODER_LIB_VL0==3 && AACENCODER_LIB_VL1>=4)
if (lib_info.version > 0x03040000)
aacEncoder_SetParam(*encoder, AACENC_SBR_RATIO, params->sbr_ratio);
#endif
if (aacEncoder_SetParam(*encoder, AACENC_TRANSMUX, if (aacEncoder_SetParam(*encoder, AACENC_TRANSMUX,
params->transport_format) != AACENC_OK) { params->transport_format) != AACENC_OK) {
@ -124,7 +178,7 @@ FAIL:
int aac_encode_frame(HANDLE_AACENCODER encoder, int aac_encode_frame(HANDLE_AACENCODER encoder,
const pcm_sample_description_t *format, const pcm_sample_description_t *format,
const int16_t *input, unsigned iframes, const int16_t *input, unsigned iframes,
uint8_t **output, uint32_t *olen, uint32_t *osize) aacenc_frame_t *output)
{ {
uint32_t ilen = iframes * format->channels_per_frame; uint32_t ilen = iframes * format->channels_per_frame;
AACENC_BufDesc ibdesc = { 0 }, obdesc = { 0 }; AACENC_BufDesc ibdesc = { 0 }, obdesc = { 0 };
@ -142,12 +196,14 @@ int aac_encode_frame(HANDLE_AACENCODER encoder,
unsigned channel_mode, obytes; unsigned channel_mode, obytes;
channel_mode = aacEncoder_GetParam(encoder, AACENC_CHANNELMODE); channel_mode = aacEncoder_GetParam(encoder, AACENC_CHANNELMODE);
obytes = 6144 / 8 * channel_mode + 7; obytes = 6144 / 8 * channel_mode;
if (!*output || *osize < obytes) { if (!output->data || output->capacity < obytes) {
*osize = obytes; uint8_t *p = realloc(output->data, obytes);
*output = realloc(*output, obytes); if (!p) return -1;
output->capacity = obytes;
output->data = p;
} }
obufs[0] = *output; obufs[0] = output->data;
obuf_sizes[0] = obytes; obuf_sizes[0] = obytes;
iargs.numInSamples = ilen ? ilen : -1; /* -1 for signaling EOF */ iargs.numInSamples = ilen ? ilen : -1; /* -1 for signaling EOF */
@ -167,6 +223,6 @@ int aac_encode_frame(HANDLE_AACENCODER encoder,
fprintf(stderr, "ERROR: aacEncEncode() failed\n"); fprintf(stderr, "ERROR: aacEncEncode() failed\n");
return -1; return -1;
} }
*olen = oargs.numOutBytes; output->size = oargs.numOutBytes;
return oargs.numInSamples; return oargs.numInSamples / format->channels_per_frame;
} }

View File

@ -15,6 +15,7 @@
unsigned bandwidth; \ unsigned bandwidth; \
unsigned afterburner; \ unsigned afterburner; \
unsigned lowdelay_sbr; \ unsigned lowdelay_sbr; \
unsigned sbr_ratio; \
unsigned sbr_signaling; \ unsigned sbr_signaling; \
unsigned transport_format; \ unsigned transport_format; \
unsigned adts_crc_check; \ unsigned adts_crc_check; \
@ -24,8 +25,19 @@ typedef struct aacenc_param_t {
AACENC_PARAMS AACENC_PARAMS
} aacenc_param_t; } aacenc_param_t;
typedef struct aacenc_frame_t {
uint8_t *data;
uint32_t size, capacity;
} aacenc_frame_t;
int aacenc_is_sbr_ratio_available();
int aacenc_is_sbr_active(const aacenc_param_t *params); int aacenc_is_sbr_active(const aacenc_param_t *params);
int aacenc_is_dual_rate_sbr(const aacenc_param_t *params);
void aacenc_get_lib_info(LIB_INFO *info);
int aacenc_init(HANDLE_AACENCODER *encoder, const aacenc_param_t *params, int aacenc_init(HANDLE_AACENCODER *encoder, const aacenc_param_t *params,
const pcm_sample_description_t *format, const pcm_sample_description_t *format,
AACENC_InfoStruct *info); AACENC_InfoStruct *info);
@ -33,6 +45,6 @@ int aacenc_init(HANDLE_AACENCODER *encoder, const aacenc_param_t *params,
int aac_encode_frame(HANDLE_AACENCODER encoder, int aac_encode_frame(HANDLE_AACENCODER encoder,
const pcm_sample_description_t *format, const pcm_sample_description_t *format,
const int16_t *input, unsigned iframes, const int16_t *input, unsigned iframes,
uint8_t **output, uint32_t *olen, uint32_t *osize); aacenc_frame_t *output);
#endif #endif

View File

@ -193,12 +193,10 @@ int caf_parse(caf_reader_t *reader, int64_t *data_length)
} else if (fcc == M4AF_FOURCC('d','a','t','a')) { } else if (fcc == M4AF_FOURCC('d','a','t','a')) {
TRY_IO(pcm_skip(&reader->io, 4)); /* mEditCount */ TRY_IO(pcm_skip(&reader->io, 4)); /* mEditCount */
*data_length = (chunk_size == ~0ULL) ? chunk_size : chunk_size - 4; *data_length = (chunk_size == ~0ULL) ? chunk_size : chunk_size - 4;
reader->data_offset += 12; reader->data_offset = pcm_tell(&reader->io);
break; break;
} else } else
TRY_IO(pcm_skip(&reader->io, chunk_size)); TRY_IO(pcm_skip(&reader->io, chunk_size));
reader->data_offset += (chunk_size + 8);
} }
ENSURE(reader->sample_format.channels_per_frame); ENSURE(reader->sample_format.channels_per_frame);
ENSURE(fcc == M4AF_FOURCC('d','a','t','a')); ENSURE(fcc == M4AF_FOURCC('d','a','t','a'));
@ -227,6 +225,7 @@ pcm_reader_t *caf_open(pcm_io_context_t *io,
memcpy(&reader->io, io, sizeof(pcm_io_context_t)); memcpy(&reader->io, io, sizeof(pcm_io_context_t));
reader->tag_callback = tag_callback; reader->tag_callback = tag_callback;
reader->tag_ctx = tag_ctx; reader->tag_ctx = tag_ctx;
memcpy(reader->chanmap, "\000\001\002\003\004\005\006\007", 8);
if (caf_parse(reader, &data_length) < 0) { if (caf_parse(reader, &data_length) < 0) {
free(reader); free(reader);

View File

@ -157,7 +157,7 @@ int aacenc_fprintf(FILE *fp, const char *fmt, ...)
codepage_decode_wchar(CP_UTF8, s, &ws); codepage_decode_wchar(CP_UTF8, s, &ws);
free(s); free(s);
fflush(fp); fflush(fp);
WriteConsoleW(fh, ws, cnt, &nw, 0); WriteConsoleW(fh, ws, wcslen(ws), &nw, 0);
free(ws); free(ws);
} }
return cnt; return cnt;

208
src/extrapolater.c Normal file
View File

@ -0,0 +1,208 @@
/*
* Copyright (C) 2013 nu774
* For conditions of distribution and use, see copyright notice in COPYING
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#if HAVE_STDINT_H
# include <stdint.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "pcm_reader.h"
#include "lpc.h"
typedef int16_t sample_t;
typedef struct buffer_t {
sample_t *data;
unsigned count; /* count in frames */
unsigned capacity; /* size in bytes */
} buffer_t;
typedef struct extrapolater_t {
pcm_reader_vtbl_t *vtbl;
pcm_reader_t *src;
pcm_sample_description_t format;
buffer_t buffer[2];
unsigned nbuffer;
int (*process)(struct extrapolater_t *, void *, unsigned);
} extrapolater_t;
#define LPC_ORDER 32
static inline pcm_reader_t *get_source(pcm_reader_t *reader)
{
return ((extrapolater_t *)reader)->src;
}
static const
pcm_sample_description_t *get_format(pcm_reader_t *reader)
{
return pcm_get_format(get_source(reader));
}
static int64_t get_length(pcm_reader_t *reader)
{
return pcm_get_length(get_source(reader));
}
static int64_t get_position(pcm_reader_t *reader)
{
return pcm_get_position(get_source(reader));
}
static int realloc_buffer(buffer_t *bp, size_t size)
{
if (bp->capacity < size) {
void *p = realloc(bp->data, size);
if (!p) return -1;
bp->data = p;
bp->capacity = size;
}
return 0;
}
static void reverse_buffer(sample_t *data, unsigned nframes, unsigned nchannels)
{
unsigned i = 0, j = nchannels * (nframes - 1), n;
for (; i < j; i += nchannels, j -= nchannels) {
for (n = 0; n < nchannels; ++n) {
sample_t tmp = data[i + n];
data[i + n] = data[j + n];
data[j + n] = tmp;
}
}
}
static int fetch(extrapolater_t *self, unsigned nframes)
{
const pcm_sample_description_t *sfmt = pcm_get_format(self->src);
buffer_t *bp = &self->buffer[self->nbuffer];
int rc = 0;
if (realloc_buffer(bp, nframes * sfmt->bytes_per_frame) == 0) {
rc = pcm_read_frames(self->src, bp->data, nframes);
bp->count = rc > 0 ? rc : 0;
}
if (rc > 0)
self->nbuffer ^= 1;
return bp->count;
}
static int extrapolate(extrapolater_t *self, const buffer_t *bp,
void *dst, unsigned nframes)
{
const pcm_sample_description_t *sfmt = pcm_get_format(self->src);
unsigned i, n = sfmt->channels_per_frame;
float lpc[LPC_ORDER];
for (i = 0; i < n; ++i) {
vorbis_lpc_from_data(bp->data + i, lpc, bp->count, LPC_ORDER, n);
vorbis_lpc_predict(lpc, &bp->data[i + n * (bp->count - LPC_ORDER)],
LPC_ORDER, (sample_t*)dst + i, nframes, n);
}
return nframes;
}
static int process1(extrapolater_t *self, void *buffer, unsigned nframes);
static int process2(extrapolater_t *self, void *buffer, unsigned nframes);
static int process3(extrapolater_t *self, void *buffer, unsigned nframes);
static int process0(extrapolater_t *self, void *buffer, unsigned nframes)
{
const pcm_sample_description_t *sfmt = pcm_get_format(self->src);
unsigned nchannels = sfmt->channels_per_frame;
buffer_t *bp = &self->buffer[self->nbuffer];
if (fetch(self, nframes) < 2 * LPC_ORDER)
memset(buffer, 0, nframes * sfmt->bytes_per_frame);
else {
reverse_buffer(bp->data, bp->count, nchannels);
extrapolate(self, bp, buffer, nframes);
reverse_buffer(buffer, nframes, nchannels);
reverse_buffer(bp->data, bp->count, nchannels);
}
self->process = bp->count ? process1 : process2;
return nframes;
}
static int process1(extrapolater_t *self, void *buffer, unsigned nframes)
{
const pcm_sample_description_t *sfmt = pcm_get_format(self->src);
buffer_t *bp = &self->buffer[self->nbuffer ^ 1];
assert(bp->count <= nframes);
memcpy(buffer, bp->data, bp->count * sfmt->bytes_per_frame);
if (!fetch(self, nframes))
self->process = process2;
return bp->count;
}
static int process2(extrapolater_t *self, void *buffer, unsigned nframes)
{
const pcm_sample_description_t *sfmt = pcm_get_format(self->src);
buffer_t *bp = &self->buffer[self->nbuffer];
buffer_t *bbp = &self->buffer[self->nbuffer ^ 1];
if (bp->count < 2 * LPC_ORDER) {
size_t total = bp->count + bbp->count;
if (bbp->count &&
realloc_buffer(bbp, total * sfmt->bytes_per_frame) == 0)
{
memcpy(bbp->data + bbp->count * sfmt->channels_per_frame,
bp->data, bp->count * sfmt->bytes_per_frame);
bbp->count = total;
bp->count = 0;
bp = bbp;
self->nbuffer ^= 1;
}
}
self->process = process3;
if (bp->count >= 2 * LPC_ORDER)
extrapolate(self, bp, buffer, nframes);
else
memset(buffer, 0, nframes * sfmt->bytes_per_frame);
return nframes;
}
static int process3(extrapolater_t *self, void *buffer, unsigned nframes)
{
return 0;
}
static int read_frames(pcm_reader_t *reader, void *buffer, unsigned nframes)
{
extrapolater_t *self = (extrapolater_t *)reader;
return self->process(self, buffer, nframes);
}
static void teardown(pcm_reader_t **reader)
{
extrapolater_t *self = (extrapolater_t *)*reader;
pcm_teardown(&self->src);
free(self->buffer[0].data);
free(self->buffer[1].data);
free(self);
*reader = 0;
}
static pcm_reader_vtbl_t my_vtable = {
get_format, get_length, get_position, read_frames, teardown
};
pcm_reader_t *extrapolater_open(pcm_reader_t *reader)
{
extrapolater_t *self = 0;
if ((self = calloc(1, sizeof(extrapolater_t))) == 0)
return 0;
self->src = reader;
self->vtbl = &my_vtable;
self->process = process0;
return (pcm_reader_t *)self;
}

169
src/lpc.c Normal file
View File

@ -0,0 +1,169 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
* by the Xiph.Org Foundation http://www.xiph.org/ *
* *
********************************************************************
function: LPC low level routines
last mod: $Id: lpc.c 16227 2009-07-08 06:58:46Z xiphmont $
********************************************************************/
/* Some of these routines (autocorrelator, LPC coefficient estimator)
are derived from code written by Jutta Degener and Carsten Bormann;
thus we include their copyright below. The entirety of this file
is freely redistributable on the condition that both of these
copyright notices are preserved without modification. */
/* Preserved Copyright: *********************************************/
/* Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann,
Technische Universita"t Berlin
Any use of this software is permitted provided that this notice is not
removed and that neither the authors nor the Technische Universita"t
Berlin are deemed to have made any representations as to the
suitability of this software for any purpose nor are held responsible
for any defects of this software. THERE IS ABSOLUTELY NO WARRANTY FOR
THIS SOFTWARE.
As a matter of courtesy, the authors request to be informed about uses
this software has found, about bugs in this software, and about any
improvements that may be of general interest.
Berlin, 28.11.1994
Jutta Degener
Carsten Bormann
*********************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#if HAVE_STDINT_H
# include <stdint.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "lpc.h"
#include "lpcm.h"
/* Autocorrelation LPC coeff generation algorithm invented by
N. Levinson in 1947, modified by J. Durbin in 1959. */
/* Input : n elements of time doamin data
Output: m lpc coefficients, excitation energy */
float vorbis_lpc_from_data(short *data,float *lpci,int n,int m,int stride){
double *aut=malloc(sizeof(*aut)*(m+1));
double *lpc=malloc(sizeof(*lpc)*(m));
double error;
double epsilon;
int i,j;
/* autocorrelation, p+1 lag coefficients */
j=m+1;
while(j--){
double d=0; /* double needed for accumulator depth */
for(i=j;i<n;i++)d+=(double)data[i*stride]*data[(i-j)*stride]/1073741824.0;
aut[j]=d;
}
/* Generate lpc coefficients from autocorr values */
/* set our noise floor to about -100dB */
error=aut[0] * (1. + 1e-10);
epsilon=1e-9*aut[0]+1e-10;
for(i=0;i<m;i++){
double r= -aut[i+1];
if(error<epsilon){
memset(lpc+i,0,(m-i)*sizeof(*lpc));
goto done;
}
/* Sum up this iteration's reflection coefficient; note that in
Vorbis we don't save it. If anyone wants to recycle this code
and needs reflection coefficients, save the results of 'r' from
each iteration. */
for(j=0;j<i;j++)r-=lpc[j]*aut[i-j];
r/=error;
/* Update LPC coefficients and total error */
lpc[i]=r;
for(j=0;j<i/2;j++){
double tmp=lpc[j];
lpc[j]+=r*lpc[i-1-j];
lpc[i-1-j]+=r*tmp;
}
if(i&1)lpc[j]+=lpc[j]*r;
error*=1.-r*r;
}
done:
/* slightly damp the filter */
{
double g = .99;
double damp = g;
for(j=0;j<m;j++){
lpc[j]*=damp;
damp*=g;
}
}
for(j=0;j<m;j++)lpci[j]=(float)lpc[j];
/* we need the error value to know how big an impulse to hit the
filter with later */
free(aut);
free(lpc);
return error;
}
void vorbis_lpc_predict(float *coeff,short *prime,int m,
short *data,long n,int stride){
/* in: coeff[0...m-1] LPC coefficients
prime[0...m-1] initial values (allocated size of n+m-1)
out: data[0...n-1] data samples */
long i,j,o,p;
float y;
float *work=malloc(sizeof(*work)*(m+n));
if(!prime)
for(i=0;i<m;i++)
work[i]=0.f;
else
for(i=0;i<m;i++)
work[i]=prime[i*stride]/32768.0f;
for(i=0;i<n;i++){
y=0;
o=i;
p=m;
for(j=0;j<m;j++)
y-=work[o++]*coeff[--p];
work[o]=y;
data[i*stride]=lrint(pcm_clip(y*32768.0,-32768.0,32767.0));
}
free(work);
}

27
src/lpc.h Normal file
View File

@ -0,0 +1,27 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
* by the Xiph.Org Foundation http://www.xiph.org/ *
* *
********************************************************************
function: LPC low level routines
last mod: $Id: lpc.h 16037 2009-05-26 21:10:58Z xiphmont $
********************************************************************/
#ifndef _V_LPC_H_
#define _V_LPC_H_
/* simple linear scale LPC code */
extern float vorbis_lpc_from_data(short *data,float *lpc,int n,int m,int stride);
extern void vorbis_lpc_predict(float *coeff,short *prime,int m,
short *data,long n,int stride);
#endif

View File

@ -13,36 +13,6 @@
#include "lpcm.h" #include "lpcm.h"
#include "m4af_endian.h" #include "m4af_endian.h"
#ifdef _MSC_VER
# define inline __inline
# ifdef _M_IX86
inline int lrint(double x)
{
int n;
_asm {
fld x
fistp n
}
return n;
}
# else
# include <emmintrin.h>
inline int lrint(double x)
{
return _mm_cvtsd_si32(_mm_load_sd(&x));
}
# endif
#endif
static
inline double pcm_clip(double n, double min_value, double max_value)
{
if (n < min_value)
return min_value;
else if (n > max_value)
return max_value;
return n;
}
static static
inline float pcm_i2f(int32_t n) inline float pcm_i2f(int32_t n)
{ {

View File

@ -31,6 +31,36 @@ typedef struct pcm_sample_description_t {
#define PCM_BYTES_PER_CHANNEL(desc) \ #define PCM_BYTES_PER_CHANNEL(desc) \
((desc)->bytes_per_frame / (desc)->channels_per_frame) ((desc)->bytes_per_frame / (desc)->channels_per_frame)
#if defined(_MSC_VER) && _MSC_VER < 1800
# ifdef _M_IX86
static inline int lrint(double x)
{
int n;
_asm {
fld x
fistp n
}
return n;
}
# else
# include <emmintrin.h>
static inline int lrint(double x)
{
return _mm_cvtsd_si32(_mm_load_sd(&x));
}
# endif
#endif
static
inline double pcm_clip(double n, double min_value, double max_value)
{
if (n < min_value)
return min_value;
else if (n > max_value)
return max_value;
return n;
}
int pcm_convert_to_native_sint16(const pcm_sample_description_t *format, int pcm_convert_to_native_sint16(const pcm_sample_description_t *format,
const void *input, uint32_t nframes, const void *input, uint32_t nframes,
int16_t *result); int16_t *result);

View File

@ -864,7 +864,6 @@ void m4af_write_sbgp_box(m4af_ctx_t *ctx, uint32_t track_idx)
static static
void m4af_write_sgpd_box(m4af_ctx_t *ctx, uint32_t track_idx) void m4af_write_sgpd_box(m4af_ctx_t *ctx, uint32_t track_idx)
{ {
m4af_track_t *track = &ctx->track[track_idx];
m4af_write(ctx, m4af_write(ctx,
"\0\0\0\026" /* size: 22 */ "\0\0\0\026" /* size: 22 */
"sgpd" /* type */ "sgpd" /* type */
@ -1050,7 +1049,6 @@ void m4af_write_elst_box(m4af_ctx_t *ctx, uint32_t track_idx)
static static
void m4af_write_edts_box(m4af_ctx_t *ctx, uint32_t track_idx) void m4af_write_edts_box(m4af_ctx_t *ctx, uint32_t track_idx)
{ {
m4af_track_t *track = &ctx->track[track_idx];
int64_t pos = m4af_tell(ctx); int64_t pos = m4af_tell(ctx);
m4af_write(ctx, "\0\0\0\0edts", 8); m4af_write(ctx, "\0\0\0\0edts", 8);
m4af_write_elst_box(ctx, track_idx); m4af_write_elst_box(ctx, track_idx);

View File

@ -54,7 +54,8 @@ static void handle_signals(void)
{ {
int i, sigs[] = { SIGINT, SIGHUP, SIGTERM }; int i, sigs[] = { SIGINT, SIGHUP, SIGTERM };
for (i = 0; i < sizeof(sigs)/sizeof(sigs[0]); ++i) { for (i = 0; i < sizeof(sigs)/sizeof(sigs[0]); ++i) {
struct sigaction sa = { 0 }; struct sigaction sa;
memset(&sa, 0, sizeof sa);
sa.sa_handler = signal_handler; sa.sa_handler = signal_handler;
sa.sa_flags |= SA_RESTART; sa.sa_flags |= SA_RESTART;
sigaction(sigs[i], &sa, 0); sigaction(sigs[i], &sa, 0);
@ -132,11 +133,14 @@ PROGNAME " %s\n"
" -a, --afterburner <n> Afterburner\n" " -a, --afterburner <n> Afterburner\n"
" 0: Off\n" " 0: Off\n"
" 1: On(default)\n" " 1: On(default)\n"
" -L, --lowdelay-sbr Enable ELD-SBR (AAC ELD only)\n" " -L, --lowdelay-sbr <-1|0|1> Configure SBR activity on AAC ELD\n"
" -s, --sbr-signaling <n> SBR signaling mode\n" " -1: Use ELD SBR auto configurator\n"
" 0: Implicit, backward compatible(default)\n" " 0: Disable SBR on ELD (default)\n"
" 1: Explicit SBR and implicit PS\n" " 1: Enable SBR on ELD\n"
" 2: Explicit hierarchical signaling\n" " -s, --sbr-ratio <0|1|2> Controls activation of downsampled SBR\n"
" 0: Use lib default (default)\n"
" 1: downsampled SBR (default for ELD+SBR)\n"
" 2: dual-rate SBR (default for HE-AAC)\n"
" -f, --transport-format <n> Transport format\n" " -f, --transport-format <n> Transport format\n"
" 0: RAW (default, muxed into M4A)\n" " 0: RAW (default, muxed into M4A)\n"
" 1: ADIF\n" " 1: ADIF\n"
@ -153,7 +157,10 @@ PROGNAME " %s\n"
" 0: iTunSMPB (default)\n" " 0: iTunSMPB (default)\n"
" 1: ISO standard (edts + sgpd)\n" " 1: ISO standard (edts + sgpd)\n"
" 2: Both\n" " 2: Both\n"
" --ignorelength Ignore length of WAV header\n" " --include-sbr-delay Count SBR decoder delay in encoder delay\n"
" This is not iTunes compatible, but is default\n"
" behavior of FDK library.\n"
" -I, --ignorelength Ignore length of WAV header\n"
" -S, --silent Don't print progress messages\n" " -S, --silent Don't print progress messages\n"
" --moov-before-mdat Place moov box before mdat box on m4a output\n" " --moov-before-mdat Place moov box before mdat box on m4a output\n"
"\n" "\n"
@ -208,6 +215,7 @@ typedef struct aacenc_param_ex_t {
char *output_filename; char *output_filename;
FILE *output_fp; FILE *output_fp;
unsigned gapless_mode; unsigned gapless_mode;
unsigned include_sbr_delay;
unsigned ignore_length; unsigned ignore_length;
int silent; int silent;
int moov_before_mdat; int moov_before_mdat;
@ -228,8 +236,9 @@ static
int parse_options(int argc, char **argv, aacenc_param_ex_t *params) int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
{ {
int ch; int ch;
unsigned n; int n;
#define OPT_INCLUDE_SBR_DELAY M4AF_FOURCC('s','d','l','y')
#define OPT_MOOV_BEFORE_MDAT M4AF_FOURCC('m','o','o','v') #define OPT_MOOV_BEFORE_MDAT M4AF_FOURCC('m','o','o','v')
#define OPT_RAW_CHANNELS M4AF_FOURCC('r','c','h','n') #define OPT_RAW_CHANNELS M4AF_FOURCC('r','c','h','n')
#define OPT_RAW_RATE M4AF_FOURCC('r','r','a','t') #define OPT_RAW_RATE M4AF_FOURCC('r','r','a','t')
@ -246,13 +255,14 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
{ "bitrate-mode", required_argument, 0, 'm' }, { "bitrate-mode", required_argument, 0, 'm' },
{ "bandwidth", required_argument, 0, 'w' }, { "bandwidth", required_argument, 0, 'w' },
{ "afterburner", required_argument, 0, 'a' }, { "afterburner", required_argument, 0, 'a' },
{ "lowdelay-sbr", no_argument, 0, 'L' }, { "lowdelay-sbr", required_argument, 0, 'L' },
{ "sbr-signaling", required_argument, 0, 's' }, { "sbr-ratio", required_argument, 0, 's' },
{ "transport-format", required_argument, 0, 'f' }, { "transport-format", required_argument, 0, 'f' },
{ "adts-crc-check", no_argument, 0, 'C' }, { "adts-crc-check", no_argument, 0, 'C' },
{ "header-period", required_argument, 0, 'P' }, { "header-period", required_argument, 0, 'P' },
{ "gapless-mode", required_argument, 0, 'G' }, { "gapless-mode", required_argument, 0, 'G' },
{ "include-sbr-delay", no_argument, 0, OPT_INCLUDE_SBR_DELAY },
{ "ignorelength", no_argument, 0, 'I' }, { "ignorelength", no_argument, 0, 'I' },
{ "silent", no_argument, 0, 'S' }, { "silent", no_argument, 0, 'S' },
{ "moov-before-mdat", no_argument, 0, OPT_MOOV_BEFORE_MDAT }, { "moov-before-mdat", no_argument, 0, OPT_MOOV_BEFORE_MDAT },
@ -324,14 +334,18 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
params->afterburner = n; params->afterburner = n;
break; break;
case 'L': case 'L':
params->lowdelay_sbr = 1; if (sscanf(optarg, "%d", &n) != 1 || n < -1 || n > 1) {
fprintf(stderr, "invalid arg for lowdelay-sbr\n");
return -1;
}
params->lowdelay_sbr = n;
break; break;
case 's': case 's':
if (sscanf(optarg, "%u", &n) != 1 || n > 2) { if (sscanf(optarg, "%u", &n) != 1 || n > 2) {
fprintf(stderr, "invalid arg for sbr-signaling\n"); fprintf(stderr, "invalid arg for sbr-ratio\n");
return -1; return -1;
} }
params->sbr_signaling = n; params->sbr_ratio = n;
break; break;
case 'f': case 'f':
if (sscanf(optarg, "%u", &n) != 1) { if (sscanf(optarg, "%u", &n) != 1) {
@ -360,6 +374,9 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
} }
params->gapless_mode = n; params->gapless_mode = n;
break; break;
case OPT_INCLUDE_SBR_DELAY:
params->include_sbr_delay = 1;
break;
case 'I': case 'I':
params->ignore_length = 1; params->ignore_length = 1;
break; break;
@ -475,16 +492,15 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
}; };
static static
int write_sample(FILE *ofp, m4af_ctx_t *m4af, int write_sample(FILE *ofp, m4af_ctx_t *m4af, aacenc_frame_t *frame)
const void *data, uint32_t size, uint32_t duration)
{ {
if (!m4af) { if (!m4af) {
fwrite(data, 1, size, ofp); fwrite(frame->data, 1, frame->size, ofp);
if (ferror(ofp)) { if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite(): %s\n", strerror(errno)); fprintf(stderr, "ERROR: fwrite(): %s\n", strerror(errno));
return -1; return -1;
} }
} else if (m4af_write_sample(m4af, 0, data, size, duration) < 0) { } else if (m4af_write_sample(m4af, 0, frame->data, frame->size, 0) < 0) {
fprintf(stderr, "ERROR: failed to write m4a sample\n"); fprintf(stderr, "ERROR: failed to write m4a sample\n");
return -1; return -1;
} }
@ -492,51 +508,76 @@ int write_sample(FILE *ofp, m4af_ctx_t *m4af,
} }
static static
int encode(pcm_reader_t *reader, HANDLE_AACENCODER encoder, int encode(aacenc_param_ex_t *params, pcm_reader_t *reader,
uint32_t frame_length, FILE *ofp, m4af_ctx_t *m4af, HANDLE_AACENCODER encoder, uint32_t frame_length,
int show_progress) m4af_ctx_t *m4af)
{ {
int16_t *ibuf = 0; int16_t *ibuf = 0, *ip;
uint8_t *obuf = 0; aacenc_frame_t obuf[2] = {{ 0 }}, *obp;
uint32_t olen; unsigned flip = 0;
uint32_t osize = 0;
int nread = 1; int nread = 1;
int consumed;
int rc = -1; int rc = -1;
int frames_written = 0; int remaining, consumed;
int frames_written = 0, encoded = 0;
aacenc_progress_t progress = { 0 }; aacenc_progress_t progress = { 0 };
const pcm_sample_description_t *fmt = pcm_get_format(reader); const pcm_sample_description_t *fmt = pcm_get_format(reader);
ibuf = malloc(frame_length * fmt->bytes_per_frame); ibuf = malloc(frame_length * fmt->bytes_per_frame);
aacenc_progress_init(&progress, pcm_get_length(reader), fmt->sample_rate); aacenc_progress_init(&progress, pcm_get_length(reader), fmt->sample_rate);
do {
for (;;) {
/*
* Since we delay the write, we cannot just exit loop when interrupted.
* Instead, we regard it as EOF.
*/
if (g_interrupted) if (g_interrupted)
nread = 0; nread = 0;
else if (nread) { if (nread > 0) {
if ((nread = pcm_read_frames(reader, ibuf, frame_length)) < 0) { if ((nread = pcm_read_frames(reader, ibuf, frame_length)) < 0) {
fprintf(stderr, "ERROR: read failed\n"); fprintf(stderr, "ERROR: read failed\n");
goto END; goto END;
} }
if (show_progress) if (!params->silent)
aacenc_progress_update(&progress, pcm_get_position(reader), aacenc_progress_update(&progress, pcm_get_position(reader),
fmt->sample_rate * 2); fmt->sample_rate * 2);
} }
if ((consumed = aac_encode_frame(encoder, fmt, ibuf, nread, ip = ibuf;
&obuf, &olen, &osize)) < 0) remaining = nread;
goto END; do {
if (olen > 0) { obp = &obuf[flip];
if (write_sample(ofp, m4af, obuf, olen, frame_length) < 0) consumed = aac_encode_frame(encoder, fmt, ip, remaining, obp);
if (consumed < 0) goto END;
if (consumed == 0 && obp->size == 0) goto DONE;
if (obp->size == 0) break;
remaining -= consumed;
ip += consumed * fmt->channels_per_frame;
flip ^= 1;
/*
* As we pad 1 frame at beginning and ending by our extrapolator,
* we want to drop them.
* We delay output by 1 frame by double buffering, and discard
* second frame and final frame from the encoder.
* Since sbr_header is included in the first frame (in case of
* SBR), we cannot discard first frame. So we pick second instead.
*/
++encoded;
if (encoded == 1 || encoded == 3)
continue;
obp = &obuf[flip];
if (write_sample(params->output_fp, m4af, obp) < 0)
goto END; goto END;
++frames_written; ++frames_written;
} } while (remaining > 0);
} while (nread > 0 || olen > 0); }
DONE:
if (show_progress) if (!params->silent)
aacenc_progress_finish(&progress, pcm_get_position(reader)); aacenc_progress_finish(&progress, pcm_get_position(reader));
rc = frames_written; rc = frames_written;
END: END:
if (ibuf) free(ibuf); if (ibuf) free(ibuf);
if (obuf) free(obuf); if (obuf[0].data) free(obuf[0].data);
if (obuf[1].data) free(obuf[1].data);
return rc; return rc;
} }
@ -546,19 +587,11 @@ void put_tool_tag(m4af_ctx_t *m4af, const aacenc_param_ex_t *params,
{ {
char tool_info[256]; char tool_info[256];
char *p = tool_info; char *p = tool_info;
LIB_INFO *lib_info = 0; LIB_INFO lib_info;
p += sprintf(p, PROGNAME " %s, ", fdkaac_version); p += sprintf(p, PROGNAME " %s, ", fdkaac_version);
aacenc_get_lib_info(&lib_info);
lib_info = calloc(FDK_MODULE_LAST, sizeof(LIB_INFO)); p += sprintf(p, "libfdk-aac %s, ", lib_info.versionStr);
if (aacEncGetLibInfo(lib_info) == AACENC_OK) {
int i;
for (i = 0; i < FDK_MODULE_LAST; ++i)
if (lib_info[i].module_id == FDK_AACENC)
break;
p += sprintf(p, "libfdk-aac %s, ", lib_info[i].versionStr);
}
free(lib_info);
if (params->bitrate_mode) if (params->bitrate_mode)
sprintf(p, "VBR mode %d", params->bitrate_mode); sprintf(p, "VBR mode %d", params->bitrate_mode);
else else
@ -610,7 +643,7 @@ char *generate_output_filename(const char *filename, const char *ext)
const char *ext_org = strrchr(base, '.'); const char *ext_org = strrchr(base, '.');
if (ext_org) ilen = ext_org - base; if (ext_org) ilen = ext_org - base;
p = malloc(ilen + ext_len + 1); p = malloc(ilen + ext_len + 1);
sprintf(p, "%.*s%s", ilen, base, ext); sprintf(p, "%.*s%s", (int)ilen, base, ext);
} }
return p; return p;
} }
@ -654,7 +687,7 @@ int parse_raw_spec(const char *spec, pcm_sample_description_t *desc)
static pcm_io_vtbl_t pcm_io_vtbl = { static pcm_io_vtbl_t pcm_io_vtbl = {
read_callback, seek_callback, tell_callback read_callback, seek_callback, tell_callback
}; };
static pcm_io_vtbl_t pcm_io_vtbl_noseek = { read_callback, 0, 0 }; static pcm_io_vtbl_t pcm_io_vtbl_noseek = { read_callback, 0, tell_callback };
static static
pcm_reader_t *open_input(aacenc_param_ex_t *params) pcm_reader_t *open_input(aacenc_param_ex_t *params)
@ -669,7 +702,7 @@ pcm_reader_t *open_input(aacenc_param_ex_t *params)
goto END; goto END;
} }
io.cookie = params->input_fp; io.cookie = params->input_fp;
if (fstat(fileno(io.cookie), &stb) == 0 if (fstat(fileno(params->input_fp), &stb) == 0
&& (stb.st_mode & S_IFMT) == S_IFREG) && (stb.st_mode & S_IFMT) == S_IFREG)
io.vtbl = &pcm_io_vtbl; io.vtbl = &pcm_io_vtbl;
else else
@ -712,10 +745,13 @@ pcm_reader_t *open_input(aacenc_param_ex_t *params)
} }
break; break;
default: default:
fprintf(stderr, "ERROR: unsupported input file\n");
goto END; goto END;
} }
} }
return pcm_open_sint16_converter(reader); if ((reader = pcm_open_sint16_converter(reader)) != 0)
reader = extrapolater_open(reader);
return reader;
END: END:
return 0; return 0;
} }
@ -734,8 +770,9 @@ int main(int argc, char **argv)
AACENC_InfoStruct aacinfo = { 0 }; AACENC_InfoStruct aacinfo = { 0 };
m4af_ctx_t *m4af = 0; m4af_ctx_t *m4af = 0;
const pcm_sample_description_t *sample_format; const pcm_sample_description_t *sample_format;
int downsampled_timescale = 0;
int frame_count = 0; int frame_count = 0;
int sbr_mode = 0;
unsigned scale_shift = 0;
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");
setbuf(stderr, 0); setbuf(stderr, 0);
@ -748,6 +785,19 @@ int main(int argc, char **argv)
sample_format = pcm_get_format(reader); sample_format = pcm_get_format(reader);
sbr_mode = aacenc_is_sbr_active((aacenc_param_t*)&params);
if (sbr_mode && !aacenc_is_sbr_ratio_available()) {
fprintf(stderr, "WARNING: Only dual-rate SBR is available "
"for this version\n");
params.sbr_ratio = 2;
}
scale_shift = aacenc_is_dual_rate_sbr((aacenc_param_t*)&params);
params.sbr_signaling =
(params.transport_format == TT_MP4_LOAS) ? 2 :
(params.transport_format == TT_MP4_RAW) ? 1 : 0;
if (sbr_mode && !scale_shift)
params.sbr_signaling = 2;
if (aacenc_init(&encoder, (aacenc_param_t*)&params, sample_format, if (aacenc_init(&encoder, (aacenc_param_t*)&params, sample_format,
&aacinfo) < 0) &aacinfo) < 0)
goto END; goto END;
@ -764,36 +814,47 @@ int main(int argc, char **argv)
goto END; goto END;
} }
handle_signals(); handle_signals();
if (!params.transport_format) { if (!params.transport_format) {
uint32_t scale; uint32_t scale;
unsigned framelen = aacinfo.frameLength; unsigned framelen = aacinfo.frameLength;
int sbr_mode = aacenc_is_sbr_active((aacenc_param_t*)&params); scale = sample_format->sample_rate >> scale_shift;
int sig_mode = aacEncoder_GetParam(encoder, AACENC_SIGNALING_MODE);
if (sbr_mode && !sig_mode)
downsampled_timescale = 1;
scale = sample_format->sample_rate >> downsampled_timescale;
if ((m4af = m4af_create(M4AF_CODEC_MP4A, scale, &m4af_io, if ((m4af = m4af_create(M4AF_CODEC_MP4A, scale, &m4af_io,
params.output_fp)) < 0) params.output_fp)) < 0)
goto END; goto END;
m4af_set_decoder_specific_info(m4af, 0, aacinfo.confBuf, m4af_set_decoder_specific_info(m4af, 0,
aacinfo.confSize); aacinfo.confBuf, aacinfo.confSize);
m4af_set_fixed_frame_duration(m4af, 0, m4af_set_fixed_frame_duration(m4af, 0,
framelen >> downsampled_timescale); framelen >> scale_shift);
m4af_set_vbr_mode(m4af, 0, params.bitrate_mode); m4af_set_vbr_mode(m4af, 0, params.bitrate_mode);
m4af_set_priming_mode(m4af, params.gapless_mode + 1); m4af_set_priming_mode(m4af, params.gapless_mode + 1);
m4af_begin_write(m4af); m4af_begin_write(m4af);
} }
frame_count = encode(reader, encoder, aacinfo.frameLength, if (scale_shift && (aacinfo.encoderDelay & 1)) {
params.output_fp, m4af, !params.silent); /*
* Since odd delay cannot be exactly expressed in downsampled scale,
* we push one zero frame to the encoder here, to make delay even
*/
int16_t zero[8] = { 0 };
aacenc_frame_t frame = { 0 };
aac_encode_frame(encoder, sample_format, zero, 1, &frame);
free(frame.data);
}
frame_count = encode(&params, reader, encoder, aacinfo.frameLength, m4af);
if (frame_count < 0) if (frame_count < 0)
goto END; goto END;
if (m4af) { if (m4af) {
uint32_t delay = aacinfo.encoderDelay; uint32_t delay = aacinfo.encoderDelay;
uint32_t padding;
int64_t frames_read = pcm_get_position(reader); int64_t frames_read = pcm_get_position(reader);
uint32_t padding = frame_count * aacinfo.frameLength
- frames_read - aacinfo.encoderDelay; if (sbr_mode && params.profile != AOT_ER_AAC_ELD &&
m4af_set_priming(m4af, 0, delay >> downsampled_timescale, !params.include_sbr_delay)
padding >> downsampled_timescale); delay -= 481 << scale_shift;
if (scale_shift && (delay & 1))
++delay;
padding = frame_count * aacinfo.frameLength - frames_read - delay;
m4af_set_priming(m4af, 0, delay >> scale_shift, padding >> scale_shift);
if (finalize_m4a(m4af, &params, encoder) < 0) if (finalize_m4a(m4af, &params, encoder) < 0)
goto END; goto END;
} }

View File

@ -1,3 +1,7 @@
/*
* Copyright (C) 2013 nu774
* For conditions of distribution and use, see copyright notice in COPYING
*/
#if HAVE_CONFIG_H #if HAVE_CONFIG_H
# include "config.h" # include "config.h"
#endif #endif
@ -56,7 +60,8 @@ static tag_key_mapping_t tag_mapping_table[] = {
{ "grouping", M4AF_TAG_GROUPING }, { "grouping", M4AF_TAG_GROUPING },
{ "itunescompilation", M4AF_TAG_COMPILATION }, { "itunescompilation", M4AF_TAG_COMPILATION },
{ "lyrics", M4AF_TAG_LYRICS }, { "lyrics", M4AF_TAG_LYRICS },
{ "performer", M4AF_TAG_ARTIST }, { "tempo", M4AF_TAG_TEMPO },
{ "recordeddate", M4AF_TAG_DATE },
{ "title", M4AF_TAG_TITLE }, { "title", M4AF_TAG_TITLE },
{ "titlesort", M4AF_FOURCC('s','o','n','m') }, { "titlesort", M4AF_FOURCC('s','o','n','m') },
{ "titlesortorder", M4AF_FOURCC('s','o','n','m') }, { "titlesortorder", M4AF_FOURCC('s','o','n','m') },

View File

@ -1,3 +1,7 @@
/*
* Copyright (C) 2013 nu774
* For conditions of distribution and use, see copyright notice in COPYING
*/
#ifndef METADATA_H #ifndef METADATA_H
#define METADATA_H #define METADATA_H

View File

@ -1,3 +1,7 @@
/*
* Copyright (C) 2013 nu774
* For conditions of distribution and use, see copyright notice in COPYING
*/
#ifndef PCM_READER_H #ifndef PCM_READER_H
#define PCM_READER_H #define PCM_READER_H
@ -85,7 +89,7 @@ uint32_t bitcount(uint32_t bits)
int pcm_read(pcm_io_context_t *io, void *buffer, uint32_t size); int pcm_read(pcm_io_context_t *io, void *buffer, uint32_t size);
int pcm_skip(pcm_io_context_t *io, int64_t count); int pcm_skip(pcm_io_context_t *io, int64_t count);
static int pcm_seek(pcm_io_context_t *io, int64_t off, int whence) static inline int pcm_seek(pcm_io_context_t *io, int64_t off, int whence)
{ {
return io->vtbl->seek ? io->vtbl->seek(io->cookie, off, whence) : -1; return io->vtbl->seek ? io->vtbl->seek(io->cookie, off, whence) : -1;
} }
@ -109,4 +113,6 @@ int apple_chan_chunk(pcm_io_context_t *io, uint32_t chunk_size,
pcm_reader_t *pcm_open_sint16_converter(pcm_reader_t *reader); pcm_reader_t *pcm_open_sint16_converter(pcm_reader_t *reader);
pcm_reader_t *extrapolater_open(pcm_reader_t *reader);
#endif #endif

View File

@ -204,7 +204,7 @@ int apple_chan_chunk(pcm_io_context_t *io, uint32_t chunk_size,
switch (mChannelLayoutTag) { switch (mChannelLayoutTag) {
case kAudioChannelLayoutTag_UseChannelBitmap: case kAudioChannelLayoutTag_UseChannelBitmap:
ENSURE(bitcount(mask) == nchannels); ENSURE(bitcount(mChannelBitmap) == nchannels);
TRY_IO(pcm_skip(io, chunk_size - 12)); TRY_IO(pcm_skip(io, chunk_size - 12));
fmt->channel_mask = mChannelBitmap; fmt->channel_mask = mChannelBitmap;
for (i = 0; i < nchannels; ++i) for (i = 0; i < nchannels; ++i)

View File

@ -1,3 +1,7 @@
/*
* Copyright (C) 2013 nu774
* For conditions of distribution and use, see copyright notice in COPYING
*/
#if HAVE_CONFIG_H #if HAVE_CONFIG_H
# include "config.h" # include "config.h"
#endif #endif

View File

@ -93,7 +93,6 @@ int riff_ds64(wav_reader_t *reader, int64_t *length)
TRY_IO(pcm_scanl(&reader->io, "QQQL", TRY_IO(pcm_scanl(&reader->io, "QQQL",
&riff_size, length, &sample_count, &table_size) != 4); &riff_size, length, &sample_count, &table_size) != 4);
TRY_IO(pcm_skip(&reader->io, (chunk_size - 27) & ~1)); TRY_IO(pcm_skip(&reader->io, (chunk_size - 27) & ~1));
reader->data_offset += (chunk_size + 9) & ~1;
FAIL: FAIL:
return -1; return -1;
} }
@ -163,7 +162,6 @@ int wav_parse(wav_reader_t *reader, int64_t *data_length)
container == RIFF_FOURCC('R','F','6','4')); container == RIFF_FOURCC('R','F','6','4'));
TRY_IO(pcm_read32le(&reader->io, &fcc)); TRY_IO(pcm_read32le(&reader->io, &fcc));
ENSURE(fcc == RIFF_FOURCC('W','A','V','E')); ENSURE(fcc == RIFF_FOURCC('W','A','V','E'));
reader->data_offset = 12;
if (container == RIFF_FOURCC('R','F','6','4')) if (container == RIFF_FOURCC('R','F','6','4'))
riff_ds64(reader, data_length); riff_ds64(reader, data_length);
@ -174,12 +172,11 @@ int wav_parse(wav_reader_t *reader, int64_t *data_length)
} else if (fcc == RIFF_FOURCC('d','a','t','a')) { } else if (fcc == RIFF_FOURCC('d','a','t','a')) {
if (container == RIFF_FOURCC('R','I','F','F')) if (container == RIFF_FOURCC('R','I','F','F'))
*data_length = chunk_size; *data_length = chunk_size;
reader->data_offset += 8; reader->data_offset = pcm_tell(&reader->io);
break; break;
} else { } else {
TRY_IO(pcm_skip(&reader->io, (chunk_size + 1) & ~1)); TRY_IO(pcm_skip(&reader->io, (chunk_size + 1) & ~1));
} }
reader->data_offset += (chunk_size + 9) & ~1;
} }
if (fcc == RIFF_FOURCC('d','a','t','a')) if (fcc == RIFF_FOURCC('d','a','t','a'))
return 0; return 0;

View File

@ -1,4 +1,4 @@
#ifndef VERSION_H #ifndef VERSION_H
#define VERSION_H #define VERSION_H
const char *fdkaac_version = "0.4.0"; const char *fdkaac_version = "0.5.4";
#endif #endif