DNS 325 - Funplug 0.7 : Compile x264, lame, shine, fdk-aac, twolame, ffmpeg and sox

Contents[Hide]

dropcap-dns325-gnu

This article will explain how to easily setup a complete GNU compilation environment on your DNS-325 and to compile latest multimedia tools optimised for ARM architecture :

  • shineenc mp3 integer encoder library (liquidsoap version, 8x faster than lame with acceptable quality)
  • fdk-aac encoder library from fraunhofer (high quality real-time aac encoder, open-sourced by Google for jelly bean android platform)
  • twolame encoder library (successor of TooLame)
  • opus encoder library (newly standardized by the IETF)
  • x264 encoder (not optimised for ARM, but a reference)
  • lame 3.9.5 (not optimised for ARM, but also a reference)
  • ffmpeg encoder/decoder multimedia framework
  • sox audio processor, a swiss army knife of sound processing programs

With the resulting binaries, you will be able to :

  • Encode aac and mp3 stream with ffmpeg in more than 3x realtime (perfect for subsonic media streamer)
  • Apply some Dynamic Range Compression on audio files with sox
  • Encode some h264/aac video files with ffmpeg & x264 as a background process

This guide needs you to have installed a complete compilation environment on fun_plug 0.7.
This can be done following DNS 325 - Funplug 0.7 : Install Compilation Environment.
All following operations suppose that your are connected to the DNS-325 console thru SSH or Telnet.

1. Compile Libraries

All following operations are supposed to be done from root home directory /ffp/home/root directory.

You are supposed to compile all libraries first (especially before ffmpeg).

1.1. X264 Codec & Encoder

audio-x264x264 will allow you to encode your video in h264 format straight from your DNS-325.

Obviously, as this box is under-powered compared to a PC, this type of encoding can take ages ...

To compile x264 executable and libraries, we need to :

  1. recover sources from then GIT repository
  2. change shell scripts to #!/ffp/bin/bash
  3. configure changing prefix to /ffp
  4. compile & install

# git clone git://git.videolan.org/x264
# cd x264
# sed -i 's/^#!.*$/#!\/ffp\/bin\/bash/g' configure version.sh
# ./configure --enable-static --disable-asm --prefix=/ffp
# make
# make install

1.2. LAME Codec & Encoder

audio-lameLame is THE reference for mp3 encoders in term of quality. But, as it is using floating point algorythm, it is really slow on DNS-325, which is not having FPU.

To compile lame executable and libraries, we need to :

  1. recover & extract sources from sourceforge
  2. change shell scripts to #!/ffp/bin/sh
  3. configure with prefix to /ffp
  4. compile & install

# cd /ffp/home/root
# wget http://downloads.sourceforge.net/project/lame/lame/3.99/lame-3.99.5.tar.gz
# tar xzvf lame-3.99.5.tar.gz
# cd lame-3.99.5
# sed -i 's/^#!.*$/#!\/ffp\/bin\/sh/g' configure
# ./configure --disable-shared --enable-nasm --prefix=/ffp
# make
# make install

1.3. TwoLame Codec

audio-twolameTwoLAME is an optimised MPEG Audio Layer 2 (MP2) encoder based on tooLAME.

TwoLame is known to be a very fast encoder (in comparison to Lame), encoding good quality mp2.

To compile TwoLame libraries, we need to :

  • recover sources from TwoLAME site
  • call autotools
  • change shell scripts to #!/ffp/bin/sh
  • configure changing prefix to /ffp
  • compile & install

# cd /ffp/home/root
# wget http://downloads.sourceforge.net/twolame/twolame-0.3.13.tar.gz
# tar xzvf twolame-0.3.13.tar.gz
# cd twolame-0.3.13
# autoreconf -i
# sed -i 's/^#!.*$/#!\/ffp\/bin\/sh/g' configure
# ./configure --disable-shared --prefix=/ffp
# make
# make install

1.4. ShineEnc Codec & Encoder

audio-mp3Shine Encoder is originally a port of Lame by Gabriel Bouvigne to make a lightweight MP3 encoder for ARM Linux.

It allows to compile mp3 files using integer only, at a very high speed on ARM architecture.

Even if it gives a lower quality than official LAME encoder at the same bitrate, it can achieve acceptable quality compression in almost 4x realtime on DSN-325.

To compile shineenc executable and libraries, we need to :

  1. recover sources from liquidsoap GIT repository
  2. call autotools
  3. change shell scripts to #!/ffp/bin/sh
  4. configure setting prefix to /ffp
  5. compile & install

# cd /ffp/home/root
# git clone git://github.com/savonet/shine
# cd shine
# libtoolize
# autoreconf -i
# sed -i 's/^#!.*$/#!\/ffp\/bin\/sh/g' configure
# ./configure --disable-shared --prefix=/ffp
# make
# make install

