Update 2 – Updated to allow build for ARMv7 CPU in Synology products using Armada370 SoC (currently the DS213j).
Update – I discovered that the cross-compiled ARMv5 build of FFmpeg cannot encode AC3 audio without severe artifacts. After a very long time spent recompiling with different options, trying static builds etc. I finally found that the Synology cross toolchain (GCC 4.2.1) appears to cause the problem. Compiling natively on a bootstrapped ARMv5 Synology system with GCC 4.2.3 produces a working binary. However, I had to spend a long time re-working the method, particularly since you can’t run automake to build libshine on the Synology due to a dependency on a threaded version of Perl, which is missing from the Optware repo, and in turn is very tricky to compile. I have appended the ARM shared build guide to the end of this post.
This method will build FFmpeg with portable shared libraries (linked with relative paths) using a Ubuntu Desktop 12 VM. The >10MB size of the static executable is kind of getting out of hand especially on embedded systems with very limited RAM. Using shared libs means many concurrent instances of FFmpeg can use broadly the same memory footprint, and package distribution binaries can be smaller – our target systems already have libmp3lame, libz, libssl, libcrypto, libfreetype, libexpat, and libpthread which add up to several megabytes. I’m also guessing that the OS will decide when to unload them from RAM which could help when FFmpeg is being launched repeatedly in a short period of time.
Although the unmodified source code will compile successfully for QorIQ CPUs, the FFmpeg binary will core dump when running any command on a video file. I contacted Synology Support for help with this issue. Their developers mentioned that they had needed to make numerous patches to the source of the version they used for DSM, and they guessed that the following one in particular was likely to be needed. This produced a working binary.
--- ffmpeg/libavcodec/ppc/dsputil_ppc.c 2012-02-17 18:20:07.000000000 +0000
+++ ffmpeg-patched/libavcodec/ppc/dsputil_ppc.c 2012-10-18 22:15:50.740992688 +0100
@@ -116,7 +116,11 @@
/* below the constraint "b" seems to mean "Address base register"
in gcc-3.3 / RS/6000 speaks. seems to avoid using r0, so.... */
+ #if 1
+ __asm__ volatile("dcbz %0, %1" : : "r" (fakedata_middle), "r" (zero));
+ #else
__asm__ volatile("dcbzl %0, %1" : : "b" (fakedata_middle), "r" (zero));
+ #endif
for (i = 0; i < 1024 ; i ++) {
if (fakedata[i] == (char)0)
Here is a patch to add libshine as an additional encoder to FFmpeg 1.1.1 which is particularly useful on ARMv5 CPUs which lack an FPU (shine is an integer maths encoder).
diff -rupN ffmpeg-1.1.1/configure ffmpeg-1.1.1-shine/configure
--- ffmpeg-1.1.1/configure 2013-01-20 01:06:39.000000000 +0000
+++ ffmpeg-1.1.1-shine/configure 2013-02-05 13:46:30.000000000 +0000
@@ -214,6 +214,7 @@ External library support:
--enable-libpulse enable Pulseaudio input via libpulse [no]
--enable-librtmp enable RTMP[E] support via librtmp [no]
--enable-libschroedinger enable Dirac de/encoding via libschroedinger [no]
+ --enable-libshine enable fixed-point MP3 encoding via libshine [no]
--enable-libsoxr enable Include libsoxr resampling [no]
--enable-libspeex enable Speex de/encoding via libspeex [no]
--enable-libstagefright-h264 enable H.264 decoding via libstagefright [no]
@@ -1174,6 +1175,7 @@ CONFIG_LIST="
libpulse
librtmp
libschroedinger
+ libshine
libsoxr
libspeex
libstagefright_h264
@@ -1843,6 +1845,7 @@ libopus_decoder_deps="libopus"
libopus_encoder_deps="libopus"
libschroedinger_decoder_deps="libschroedinger"
libschroedinger_encoder_deps="libschroedinger"
+libshine_encoder_deps="libshine"
libspeex_decoder_deps="libspeex"
libspeex_encoder_deps="libspeex"
libstagefright_h264_decoder_deps="libstagefright_h264"
@@ -3843,6 +3846,7 @@ enabled libopus && require_pkg_config
enabled libpulse && require_pkg_config libpulse-simple pulse/simple.h pa_simple_new
enabled librtmp && require_pkg_config librtmp librtmp/rtmp.h RTMP_Socket
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 libsoxr && require libsoxr soxr.h soxr_create -lsoxr
enabled libspeex && require libspeex speex/speex.h speex_decoder_init -lspeex
enabled libstagefright_h264 && require_cpp libstagefright_h264 "binder/ProcessState.h media/stagefright/MetaData.h
@@ -4264,6 +4268,7 @@ echo "libopus enabled ${libopu
echo "libpulse enabled ${libpulse-no}"
echo "librtmp enabled ${librtmp-no}"
echo "libschroedinger enabled ${libschroedinger-no}"
+echo "libshine enabled ${libshine-no}"
echo "libsoxr enabled ${libsoxr-no}"
echo "libspeex enabled ${libspeex-no}"
echo "libstagefright-h264 enabled ${libstagefright_h264-no}"
diff -rupN ffmpeg-1.1.1/libavcodec/allcodecs.c ffmpeg-1.1.1-shine/libavcodec/allcodecs.c
--- ffmpeg-1.1.1/libavcodec/allcodecs.c 2013-01-06 21:53:29.000000000 +0000
+++ ffmpeg-1.1.1-shine/libavcodec/allcodecs.c 2013-02-05 13:48:04.000000000 +0000
@@ -469,6 +469,7 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (LIBGSM, libgsm);
REGISTER_ENCDEC (LIBGSM_MS, libgsm_ms);
REGISTER_ENCDEC (LIBILBC, libilbc);
+ REGISTER_ENCODER(LIBSHINE, libshine);
REGISTER_ENCODER(LIBMP3LAME, libmp3lame);
REGISTER_ENCDEC (LIBOPENCORE_AMRNB, libopencore_amrnb);
REGISTER_DECODER(LIBOPENCORE_AMRWB, libopencore_amrwb);
diff -rupN ffmpeg-1.1.1/libavcodec/libshine.c ffmpeg-1.1.1-shine/libavcodec/libshine.c
--- ffmpeg-1.1.1/libavcodec/libshine.c 1970-01-01 00:00:00.000000000 +0000
+++ ffmpeg-1.1.1-shine/libavcodec/libshine.c 2013-02-05 13:49:39.000000000 +0000
@@ -0,0 +1,149 @@
+/*
+ * 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 "audio_frame_queue.h"
+#include "avcodec.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;
+
+ if (avctx->channels <= 0 || avctx->channels > 2){
+ av_log(avctx, AV_LOG_ERROR, "only mono or stereo is supportedn");
+ return AVERROR(EINVAL);
+ }
+
+ 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 bitraten");
+ 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 smalln");
+ 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 supportedn");
+ 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)"),
+};
diff -rupN ffmpeg-1.1.1/libavcodec/Makefile ffmpeg-1.1.1-shine/libavcodec/Makefile
--- ffmpeg-1.1.1/libavcodec/Makefile 2013-01-06 21:53:29.000000000 +0000
+++ ffmpeg-1.1.1-shine/libavcodec/Makefile 2013-02-05 13:49:09.000000000 +0000
@@ -685,6 +685,7 @@ OBJS-$(CONFIG_LIBSCHROEDINGER_DECODER)
libschroedinger.o
OBJS-$(CONFIG_LIBSCHROEDINGER_ENCODER) += libschroedingerenc.o
libschroedinger.o
+OBJS-$(CONFIG_LIBSHINE_ENCODER) += libshine.o
OBJS-$(CONFIG_LIBSPEEX_DECODER) += libspeexdec.o
OBJS-$(CONFIG_LIBSPEEX_ENCODER) += libspeexenc.o audio_frame_queue.o
OBJS-$(CONFIG_LIBSTAGEFRIGHT_H264_DECODER)+= libstagefright.o
#-----set up Synology toolchain
cd ~/Downloads
export DL_PATH="http://sourceforge.net/projects/dsgpl/files/DSM%204.1%20Tool%20Chains"
#----------------------------------------------------
#-----NOW PASTE ONE OF THE FOLLOWING FOUR BLOCKS TO THE TERMINAL, DEPENDING ON YOUR TARGET CPU TYPE
#-----Marvell Kirkwood mv6281/mv6282 CPU is based on the ARMv5TE core which has DSP and thumb instruction support
#-----http://www.arm.com/products/processors/technologies/dsp-simd.php
#-----http://www.marvell.com/embedded-processors/kirkwood/assets/88f6282-3_pb.pdf
wget "${DL_PATH}/Marvell%2088F628x%20Linux%202.6.32/gcc421_glibc25_88f6281-GPL.tgz"
tar xvzf gcc421_glibc25_88f6281-GPL.tgz
export CROSS_PREFIX=arm-none-linux-gnueabi
export TOOLCHAIN=/usr/local/${CROSS_PREFIX}
export TARGET=armle-unknown-linux
export MARCH=-march=armv5te
export LAME_CONFIG="./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static --disable-decoder"
export SSL_CONFIG="./Configure.syno --prefix=${TOOLCHAIN} threads shared linux-elf-armle"
#-----ARMv5TE CPU-specific options (based on inspecting 'configure' script https://github.com/FFmpeg/FFmpeg/blob/master/configure)
#-----pkg-config needs to be defined because with cross-prefix it assumes ${CROSS_PREFIX}-pkg-config which doesn't exist, and then librtmp won't be detected
#-----zbmv decoder won't cross compile for some reason so it is disabled: https://ffmpeg.org/trac/ffmpeg/ticket/1794
#-----something changed in FFmpeg 1.1.1's configure script and now vfp and neon optimizations have to be explicitly disabled for ARMv5TE, which doesn't have those features in any case
export FF_CONFIG="./configure --arch=arm --cpu=armv5te --enable-cross-compile --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --target-os=linux --prefix=${TOOLCHAIN} --enable-shared --disable-static --enable-pic --disable-ffplay --disable-ffserver --disable-vfp --disable-neon --disable-debug --enable-pthreads --enable-libshine --enable-librtmp --enable-libass --disable-encoder=zmbv --pkg-config=pkg-config --extra-version=compiled_by_patters_for_Serviio"
#-----sudo apt-get automake
#-----sudo apt-get libtool
wget https://github.com/savonet/shine/zipball/master
unzip master
cd savonet-shine-*
./bootstrap
cd ..
#-----Marvell Armada 370 CPU is based on a dual issue ARMv7 core with VFPv3-16
#-----http://www.marvell.com/embedded-processors/armada-300/assets/Marvell_ARMADA_370_SoC.pdf
#-----http://www.arm.com/products/processors/technologies/vector-floating-point.php
wget "${DL_PATH}/Marvell%20armada%20370%20Linux%203.2.30/gcc464_glibc215_hard_armada370-GPL.tgz"
tar xvzf gcc464_glibc215_hard_armada370-GPL.tgz
#-----correct some missing header file links in the toolchain
cp /usr/local/arm-marvell-linux-gnueabi/arm-marvell-linux-gnueabi/libc/thumb2/usr/include/asm/errno.h /usr/local/arm-marvell-linux-gnueabi/arm-marvell-linux-gnueabi/libc/usr/include/asm/errno.h
cp /usr/local/arm-marvell-linux-gnueabi/arm-marvell-linux-gnueabi/libc/thumb2/usr/include/asm/ioctl.h /usr/local/arm-marvell-linux-gnueabi/arm-marvell-linux-gnueabi/libc/usr/include/asm/ioctl.h
cp /usr/local/arm-marvell-linux-gnueabi/arm-marvell-linux-gnueabi/libc/thumb2/usr/include/asm/bitsperlong.h /usr/local/arm-marvell-linux-gnueabi/arm-marvell-linux-gnueabi/libc/usr/include/asm/bitsperlong.h
export CROSS_PREFIX=arm-marvell-linux-gnueabi
export TARGET=armle-unknown-linux
export TOOLCHAIN=/usr/local/${CROSS_PREFIX}
export MARCH="-mhard-float -mfpu=vfpv3-d16"
export LAME_CONFIG="./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static --disable-decoder"
export SSL_CONFIG="./Configure.syno --prefix=${TOOLCHAIN} threads shared no-asm linux-elf-armle"
#-----ARMv7 CPU-specific options (based on inspecting 'configure' script https://github.com/FFmpeg/FFmpeg/blob/master/configure)
#-----pkg-config needs to be defined because with cross-prefix it assumes ${CROSS_PREFIX}-pkg-config which doesn't exist, and then librtmp won't be detected
export FF_CONFIG="./configure --arch=arm --enable-cross-compile --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --target-os=linux --prefix=${TOOLCHAIN} --enable-shared --disable-static --enable-pic --disable-ffplay --disable-ffserver --disable-neon --enable-thumb --disable-debug --enable-pthreads --enable-libmp3lame --enable-librtmp --enable-libass --pkg-config=pkg-config --extra-version=compiled_by_patters_for_Serviio"
#-----Intel CPUs used in Synology products are all 64bit and SSSE3 capable but existing DSM libs are 32bit, so use the i686 toolchain rather than x86_64
wget "${DL_PATH}/Intel%20x86%20Linux%203.2.11%20%28Pineview%29/gcc421_glibc236_x86-GPL.tgz"
tar xvzf gcc421_glibc236_x86-GPL.tgz
export CROSS_PREFIX=i686-linux-gnu
export TOOLCHAIN=/usr/local/${CROSS_PREFIX}
export TARGET=i686-linux-gnu
export LAME_CONFIG="./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static --disable-decoder --enable-nasm"
export SSL_CONFIG="./Configure.syno --prefix=${TOOLCHAIN} threads shared linux-generic32"
#-----Intel CPU-specific options (based on inspecting 'configure' script https://github.com/FFmpeg/FFmpeg/blob/master/configure)
#-----pkg-config needs to be defined because with cross-prefix it assumes ${CROSS_PREFIX}-pkg-config which doesn't exist, and then librtmp won't be detected
export FF_CONFIG="./configure --arch=x86 --enable-ssse3 --enable-cross-compile --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --target-os=linux --prefix=${TOOLCHAIN} --enable-shared --disable-static --enable-pic --disable-ffplay --disable-ffserver --disable-debug --enable-pthreads --enable-libmp3lame --enable-librtmp --enable-libass --pkg-config=pkg-config --extra-version=compiled_by_patters_for_Serviio"
sudo apt-get install yasm
#-----QorIQ P1022 CPU is based on the PowerPC e500v2 core which has Signal Processing Engine which is not a classic FPU design
#-----Some QorIQ models have e500mc cores with true FPUs but these are not used in 2013 series Synology NAS
#-----http://en.wikipedia.org/wiki/QorIQ
#-----http://cache.freescale.com/files/32bit/doc/fact_sheet/QP1022FS.pdf?fpsp=1
wget "${DL_PATH}/PowerPC%20QorIQ%20Linux%202.6.32/gcc4374_eglibc2874_qoriq-GPL.tgz"
tar xvzf gcc4374_eglibc2874_qoriq-GPL.tgz
export CROSS_PREFIX=powerpc-none-linux-gnuspe
export TOOLCHAIN=/usr/local/${CROSS_PREFIX}
export TARGET=powerpc-unknown-linux
export MARCH="-mcpu=8548 -mhard-float -mfloat-gprs=double"
export LAME_CONFIG="./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static --disable-decoder"
export SSL_CONFIG="./Configure.syno --prefix=${TOOLCHAIN} threads shared linux-ppc"
#-----PowerPC e500v2 CPU-specific options (based on inspecting 'configure' script https://github.com/FFmpeg/FFmpeg/blob/master/configure)
#-----pkg-config needs to be defined because with cross-prefix it assumes ${CROSS_PREFIX}-pkg-config which doesn't exist, and then librtmp won't be detected
export FF_CONFIG="./configure --arch=ppc --cpu=e500v2 --enable-cross-compile --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --target-os=linux --prefix=${TOOLCHAIN} --enable-shared --disable-static --enable-pic --disable-ffplay --disable-ffserver --disable-debug --enable-pthreads --enable-libmp3lame --enable-librtmp --enable-libass --pkg-config=pkg-config --extra-version=compiled_by_patters_for_Serviio"
#----------------------------------------------------
#-----script continues
sudo mv ${CROSS_PREFIX} /usr/local
export AR=${TOOLCHAIN}/bin/${CROSS_PREFIX}-ar
export CC=${TOOLCHAIN}/bin/${CROSS_PREFIX}-gcc
export CXX=${TOOLCHAIN}/bin/${CROSS_PREFIX}-g++
export LD=${TOOLCHAIN}/bin/${CROSS_PREFIX}-ld
export RANLIB=${TOOLCHAIN}/bin/${CROSS_PREFIX}-ranlib
export CFLAGS="-I${TOOLCHAIN}/include -O3 ${MARCH}"
export LDFLAGS="-L${TOOLCHAIN}/lib"
export PKG_CONFIG_PATH="${TOOLCHAIN}/lib/pkgconfig"
#-----fetch Synology's DSM sources for certain libraries
wget http://dl.dropbox.com/u/1188556/DSM-source.tgz
tar xvzf DSM-source.tgz
cd DSM-source
#-----libz shared lib (toolchain only has static lib)
cd zlib-1.2
./configure --prefix=${TOOLCHAIN}
make
make install
cd ..
#-----lame shared lib
cd lame-398
$LAME_CONFIG
make
make install
cd ..
#-----shine shared lib for ARMv5
[ "${CROSS_PREFIX}" == "arm-none-linux-gnueabi" ] && mv ../savonet-shine-* .
[ "${CROSS_PREFIX}" == "arm-none-linux-gnueabi" ] && cd savonet-shine-*
[ "${CROSS_PREFIX}" == "arm-none-linux-gnueabi" ] && ./configure --prefix=${TOOLCHAIN} --host=${CROSS_PREFIX} --build=x86_64-linux-gnu --enable-shared --disable-static
[ "${CROSS_PREFIX}" == "arm-none-linux-gnueabi" ] && make
[ "${CROSS_PREFIX}" == "arm-none-linux-gnueabi" ] && make install
[ "${CROSS_PREFIX}" == "arm-none-linux-gnueabi" ] && cd ..
#-----openssl shared lib (Synology seem to have tweaked the source for each CPU)
cd openssl-1.0.x-${CROSS_PREFIX}
$SSL_CONFIG
make
make install
cd ..
#-----expat shared lib
cd expat-2.x
./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static
make
make install
cd ..
#-----freetype shared lib
cd freetype-2.3.7
./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static
make
make install
cd ..
#-----finished building DSM-bundled libs
cd ..
#-----fribidi shared lib
wget http://fribidi.org/download/fribidi-0.19.5.tar.bz2
tar xvjf fribidi-0.19.5.tar.bz2
cd fribidi-0.19.5
#-----patch fribidi source since it won't compile - some sort of page size function is no longer available
#-----error on ARMv5 and Intel: fribidi-run.c:70: error: 'PAGE_SIZE' undeclared (first use in this function)
#-----error on QorIQ: include/asm/kdump.h:41: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'void'
#-----clues found here:
#-----http://armbedded.eu/node/56
#-----http://lists.debian.org/debian-glibc/2006/10/msg00169.html
#-----http://my.safaribooksonline.com/book/operating-systems-and-server-administration/linux/0596009585/advanced-file-i-o/mapping_files_into_memory
[ "${CROSS_PREFIX}" == "arm-marvell-linux-gnueabi" ] || sed -i "s|include <asm/page.h>|include <unistd.h>\n# define PAGE_SIZE sysconf(_SC_PAGESIZE)|" lib/common.h
./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static
make
make install
cd ..
#-----fontconfig shared lib
wget http://freedesktop.org/software/fontconfig/release/fontconfig-2.10.91.tar.gz
tar xvzf fontconfig-2.10.91.tar.gz
cd fontconfig-2.10.91
LDFLAGS=-Wl,-rpath,\'\$\$ORIGIN\' ./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static
#-----correct some non-standard library linking behaviour
sed -i "s/^hardcode_into_libs=yes/hardcode_into_libs=no/" libtool
make
make install
cd ..
#-----libass shared lib
wget http://libass.googlecode.com/files/libass-0.10.1.tar.gz
tar xvzf libass-0.10.1.tar.gz
cd libass-0.10.1
LDFLAGS=-Wl,-rpath,\'\$\$ORIGIN\' ./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-shared --disable-static
#-----correct some non-standard library linking behaviour
sed -i "s/^hardcode_into_libs=yes/hardcode_into_libs=no/" libtool
make
make install
cd ..
#-----librtmp shared lib
wget http://download.serviio.org/opensource/rtmpdump.tar.gz
tar xvfz rtmpdump.tar.gz
cd rtmpdump
make CROSS_COMPILE=${TOOLCHAIN}/bin/${CROSS_PREFIX}- SYS=posix prefix=${TOOLCHAIN} INC=-I${TOOLCHAIN}/include XLDFLAGS=-L${TOOLCHAIN}/lib
make install prefix=${TOOLCHAIN}
cd ..
#-----FFmpeg
wget http://www.ffmpeg.org/releases/ffmpeg-1.1.1.tar.gz
tar xvzf ffmpeg-1.1.1.tar.gz
cd ffmpeg-1.1.1
#-----patch in libshine support for ARMv5 build
[ "${CROSS_PREFIX}" == "arm-none-linux-gnueabi" ] && wget http://dl.dropbox.com/u/1188556/ffmpeg-1.1.1-shine.patch
[ "${CROSS_PREFIX}" == "arm-none-linux-gnueabi" ] && patch --verbose -p1 < ffmpeg-1.1.1-shine.patch
#-----fetch latest wrapper source code from richardpl's FFmpeg fork
[ "${CROSS_PREFIX}" == "arm-none-linux-gnueabi" ] && wget --no-check-certificate https://raw.github.com/richardpl/FFmpeg/shine/libavcodec/libshine.c -O libavcodec/libshine.c
#-----ARM-specific fixed point maths modification for mpeg audio encoder
[ "${CROSS_PREFIX}" == "arm-none-linux-gnueabi" ] && sed -i "s/^#define USE_FLOATS//" libavcodec/mpegaudioenc.c
#-----QorIQ-specific fix provided by Synology Support
[ "${CROSS_PREFIX}" == "powerpc-none-linux-gnuspe" ] && wget http://dl.dropbox.com/u/1188556/ffmpeg-synology-qoriq.patch
[ "${CROSS_PREFIX}" == "powerpc-none-linux-gnuspe" ] && patch --verbose -p1 < ffmpeg-synology-qoriq.patch
#-----set library linker to use relative library search path (../lib and .)
#-----tricky shell escaping of $ORIGIN is required http://itee.uq.edu.au/~daniel/using_origin/
#-----http://stackoverflow.com/questions/6562403/i-dont-understand-wl-rpath-wl
#-----the use of -rpath-link appears to be necessary for compilation using the Armada370 toolchain
LDFLAGS=-Wl,-rpath,\'\$\$ORIGIN/../lib:\$\$ORIGIN\',-rpath-link,${TOOLCHAIN}/lib ${FF_CONFIG}
#-----external libs (librtmp, libass) don't seem to link correctly as shared libs
#-----on QorIQ and Intel toolchains without this fix (check with objdump -x)
[ "${CROSS_PREFIX}" == "arm-none-linux-gnueabi" ] || sed -r -i 's%(^LDFLAGS.*)\$\(LDFLAGS\)%\1-Wl,-rpath=z888z\$\$ORIGIN/../libz888z%' common.mak; sed -i "s/z888z/'/g" common.mak
make
make install
cd ..
mkdir native-${CROSS_PREFIX}
cd native-${CROSS_PREFIX}
cp ${TOOLCHAIN}/bin/ffmpeg .
cp ${TOOLCHAIN}/lib/libass.so.4 .
cp ${TOOLCHAIN}/lib/libavcodec.so.54 .
cp ${TOOLCHAIN}/lib/libavdevice.so.54 .
cp ${TOOLCHAIN}/lib/libavfilter.so.3 .
cp ${TOOLCHAIN}/lib/libavformat.so.54 .
cp ${TOOLCHAIN}/lib/libavutil.so.52 .
cp ${TOOLCHAIN}/lib/libfontconfig.so.1 .
cp ${TOOLCHAIN}/lib/libfribidi.so.0 .
cp ${TOOLCHAIN}/lib/librtmp.so.0 .
cp ${TOOLCHAIN}/lib/libswresample.so.0 .
cp ${TOOLCHAIN}/lib/libswscale.so.2 .
[ "${CROSS_PREFIX}" == "arm-none-linux-gnueabi" ] && cp ${TOOLCHAIN}/lib/libshine.so.1 .
sudo chown root:root *
cd ..
mkdir oldDSM
cd oldDSM
cp ${TOOLCHAIN}/lib/libz.so.1 .
cp ${TOOLCHAIN}/lib/libcrypto.so.1.0.0 .
cp ${TOOLCHAIN}/lib/libssl.so.1.0.0 .
cp ${TOOLCHAIN}/lib/libmp3lame.so.0 .
cp ${TOOLCHAIN}/lib/libfreetype.so.6 .
cp ${TOOLCHAIN}/lib/libexpat.so.1 .
sudo chown root:root *
cd ..
Native compile for ARMv5 systems
Here is the method to natively compile FFmpeg with libshine and libass, with shared libraries rather than static. It transpires that the cross compiled build has a broken AC3 encoder which produces crackling and muffled audio streams. The guide assumes a bootstrapped NAS with the optware-devel tools installed. See my much earlier blog post for details of how to set that up, since there are some pitfalls. I haven’t run through and tested the whole sequence – I have assembled this from hundreds of lines of notes I made while working – but I’m publishing it here to help others, and to refer to in future when I need to build newer FFmpeg revisions for future Serviio releases.
#-----on a bootstrapped system that's since had its DSM upgraded the path has been reset
#export PATH=/opt/bin:/opt/sbin:$PATH
#-----fetch headers for zlib, OpenSSL, LAME, freetype2, and expat libraries obtained by compiling the DSM 4.1 included versions from source, plus ncurses headers from Synology ARMv5 cross toolchain
cd /tmp
mkdir include
cd include
wget http://dl.dropbox.com/u/1188556/synology-armv5te-headers.tgz
tar xvzf synology-armv5te-headers.tgz
#-----this archive also contains pkgconfig definitions for DSM's existing versions of libcrypto, libssl and freetype2, edited to fit requirements
#-----this will allow librtmp to link to DSM's existing OpenSSL libraries, and libass to link to DSM's bundled freetype2 and expat libraries
cp *.pc /opt/lib/pkgconfig
cd /volume1/@tmp
#-----fetch savonet-shine source which has already had the bootstrap script run on a Linux system with automake
#-----on the Linux system you would need to run:
#sudo apt-get automake
#sudo apt-get libtool
#wget https://github.com/savonet/shine/zipball/master
#unzip master
#cd savonet-shine-*
#./bootstrap
#cd ..
#-----but here's one I made earlier:
wget http://dl.dropbox.com/u/1188556/savonet-shine-43c74e7.tgz
tar xvzf savonet-shine-43c74e7.tgz
cd savonet-shine-43c74e7
./configure --prefix=/opt --enable-shared --disable-static
make
#-----don't worry about the repeated message #warning NO MULT FILE FOR ARCHITECTURE - USING GENERIC MATH
#-----the include for mult_sarm_gcc.h (optimized ARM maths in assembler) is commented out in src/lib/types.h
#-----the comment mentions that fixing this is on the to-do list, so it can't be helped
make install
cd ..
#-----fetch libRTMP source
wget http://download.serviio.org/opensource/rtmpdump.tar.gz
tar xvfz rtmpdump.tar.gz
cd rtmpdump
#-----the following options will force it to use the existing OpenSSL libs thanks to the imported headers
make SYS=posix prefix=/opt INC=-I/tmp/include XLDFLAGS=-L/lib
make install prefix=/opt
cp -R /opt/include/librtmp /tmp/include
#-----remove unsupported URL line from pkgconfig/librtmp.pc
#-----pkg-config --exists --print-errors librtmp
sed -i -e '/^URL/d' /opt/lib/pkgconfig/librtmp.pc
cd ..
#-----fetch fribidi source
wget http://fribidi.org/download/fribidi-0.19.5.tar.bz2
tar xvjf fribidi-0.19.5.tar.bz2
cd fribidi-0.19.5
#-----patch fribidi source since it won't compile on ARMv5
#-----fribidi-run.c:70: error: 'PAGE_SIZE' undeclared (first use in this function)
#-----clues found here:
#-----http://armbedded.eu/node/56
#-----http://lists.debian.org/debian-glibc/2006/10/msg00169.html
#-----http://my.safaribooksonline.com/book/operating-systems-and-server-administration/linux/0596009585/advanced-file-i-o/mapping_files_into_memory
sed -i "s|include <asm/page.h>|include <unistd.h>\n# define PAGE_SIZE sysconf(_SC_PAGESIZE)|" lib/common.h
./configure --prefix=/opt --enable-shared --disable-static
make
make install
cd ..
#-----fetch fontconfig source
wget http://freedesktop.org/software/fontconfig/release/fontconfig-2.10.91.tar.gz
tar xvzf fontconfig-2.10.91.tar.gz
cd fontconfig-2.10.91
LDFLAGS=-Wl,-rpath='$$ORIGIN' ./configure --prefix=/opt --enable-shared --disable-static
#-----correct some non-standard library linking behaviour
sed -i "s/^hardcode_into_libs=yes/hardcode_into_libs=no/" libtool
sed -i "s|^sys_lib_search_path_spec="/opt/lib/gcc/arm-none-linux-gnueabi/4.2.3 /opt/arm-none-linux-gnueabi/lib /opt/lib /lib /usr/lib"|sys_lib_search_path_spec="/lib /usr/lib /opt/lib/gcc/arm-none-linux-gnueabi/4.2.3 /opt/arm-none-linux-gnueabi/lib /opt/lib"|" libtool
make
make install
cd ..
#-----fetch libass source
wget http://libass.googlecode.com/files/libass-0.10.1.tar.gz
tar xvzf libass-0.10.1.tar.gz
cd libass-0.10.1
export CFLAGS=-I/tmp/include
LDFLAGS=-Wl,-rpath='$$ORIGIN' ./configure --prefix=/opt --enable-shared --disable-static
#-----correct some non-standard library linking behaviour
sed -i "s/^hardcode_into_libs=yes/hardcode_into_libs=no/" libtool
sed -i "s|^sys_lib_search_path_spec="/opt/lib/gcc/arm-none-linux-gnueabi/4.2.3 /opt/arm-none-linux-gnueabi/lib /opt/lib /lib /usr/lib"|sys_lib_search_path_spec="/lib /usr/lib /opt/lib/gcc/arm-none-linux-gnueabi/4.2.3 /opt/arm-none-linux-gnueabi/lib /opt/lib"|" libtool
make
make install
cd ..
#-----fetch exact FFmpeg source version that Serviio requires
wget http://www.ffmpeg.org/releases/ffmpeg-1.1.1.tar.gz
tar xvzf ffmpeg-1.1.1.tar.gz
cd ffmpeg-1.1.1
#-----libshine patch by richardpl posted in FFmpeg ticket which I raised, applied to ffmpeg-1.1.1 by hand, then diffed to make patch file
#-----https://ffmpeg.org/trac/ffmpeg/ticket/1457
wget http://dl.dropbox.com/u/1188556/ffmpeg-1.1.1-shine.patch
patch -p1 --verbose < ffmpeg-1.1.1-shine.patch
#-----fetch latest wrapper source code from richardpl's FFmpeg fork
wget --no-check-certificate https://raw.github.com/richardpl/FFmpeg/shine/libavcodec/libshine.c -O libavcodec/libshine.c
#-----ARMv5-specific fixed point maths modification for mpeg audio encoder, mentioned in same ticket
sed -i "s/^#define USE_FLOATS//" libavcodec/mpegaudioenc.c
#-----FFmpeg configure parameters for native compile with shared libraries
#-----something changed in FFmpeg 1.1.1's configure script and now vfp and neon optimizations have to be explicitly disabled for ARMv5TE, which doesn't have those features in any case
export FF_CONFIG="./configure --arch=arm --cpu=armv5te --prefix=/opt --extra-cflags=-I/tmp/include --enable-shared --disable-static --enable-pic --disable-ffplay --disable-ffserver --disable-vfp --disable-neon --disable-debug --enable-pthreads --enable-libshine --enable-librtmp --enable-libass --extra-version=compiled_by_patters_for_Serviio"
#-----set library linker to use relative library search path (../lib:.)
#-----tricky shell escaping of $ORIGIN is required http://itee.uq.edu.au/~daniel/using_origin/
#-----http://stackoverflow.com/questions/6562403/i-dont-understand-wl-rpath-wl
LDFLAGS=-Wl,-rpath='$$ORIGIN/../lib:$$ORIGIN' ${FF_CONFIG}
make
make install
mkdir /volume1/@tmp/binaries
cd /volume1/@tmp/binaries
mkdir bin
mkdir lib
cp /opt/bin/ffmpeg bin
cp /opt/lib/libass.so.4 lib
cp /opt/lib/libavcodec.so.54 lib
cp /opt/lib/libavdevice.so.54 lib
cp /opt/lib/libavfilter.so.3 lib
cp /opt/lib/libavformat.so.54 lib
cp /opt/lib/libavutil.so.52 lib
cp /opt/lib/libfontconfig.so.1 lib
cp /opt/lib/libfribidi.so.0 lib
cp /opt/lib/librtmp.so.0 lib
cp /opt/lib/libshine.so.1 lib
cp /opt/lib/libswresample.so.0 lib
cp /opt/lib/libswscale.so.2 lib
tar -cvf ffmpeg-syno-armv5tel.tar *
gzip ffmpeg-syno-armv5tel.tar
mv ffmpeg-syno-armv5tel.tar.gz ffmpeg-syno-armv5tel.tgz
Here’s how the library dependencies look. There are no links to any libraries in /opt, and DSM-bundled libraries in /lib are linked to where possible. All the other new libraries are kept within the Serviio lib folder (../lib relative to the ffmpeg binary).
~$ ldd /volume1/@appstore/Serviio/bin/ffmpeg
libavdevice.so.54 => /volume1/@appstore/Serviio/bin/../lib/libavdevice.so.54 (0x40026000)
libavfilter.so.3 => /volume1/@appstore/Serviio/bin/../lib/libavfilter.so.3 (0x40038000)
libavformat.so.54 => /volume1/@appstore/Serviio/bin/../lib/libavformat.so.54 (0x40095000)
libavcodec.so.54 => /volume1/@appstore/Serviio/bin/../lib/libavcodec.so.54 (0x401db000)
libswresample.so.0 => /volume1/@appstore/Serviio/bin/../lib/libswresample.so.0 (0x40f36000)
libswscale.so.2 => /volume1/@appstore/Serviio/bin/../lib/libswscale.so.2 (0x40f50000)
libavutil.so.52 => /volume1/@appstore/Serviio/bin/../lib/libavutil.so.52 (0x40f90000)
libm.so.6 => /lib/libm.so.6 (0x40fcc000)
libpthread.so.0 => /lib/libpthread.so.0 (0x4107b000)
libc.so.6 => /lib/libc.so.6 (0x4109b000)
librt.so.1 => /lib/librt.so.1 (0x411ca000)
libass.so.4 => /volume1/@appstore/Serviio/bin/../lib/libass.so.4 (0x411d9000)
librtmp.so.0 => /volume1/@appstore/Serviio/bin/../lib/librtmp.so.0 (0x4120b000)
libz.so.1 => /lib/libz.so.1 (0x4122a000)
libshine.so.1 => /volume1/@appstore/Serviio/bin/../lib/libshine.so.1 (0x41247000)
/lib/ld-linux.so.3 (0x40000000)
libfreetype.so.6 => /lib/libfreetype.so.6 (0x41259000)
libfribidi.so.0 => /volume1/@appstore/Serviio/bin/../lib/libfribidi.so.0 (0x41318000)
libfontconfig.so.1 => /volume1/@appstore/Serviio/bin/../lib/libfontconfig.so.1 (0x41337000)
libssl.so.1.0.0 => /lib/libssl.so.1.0.0 (0x41386000)
libcrypto.so.1.0.0 => /lib/libcrypto.so.1.0.0 (0x413d2000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x4156d000)
libexpat.so.1 => /lib/libexpat.so.1 (0x41581000)
libdl.so.2 => /lib/libdl.so.2 (0x415a8000)











