Cross-compiling FFmpeg for Serviio with shared libraries on Synology NAS (Intel, ARMv5, ARMv7, and QorIQ CPUs)

Update 3 – Updated the guide for building FFmpeg 2.1, with libx264 which is required for Serviio 1.3. The patch for the libshine encoder is no longer needed now that it has been merged into FFmpeg. I’m proud to have suggested and tested that feature and contributed in some small way to FFmpeg!

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)
 
#-----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"
#-----libx264:
#-----http://forum.doom9.org/showthread.php?t=160584
#-----https://mailman.videolan.org/pipermail/x264-devel/2010-December/008093.html
#-----x264 builds with NEON by default because x264 is so slow without NEON (and on any non-NEON chip) as to be useless.
#-----You can of course compile with --disable-asm on such chips, but we don't do it by default because
#-----we don't feel it's necessary to actively support chips on which x264 would be basically useless
export X264_CONFIG="./configure --prefix=${TOOLCHAIN} --enable-shared --disable-opencl --disable-asm --enable-strip"
#-----FFmpeg:
#-----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 the FFmpeg 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 --enable-libx264 --enable-gpl --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, but no NEON vector unit
#-----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"
#-----libx264:
#-----http://forum.doom9.org/showthread.php?t=160584
#-----https://mailman.videolan.org/pipermail/x264-devel/2010-December/008093.html
#-----x264 builds with NEON by default because x264 is so slow without NEON (and on any non-NEON chip) as to be useless.
#-----You can of course compile with --disable-asm on such chips, but we don't do it by default because
#-----we don't feel it's necessary to actively support chips on which x264 would be basically useless
export X264_CONFIG="./configure --prefix=${TOOLCHAIN} --host=${TARGET} --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --enable-shared --disable-opencl --disable-asm --enable-pic --enable-strip"
#-----FFmpeg:
#-----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 --enable-libx264 --enable-gpl --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
#-----libx264 requires yasm 1.20 which is not on Ubuntu apt-get
#-----https://trac.ffmpeg.org/wiki/UbuntuCompilationGuide
sudo apt-get remove yasm
wget http://www.tortall.net/projects/yasm/releases/yasm-1.2.0.tar.gz
tar xvzf yasm-1.2.0.tar.gz
cd yasm-1.2.0
./configure --prefix=/
make
sudo make install
cd..
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"
export X264_CONFIG="./configure --prefix=${TOOLCHAIN} --host=${TARGET} --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --enable-shared --disable-opencl --enable-pic --enable-strip"
#-----FFmpeg:
#-----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 --enable-libx264 --enable-gpl --pkg-config=pkg-config --extra-version=compiled_by_patters_for_Serviio"




#-----QorIQ P1022 CPU is based on a dual PowerPC e500v2 core with Signal Processing Engine (SPE) which is not a classic FPU design, but no AltiVec vector unit 
#-----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"
#-----asm disabled since QorIQ has no AltiVec
export X264_CONFIG="./configure --prefix=${TOOLCHAIN} --host=${TARGET} --cross-prefix=${TOOLCHAIN}/bin/${CROSS_PREFIX}- --enable-shared --disable-opencl --disable-asm --enable-pic --enable-strip"
#-----FFmpeg:#-----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 --enable-libx264 --enable-gpl --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 LDSHARED="${TOOLCHAIN}/bin/${CROSS_PREFIX}-gcc -shared "
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 https://dl.dropboxusercontent.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}
#-----owing to a bug in the configure script, libz cross compiles without a SONAME (check it with objdump -x)
#-----http://forums.gentoo.org/viewtopic-p-7156392.html
sed -i "s/\(^LDSHARED=.*$\)/\1 -Wl,-soname,libz.so.1,--version-script,zlib.map/" Makefile
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
#-----Although libass would link correctly to older FFmpeg versions, this mod is now necessary:
#-----http://ffmpeg.org/pipermail/ffmpeg-user/2012-November/010906.html
sed -i -r "s/(^Libs: .*$)/\1 -lfontconfig -lfribidi -lfreetype -lexpat/" $TOOLCHAIN/lib/pkgconfig/libass.pc
cd ..