1.5. FDK-AAC Codec

audio-aacAndroid 4.1 has included an AAC encoding library by Fraunhofer : fdk-aac.

This library is a brand new high quality Advanced Audio Coding (AAC) audio decoder and encoder, supporting AAC-LC, HE-AAC, HE-AACv2, AAC-LD and AAC-ELD.

To compile fraunhofer fdk-aac libraries, we need to :

  1. recover sources from the GIT repository
  2. call autotools
  3. configure setting prefix to /ffp
  4. compile & install

# cd /ffp/home/root
# git clone git://opencore-amr.git.sourceforge.net/gitroot/opencore-amr/fdk-aac
# cd fdk-aac
# autoreconf -i
# sed -i 's/^#!.*$/#!\/ffp\/bin\/sh/g' configure
# ./configure --disable-shared --prefix=/ffp
# make
# make install

1.6. OPUS Codec

audio-opusOpus is a totally open, royalty-free, highly versatile audio codec.

Opus is unmatched for interactive speech and music transmission over the Internet, but also intended for storage and streaming applications. It is standardized by the Internet Engineering Task Force (IETF) as RFC 6716 which incorporated technology from Skype's SILK codec and Xiph.Org's CELT codec.

This codec should become tomorrow's standard, replacing today's codec collection (mp3, vorbis, aac, ...).

To compile Opus library, we need to :

  • recover sources from OPUS site.
  • configure with prefix to /ffp and enabling fixed point conversion only
  • compile & install

# cd /ffp/home/root
# wget http://downloads.xiph.org/releases/opus/opus-1.0.1.tar.gz
# tar xzvf opus-1.0.1.tar.gz
# cd opus-1.0.1
# sed -i 's/^#!.*$/#!\/ffp\/bin\/sh/g' configure
# ./configure --disable-shared --enable-fixed-point --prefix=/ffp
# make
# make install

2. Compile FFmpeg

audio-ffmpegAt the time of this article, FFmpeg is not supporting libshine out of the box.

We need to patch it to be able to compile it with libshine library.

So to compile ffmpeg will all previous libraries, we need to follow these steps :

  1. retrieve latest source from GIT repository
  2. patch sources to add libshine support (may not be needed in future)
  3. configure, compile & install

2.1. Retrieve project source code

# cd /ffp/home/root
# git clone git://source.ffmpeg.org/ffmpeg.git ffmpeg

2.2. Patch Sources for libShine support

If you are planning to compileFFmpeg with --enable-libshine option (ShineEnc integer mp3 encoding library), you need to patch FFmpeg sources with FFmpeg ticket #1457.

All lines in blue bold should be added ot the original file.

./configure

...
--enable-libschroedinger enable Dirac de/encoding via libschroedinger [no]
--enable-libshine enable fixed-point MP3 encoding via libshine [no]
--enable-libspeex enable Speex de/encoding via libspeex [no]
...
libschroedinger
libshine
libspeex
...
libschroedinger_encoder_deps="libschroedinger"
libshine_encoder_deps="libshine"
libspeex_decoder_deps="libspeex"
...
enabled libschroedinger && require_pkg_config schroedinger-1.0 schroedinger/schro.h schro_init
enabled libshine && require_pkg_config shine shine/layer3.h L3_encode_frame
enabled libspeex && require libspeex speex/speex.h speex_decoder_init -lspeex
...
echo "libschroedinger enabled ${libschroedinger-no}"
echo "libshine enabled ${libshine-no}"
echo "libspeex enabled ${libspeex-no}"
...

./libavcodec/Makefile

...
OBJS-$(CONFIG_LIBSCHROEDINGER_ENCODER) += libschroedingerenc.o \
libschroedinger.o
OBJS-$(CONFIG_LIBSHINE_ENCODER) += libshine.o
OBJS-$(CONFIG_LIBSPEEX_DECODER) += libspeexdec.o
...

./libavcodec/allcodecs.c

...
REGISTER_ENCDEC (LIBILBC, libilbc);
REGISTER_ENCODER (LIBSHINE, libshine);
REGISTER_ENCODER (LIBMP3LAME, libmp3lame);
...

You also need to create a new ./libavcodec/libshine.c file :

./libavcodec/libshine.c