#-----librtmp shared lib
wget http://download.serviio.org/opensource/rtmpdump.tar.gz
tar xvzf 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 ..

#-----libx264 shared lib
wget http://download.serviio.org/opensource/last_x264.tar.bz2
tar xvfj last_x264.tar.bz2
cd x264-snapshot-20130529-2245
$X264_CONFIG
make
make install
cd ..

#-----FFmpeg
wget http://ffmpeg.org/releases/ffmpeg-2.1.tar.gz
tar xvzf ffmpeg-2.1.tar.gz
cd ffmpeg-2.1

#-----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 https://dl.dropboxusercontent.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 all toolchains except Marvell Kirkwood without this fix (check compiled binary with objdump -x)
[ "${CROSS_PREFIX}" == "arm-none-linux-gnueabi" ] || sed -r -i 's%(^LDFLAGS.*)\$\(LDFLAGS\)%\1-Wl,-rpath=z888z\$\$ORIGIN/../lib:\$\$ORIGINz888z%' 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.55 .
cp ${TOOLCHAIN}/lib/libavdevice.so.55 .
cp ${TOOLCHAIN}/lib/libavfilter.so.3 .
cp ${TOOLCHAIN}/lib/libavformat.so.55 .
cp ${TOOLCHAIN}/lib/libavutil.so.52 .
cp ${TOOLCHAIN}/lib/libfontconfig.so.1 .
cp ${TOOLCHAIN}/lib/libfribidi.so.0 .
cp ${TOOLCHAIN}/lib/libpostproc.so.52 .
cp ${TOOLCHAIN}/lib/librtmp.so.0 .
cp ${TOOLCHAIN}/lib/libswresample.so.0 .
cp ${TOOLCHAIN}/lib/libswscale.so.2 .
cp ${TOOLCHAIN}/lib/libx264.so.133 .
[ "${CROSS_PREFIX}" == "arm-none-linux-gnueabi" ] && cp ${TOOLCHAIN}/lib/libshine.so.3 .
sudo chown root:root *
tar -cvzf ffmpeg-syno-${CROSS_PREFIX}.tgz *
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 *
tar -cvzf ffmpeg-syno-${CROSS_PREFIX}-oldDSM.tgz *
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 --no-check-certificate https://dl.dropboxusercontent.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 --no-check-certificate https://dl.dropboxusercontent.com/u/1188556/savonet-shine-bc9e3b6.tgz
tar xvzf savonet-shine-bc9e3b6.tgz
cd savonet-shine-bc9e3b6
./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 libfdk-aac fixed point math AAC encoder
#-----binaries linked to it cannot be redistributed under GPL
#-----so it is excluded from the FFmpeg I built for the Serviio package
wget http://sourceforge.net/projects/opencore-amr/files/fdk-aac/fdk-aac-0.1.2.tar.gz
tar xvzf fdk-aac-0.1.2.tar.gz
cd fdk-aac-0.1.2
./configure --prefix=/opt --disable-static --enable-shared
make
make install
cd ..

#-----fetch libRTMP source
wget http://download.serviio.org/opensource/rtmpdump.tar.gz
tar xvzf 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 ..

#-----libx264 shared lib
wget http://download.serviio.org/opensource/last_x264.tar.bz2
tar xvfj last_x264.tar.bz2
cd x264-snapshot-20130529-2245
sed -i "s/^\${SRCPATH}\/version\.sh/bash \${SRCPATH}\/version\.sh/" ./configure
#-----http://forum.doom9.org/showthread.php?t=160584
#-----https://mailman.videolan.org/pipermail/x264-devel/2010-December/008093.html
#-----x264 builds with NEON by default because x264 is so slow without NEON (and on any non-NEON chip) as to be useless.
#-----You can of course compile with --disable-asm on such chips, but we don't do it by default because
#-----we don't feel it's necessary to actively support chips on which x264 would be basically useless
bash ./configure --prefix=/opt --enable-shared --disable-opencl --disable-asm
make
make install
cd ..

#-----FFmpeg
wget http://ffmpeg.org/releases/ffmpeg-2.1.tar.gz
tar xvzf ffmpeg-2.1.tar.gz
cd ffmpeg-2.1

#-----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 the FFmpeg 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-libfdk_aac --enable-librtmp --enable-libass --enable-libx264 --enable-gpl --enable-nonfree --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
cp /opt/bin/ffmpeg .
cp /opt/lib/libass.so.4 .
cp /opt/lib/libavcodec.so.55 .
cp /opt/lib/libavdevice.so.55 .
cp /opt/lib/libavfilter.so.3 .
cp /opt/lib/libavformat.so.55 .
cp /opt/lib/libavutil.so.52 .
cp /opt/lib/libfontconfig.so.1 .
cp /opt/lib/libfribidi.so.0 .
cp /opt/lib/libpostproc.so.52 .
cp /opt/lib/librtmp.so.0 .
cp /opt/lib/libshine.so.3 .
cp /opt/lib/libfdk-aac.so.0 .
cp /opt/lib/libswresample.so.0 .
cp /opt/lib/libswscale.so.2 .
cp /opt/lib/libx264.so.133 .
tar -cvzf ffmpeg-syno-armv5tel.tgz *
mkdir oldDSM
cd oldDSM
cp /lib/libz.so.1 .
cp /lib/libcrypto.so.1.0.0 .
cp /lib/libssl.so.1.0.0 .
cp /lib/libmp3lame.so.0 .
cp /lib/libfreetype.so.6 .
cp /lib/libexpat.so.1 .
tar -cvzf ffmpeg-syno-armv5tel-oldDSM.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.55 => /volume1/@appstore/Serviio/bin/../lib/libavdevice.so.55 (0x40026000)
        libavfilter.so.3 => /volume1/@appstore/Serviio/bin/../lib/libavfilter.so.3 (0x40039000)
        libavformat.so.55 => /volume1/@appstore/Serviio/bin/../lib/libavformat.so.55 (0x40112000)
        libavcodec.so.55 => /volume1/@appstore/Serviio/bin/../lib/libavcodec.so.55 (0x40271000)
        libpostproc.so.52 => /volume1/@appstore/Serviio/bin/../lib/libpostproc.so.52 (0x4110c000)
        libswresample.so.0 => /volume1/@appstore/Serviio/bin/../lib/libswresample.so.0 (0x4111e000)
        libswscale.so.2 => /volume1/@appstore/Serviio/bin/../lib/libswscale.so.2 (0x4113b000)
        libavutil.so.52 => /volume1/@appstore/Serviio/bin/../lib/libavutil.so.52 (0x4118c000)
        libx264.so.133 => /volume1/@appstore/Serviio/bin/../lib/libx264.so.133 (0x411f3000)
        libm.so.6 => /lib/libm.so.6 (0x41346000)
        libpthread.so.0 => /lib/libpthread.so.0 (0x413f5000)
        libc.so.6 => /lib/libc.so.6 (0x41415000)
        librt.so.1 => /lib/librt.so.1 (0x41544000)
        libass.so.4 => /volume1/@appstore/Serviio/bin/../lib/libass.so.4 (0x41553000)
        librtmp.so.0 => /volume1/@appstore/Serviio/bin/../lib/librtmp.so.0 (0x41585000)
        libz.so.1 => /lib/libz.so.1 (0x415a5000)
        libshine.so.3 => /volume1/@appstore/Serviio/bin/../lib/libshine.so.3 (0x415c2000)
        libfdk-aac.so.0 => /volume1/@appstore/Serviio/bin/../lib/libfdk-aac.so.0 (0x415d4000)
        /lib/ld-linux.so.3 (0x40000000)
        libfreetype.so.6 => /lib/libfreetype.so.6 (0x41678000)
        libfribidi.so.0 => /volume1/@appstore/Serviio/bin/../lib/libfribidi.so.0 (0x41737000)
        libfontconfig.so.1 => /volume1/@appstore/Serviio/bin/../lib/libfontconfig.so.1 (0x41756000)
        libssl.so.1.0.0 => /lib/libssl.so.1.0.0 (0x4178d000)
        libcrypto.so.1.0.0 => /lib/libcrypto.so.1.0.0 (0x417db000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x4196f000)
        libexpat.so.1 => /lib/libexpat.so.1 (0x41983000)
        libdl.so.2 => /lib/libdl.so.2 (0x419aa000)