/*
* Interface to libshine for mp3 encoding
* Copyright (c) 2012 Paul B Mahol
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <shine/layer3.h>

#include <libavutil/intreadwrite.h>
#include "avcodec.h"
#include "audio_frame_queue.h"
#include "internal.h"
#include "mpegaudio.h"
#include "mpegaudiodecheader.h"

#define BUFFER_SIZE (4096 * 20)

typedef struct SHINEContext {
  shine_config_t config;
  shine_t shine;
  uint8_t buffer[BUFFER_SIZE];
  int buffer_index;
  AudioFrameQueue afq;
} SHINEContext;

static av_cold int shine_encode_init (AVCodecContext *avctx) {
  SHINEContext *s = avctx->priv_data;

  L3_set_config_mpeg_defaults(&s->config.mpeg);
  if (avctx->bit_rate)
  s->config.mpeg.bitr = avctx->bit_rate / 1000;
  if (L3_find_bitrate_index(s->config.mpeg.bitr) < 0) {
    av_log(avctx, AV_LOG_ERROR, "invalid bitrate\n");
    return AVERROR(EINVAL);
  }

  s->config.mpeg.mode = avctx->channels == 2 ? STEREO : MONO;
  s->config.wave.samplerate = avctx->sample_rate;
  s->config.wave.channels = avctx->channels == 2 ? PCM_STEREO : PCM_MONO;
  s->shine = L3_initialise(&s->config);
  if (!s->shine)
    return AVERROR(ENOMEM);
  avctx->frame_size = samp_per_frame;
  ff_af_queue_init(avctx, &s->afq);
  return 0;
}

static int shine_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr) {
  SHINEContext *s = avctx->priv_data;
  MPADecodeHeader hdr;
  unsigned char *data;
  long written;
  int ret, len;

  if (frame)
    data = L3_encode_frame(s->shine, frame->data[0], &written);
  else
    data = L3_flush(s->shine, &written);
    if (written < 0)
      return -1;
    if (written > 0) {
      if (s->buffer_index + written > BUFFER_SIZE) {
        av_log(avctx, AV_LOG_ERROR, "internal buffer too small\n");
        return AVERROR_BUG;
      }
      memcpy(s->buffer + s->buffer_index, data, written);
      s->buffer_index += written;
    }
  if (frame) {
    if ((ret = ff_af_queue_add(&s->afq, frame)) < 0)
      return ret;
  }

  if (s->buffer_index < 4 || !s->afq.frame_count)
    return 0;
  if (avpriv_mpegaudio_decode_header(&hdr, AV_RB32(s->buffer))) {
    av_log(avctx, AV_LOG_ERROR, "free format output not supported\n");
    return -1;
  }

  len = hdr.frame_size;
  if (len <= s->buffer_index) {
    if ((ret = ff_alloc_packet2(avctx, avpkt, len)))
      return ret;
    memcpy(avpkt->data, s->buffer, len);
    s->buffer_index -= len;
    memmove(s->buffer, s->buffer + len, s->buffer_index);

    ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts, &avpkt->duration);

    avpkt->size = len;
    *got_packet_ptr = 1;
  }

return 0;
}

static av_cold int shine_encode_close(AVCodecContext *avctx)
{
  SHINEContext *s = avctx->priv_data;

  ff_af_queue_close(&s->afq);
  L3_close(s->shine);
  return 0;
}

static const int libshine_sample_rates[] = {
  44100, 48000, 32000, 0
};

AVCodec ff_libshine_encoder = {
  .name = "libshine",
  .type = AVMEDIA_TYPE_AUDIO,
  .id = CODEC_ID_MP3,
  .priv_data_size = sizeof(SHINEContext),
  .init = shine_encode_init,
  .encode2 = shine_encode_frame,
  .close = shine_encode_close,
  .capabilities = CODEC_CAP_DELAY,
  .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_NONE },
  .supported_samplerates = libshine_sample_rates,
  .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO, AV_CH_LAYOUT_STEREO, 0 },
  .long_name = NULL_IF_CONFIG_SMALL("libshine MP3 (MPEG audio layer 3)"),
};

You can directly download libshine.c

2.3. Compile

You are now ready to compile FFmpeg with all the previous libraries.

We won't include lame, as shineenc library is available and lame is very slow on ARM as it is using floating point.

Steps are :

  1. configure with all previous libraries & setting prefix to /ffp
  2. compile & install

# cd ffmpeg
# sed -i 's/^#!.*$/#!\/ffp\/bin\/sh/g' configure
# ./configure --disable-shared --enable-gpl --enable-version3 --enable-nonfree --enable-libx264 --enable-libshine --enable-libfdk_aac --enable-libtwolame --enable-libopus --prefix=/ffp
# make
# make install

The compilation process will be very slow, being stuck on libavcodec/dsputil.o for almost 10 mn ... everything is normal.

Be patient ... whole compilation will take more than one hour.

Once it's over, you can check that you are running your own version of FFmpeg with your specific options :

# ffmpeg
ffmpeg version N-45150-gf2a7e1a Copyright (c) 2000-2012 the FFmpeg developers
built on Oct 14 2012 17:35:43 with gcc 4.5.4 (GCC) 20111110 (prerelease)
configuration: --disable-shared --enable-gpl --enable-version3 --enable-nonfree --enable-libx264 --enable-libshine --enable-libfdk_aac --enable-libtwolame --enable-libopus --prefix=/ffp
libavutil 51. 73.102 / 51. 73.102
libavcodec 54. 64.100 / 54. 64.100
libavformat 54. 29.105 / 54. 29.105
libavdevice 54. 3.100 / 54. 3.100
libavfilter 3. 19.102 / 3. 19.102
libswscale 2. 1.101 / 2. 1.101
libswresample 0. 16.100 / 0. 16.100
libpostproc 52. 1.100 / 52. 1.100
Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...

Use -h to get full help or, even better, run 'man ffmpeg'

You are now running the latest version of FFmpeg on your DNS-325, including the latest real-time library encoders shineenc for mp3, fdk-aac for aac & opus for futur standard.

3. Compile SoX

audio-soxSoX is a cross-platform command line utility that can apply various effects to sound files (gain, DRC, ...).

It is not heavily optimised for integer ARM processor, but it can still apply a DRC filter to a sound file in realtime on a DNS-325.

To compile SoX, we need to :

  • recover sources from latest stable (GIT is not compiling at the time of this article)
  • Correct a source bug specific to uclibc environment (https://bugs.gentoo.org/attachment.cgi?id=246167&action=diff)
  • call autotools
  • configure without ffmpeg, oss & ladspa support and set prefix to /ffp
  • make & install

# cd /ffp/home/root
# wget http://sourceforge.net/settings/mirror_choices?projectname=sox&filename=sox/14.4.0/sox-14.4.0.tar.gz
# tar xzvf sox-14.4.0.tar.gz
# cd sox-14.4.0
# sed -i 's/^#elif defined __GLIBC__$/#elif defined __GLIBC__ \&\& ! defined __UCLIBC__/g' ./src/formats.c
# sed -i 's/#error FIX NEEDED HERE/\/* #error FIX NEEDED HERE *\//g' ./src/formats.c
# autoreconf -i
# sed -i 's/^#!.*$/#!\/ffp\/bin\/sh/g' configure
# ./configure --disable-shared --with-ffmpeg=no --with-oss=no --with-ladspa=no --prefix=/ffp
# make
# make install

SoX is now available as a command line tool.

4. Speed Test Comparison

Now that we have a complete multimedia framework, let's do a speed test to compare all different tools and codecs on our DNS-325.

The original file is a sacred classical song from Vivaldi compressed in a 320kbits mp3 file with LAME.

These tests have been done on a DNS-325 running some classic services (SMB share, uPnP twonkyserver, subsonic server, ...) but with no special activity.

Here are the results, giving encoding time compared to the original songs length (in seconds) :

Encoder Duration (s) Realtime (x)
Original song 184 1.00
FFmpeg + ShineEnc 58 3.17
FFmpeg with libshine 57 3.23
FFmpeg with libfdk_aac 51 3.61
FFmpeg with libopus 52 3.54
FFmpeg with libtwolame 244 0.75
Lame 483 0.38

All transcoding chains giving more than realtime compression are in green, others are in red.

It clearly shows that FFmpeg with libshine & libfdk_aac libraries are the most efficient ones, giving more than 3x realtime encoding speed !

FFmpeg with libopus library will be a very good competitor in a near futur ...

5. Example : Apply DRC to an Audio File

Using all these tools, you can for example setup a command line to apply some Dynamic Range Compression on some audio files, to make them easily audible even in a very noisy environment (like inside a car ...).

The process will be :

  1. to decode any type of audio file format, like MP3
  2. to apply a DRC filter
  3. to recompress the resulting file in a high quality format, like AAC

The command line to do that will look like :

ffmpeg -i input-file.mp3 -f wav -acodec pcm_s16le -ac 2 -ar 44100 - | sox -t raw -b 16 -e signed -c 2 -r 44100 - -t wav -b 16 -e signed -c 2 -r 44100 - compand 0.3,1 6:-70,-60,-20 -6 -90 0.2 | ffmpeg -i - -f adts -acodec libfdk_aac -b:a 128k -ac 2 output-file.aac

 

Enjoy your new realtime audio encoding appliance   :-)

Signature Technoblog

This article is published "as is", without any warranty that it will work for your specific need.
If you think this article needs some complement, or simply if you think it saved you lots of time & trouble,
just let me know at This email address is being protected from spambots. You need JavaScript enabled to view it.. Cheers !

icon linux icon debian icon apache icon mysql icon php icon piwik icon googleplus