/$
About these ads

27 thoughts on “Cross-compiling FFmpeg for Serviio with shared libraries on Synology NAS (Intel, ARMv5, ARMv7, and QorIQ CPUs)

  1. michael

    keep up the great work on serviio, i hope you get something going for the PPC cpu for synology soon. are synology assiting you? i hope they are!

    Reply
  2. Steven

    Hi, I’d like to setup some kind of automatic (via cron job) reencoding of dreambox .ts-files (dvb-c) for later watching on the iPad. On OSX I use the following command “ffmpeg -i input.ts -vcodec libx264 -vprofile high -preset faster -b:v 2000k -vf scale=-1:720 -maxrate 10M -bufsize 10M -threads 0 -acodec libvo_aacenc -ab 196k output.mp4″ which gives good results.

    I have an DS412+ with Atom. I know it will take maybe days for one movie to reencode, but I would not care, if it would run in background.

    Do you think that is possible on DS412+? Unfortunately I don’t have the skills for x-compiling something and setting the right compiler flags, etc. – I tried, but I now know my limits :)

    Could you upload a compiled current version of ffmpeg with all the codecs (especially X264) the osx version of the ffmpeg.org site has?

    This would be GREAT !!! :)

    Reply
  3. EJ

    Great, this worked for me. I built under xubuntu 12.10 and built for the DS211j. I can successfully transcode my FLAC collection to mp3 to take on the go with my android.

    Reply
  4. MoBO

    Hello, I don’t have any Linux experience but I need tom compile ffmpeg to support video streaming on my Intel Synology NAS.
    I followed this note under a Ubuntu 12 VM (using Oracle VM).
    The process seems to work correctly but I don’t have any ffmpeg file created.

    Is there something missing to compile it ?

    I’m sorry, this might seems stupid for Linux geek… ;o(

    Reply
    1. MoBO

      Everything seem just fine ’til the end…
      (I run it with sudo then as root)…

      root@ubuntu:~/Downloads/DSM-source/ffmpeg# export CFLAGS=”-I${TOOLCHAIN}/include”
      root@ubuntu:~/Downloads/DSM-source/ffmpeg# make
      Makefile:2: config.mak: No such file or directory
      Makefile:47: /common.mak: No such file or directory
      Makefile:89: /libavutil/Makefile: No such file or directory
      Makefile:89: /library.mak: No such file or directory
      Makefile:169: /doc/Makefile: No such file or directory
      Makefile:170: /tests/Makefile: No such file or directory
      make: *** No rule to make target `/tests/Makefile’. Stop.
      root@ubuntu:~/Downloads/DSM-source/ffmpeg# make install
      Makefile:2: config.mak: No such file or directory
      Makefile:47: /common.mak: No such file or directory
      Makefile:89: /libavutil/Makefile: No such file or directory
      Makefile:89: /library.mak: No such file or directory
      Makefile:169: /doc/Makefile: No such file or directory
      Makefile:170: /tests/Makefile: No such file or directory
      make: *** No rule to make target `/tests/Makefile’. Stop.
      root@ubuntu:~/Downloads/DSM-source/ffmpeg#

      Any way to fix that or find how to ?

      Thanks in advance for your help.

      Reply
  5. MoBO

    I tried many times, many different ways but I’ve been unable to compile an INTEL version.
    I created a VM (VirtualBOX) with Ubuntu 12.10, 10.04 (64bits AND 32bits) and never been able to pass the librtmp & ffmpeg compilation.

    I searched on Internet and already spend to much hours ;o(
    If anyone could share an “how to”, this will be just fantastic !
    This way anyone could compile…

    If not, do anybody will be nice enough to share an INTEL version ?
    PS It will be used for Subsonic and video support ;o)

    It’s Christmas after all !!!

    Reply
  6. Pingback: Serviio 1.1 package for Synology NAS « PC LOAD LETTER

  7. Hanz

    What I like about all this Serviio and Synology business is WHAT DOES IT ALL MEAN????

    I have a Synology NAS, I have a Samsung Smart TV – I want the F**ker to play Xvid, .MKV – I heard Serviio would help me achieve this. But I’ll be f**ked if I can follow your instructions / find the links to where the files reside.

    I admit I might be a bit dyslexic and have the attention of a gnat, but two hours in I haven’t a f**king clue why I can’t get things working. I need you to provide pictures, step by step instruction, links to files, instructions on where to save them, instruction of which ones to download first and install first, if I need to extract them, where to extract them, how to get the Synology NAS to act upon the information. No abriviation, no block paragraph’s. Even a youtube video would be helpful.

    Or if you think I need to direct my frustrations at Synology please let me know.

    Reply
    1. patters Post author

      I’m afraid I don’t have time to record YouTube videos for you. The intended audience for my posts is a reasonably technical one. If you are only interested in running Serviio, this particular post is not for you – it’s intended to show other technically-minded people how I compiled FFmpeg so as to help other aspiring Linux hobbyists. For running Serviio on Synology you want this post:
      http://pcloadletter.co.uk/2012/01/25/serviio-syno-package/

      Reply
  8. Piotr

    Hello Patters,
    there is a missed characted ‘\’ in Native compile for ARM systems line 60. correct line is:
    sed -i “s|include |include \n# define PAGE_SIZE sysconf(_SC_PAGESIZE)|” lib/common.h

    Reply
    1. patters Post author

      Thanks, post corrected. It’s entirely possible there are some more errors in there. When I last updated it I had an issue in the WordPress editor and had to revert to a draft, whereupon WordPress helpfully mangled the syntax of the whole thing by HTML encoding the entire post. It made a real mess, and the only way back was the run the post back through a free online HTML decoder – but I guess it wasn’t perfect.

      Reply
  9. shadock

    @patters: is it possible for you to add libx264 support ?

    (including on your serviio package since I do use it on my NAS) ?

    Reply
    1. shadock

      Juste a small note, I would like to use the following recommended transcode command for Apple (HFS) : “ffmpeg -ss %o -t %d -i %s -async 1 -b %bk -s %wx%h -ar 44100 -ac 2 -v 0 -f mpegts -vcodec libx264 -preset superfast -acodec libmp3lame -threads 0 -“

      Reply
    1. coolraoul

      Oups, sorry didn’t noticed at first sight that you were cross compiling

      Please ignore my comment

      Reply
    2. patters Post author

      I didn’t – all the stuff I have made has been by using the cross-compiling toolchain in a Linux VM on my MacBook.

      Reply
  10. Forgetful Orange (@ForgotMyOrange)

    FYI much appreciate this.
    I might be able to do without it, but I couldn’t get this sed command working under #—–fetch libass source

    dsm@/volume1/downloads/libass-0.10.1> sed -i “s|^sys_lib_search_path_spec=”/opt/lib/gcc/arm-none-linux-gnueabi/4.2.3 /opt/a
    rm-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
    sed: unmatched ‘|’

    Reply
  11. JoergGaBo

    Hi,
    thanks a lot for this one… I think it might be quite helpful even for other compiling projects. Currently I try to cross-compile ReadyMedia (aka miniDLNA) for the Synology DiskStation DS213+ under DS4.3. However I can’t seem to get it working right. I managed once to compile the minidlnad deamon, starting it on the diskstation returned in some dump.

    Might somebody be interested in helping out with the ReadyMedia compilation?

    thanks & cu
    jgb

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s