wiki:CompilationGuide/RaspberryPi

Introduction

If you are familiar with a cool little thing named Raspberry Pi (a credit-card-sized single-board computer, shortly called RPi) and you need to compile your FFmpeg source code to be able to run it on Raspbian (a Debian Linux-based operating system optimized for the Raspberry Pi hardware), then this tutorial might help you.

Be aware, though, that Raspberry Pi does not have a very powerful hardware (it has a Broadcom System On a Chip (SoC), which includes 700 MHz ARM processor, with possible overclocking up-to 1 GHz, VideoCore IV GPU and usually is shipped with 256/512 MB of RAM memory), so you probably won't be able to run any kind of encoder on it, but you can use it as a very cheap 1080 media player.

Compiling directly on RPi (running on Raspbian) is possible and some people do it that way, but since its hardware is very limited, this is not recommended for anything as big as FFmpeg (it took me 9 hours to compile the basic FFmpeg this way, without any additional libraries). Fortunately, there are other ways to compile things for RPi. One of them is emulating Raspberry Pi on your machine using QEMU (emulator). Another way (described in this document) is cross-compilation, which means that you compile everything on your desktop machine, using your own operating system, producing binaries for the Raspbian.

(TODO: The comparison table of different ways to compile FFmpeg for Raspbian)

Cross-compiling FFmpeg for Raspbian

We will describe here the method to cross-compile FFmpeg for Raspbian. First, we will prepare our build environment. Then we will show how to compile common additional libraries that FFmpeg might use (for example libx264). And finally we'll show how to compile the latest (and greatest) version of FFmpeg that will run on Raspbian.

Preparing the environment

To successfully cross-compile things, we need something called a Toolchain (a set of programming tools that are used to create another computer program). We need a toolchain that will be able to produce binaries, specific to the ARM architecture and the Raspbian itself. Now, there are a lot of already created toolchains for Raspbian and if you like to speed up things, you could just go find one of them and install it, but be aware that whatever toolchain you download, it might not be optimized for both your own operating system and Raspbian. If you compile your own toolchain, you can be sure that you'll be able to use all the available optimizations that your operating system and your Raspbian support.

The crosstool-ng is a tool used to create a custom toolchain. We'll use it to create our own toolchain which we can then use to compile anything we want for the Raspbian. So, let's prepare everything to first build our toolchain.

Building the crosstool-ng

The following section is mostly inspired by How to build a cross compiler for your Raspberry Pi.

First, download crosstool-ng, extract the archive and compile the source code. We recommend you to use something like this:

./configure --prefix=/opt/cross
make
sudo make install
export PATH=$PATH:/opt/cross/bin

which will install all the crosstool-ng needed files into the "/opt/cross" directory and add it to the current PATH environment variable.

If something goes wrong, check your "build.log" file to get a clue on what went wrong. I've had some trouble because of some missing system packages, which I installed using:

apt-get install texinfo pkg-config

Although, the error complained about "makeinfo", it appears that, in Debian, this package is named "texinfo". Also consider installing texi2html package.

Building the toolchain

Now that we built crosstool-ng, we can build our RPi toolchain.

First, create a directory that crosstool-ng will use as a staging ground. This directory will contain your toolchain configuration, downloaded files and intermediary build results. This is not where your final toolchain will end up and it does take up quite a lot of space (for example /home/user/ctng). Go into that directory and run "ct-ng menuconfig":

mkdir /home/user/ctng
cd /home/user/ctng
ct-ng menuconfig

The menu should show up and you should set up things as instructed by the following walkthrough (checkboxes are selected using the SPACEBAR key and text fields can be edited pressing the ENTER/RETURN key on your keyboard, once you select it with your cursor keys):

  • Paths and misc options
    • (Important) Enable "Try features marked as EXPERIMENTAL"
    • (Optional) Change "Prefix directory" (for example, you can put "/opt/cross/x-tools/${CT_TARGET}" there)
  • Target options
    • (Important) Change "Target architecture" to "arm"
    • (Important) Leave "Endianness" set to "Little endian"
    • (Important) Leave "Bitness" set to "32-bit"
  • Toolchain options
    • (Nothing to do here, the defaults are fine)
  • Operating system
    • (Important) Change "Target OS" to "linux"
  • Binary utilities
    • (Optional) Change "binutils version" to "2.21.1a" or whichever is the latest that isn't marked as experimental
  • C compiler
    • (Optional) Enable "Show Linaro versions (EXPERIMENTAL)". In the "gcc version" field, choose the "linaro-4.6-2012.04 (EXPERIMENTAL) compiler". You're free to choose a different one but this one works well. We do recommend the Linaro versions over the vanilla ones for the RPi
    • (Optional) Enable "C++" under the group "*** Additional supported languages: ***" if you need g++ tool also built for your RPi toolchain

Now, exit the configuration tool, save your changes and run:

ct-ng build

This will take some time and when it finishes, you should have an ARM compiler, in the "Prefix directory" that you chose above - "/opt/cross/x-tools/${CT_TARGET}", ready to build anything for your RPi. One final step is to add that directory to your PATH:

export PATH=$PATH:/opt/cross/x-tools/arm-unknown-linux-gnueabi/bin

It also might help to export one more important environment variable CCPREFIX:

export CCPREFIX="/opt/cross/x-tools/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-"

Quick test of the toolchain

Let's make a quick sanity check of our ARM compiler:

$ arm-unknown-linux-gnueabi-gcc --version
arm-unknown-linux-gnueabi-gcc (crosstool-NG 1.15.2) 4.6.4 20120402 (prerelease)
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ cat > test.c
#include <stdio.h>
int main() { printf("Hello, world!\n"); return 0; }
^D

$ arm-unknown-linux-gnueabi-gcc -o test test.c

Copy the "test" binary to your RPi and run it. It should display a familiar "Hello, world!" text.

Compiling additional libraries needed for FFmpeg

This section will describe how to compile some common libraries that are usually used by FFmpeg, like libx264 or libaacplus, etc.

Compiling libaacplus

cd /my/path/where/i/keep/my/source/code
wget http://217.20.164.161/~tipok/aacplus/libaacplus-2.0.2.tar.gz
tar -xzf libaacplus-2.0.2.tar.gz
cd libaacplus-2.0.2
./autogen.sh --with-parameter-expansion-string-replace-capable-shell=/bin/bash --host=arm-unknown-linux-gnueabi --enable-static --prefix=/my/path/were/i/keep/built/arm/stuff
make
make install

After you finish, all the libraries and binaries will be installed in "/my/path/were/i/keep/built/arm/stuff", so if you are compiling some libraries as dependencies for other things, you will most probably reference this directory later using:

cd /my/path/where/i/keep/my/source/code
cd my_other_library
CFLAGS="-I/my/path/were/i/keep/built/arm/stuff/include" LDFLAGS="-L/my/path/were/i/keep/built/arm/stuff/libs" ./configure ... --prefix=...
make
make install

That way you are telling the compiler where are the dependencies, that you also compiled for RPi, located, in order to successfully compile that "other library" too.

Compiling libx264

cd /my/path/where/i/keep/my/source/code
git clone git://git.videolan.org/x264
cd x264
./configure --host=arm-unknown-linux-gnueabi --enable-static --cross-prefix=${CCPREFIX} --prefix=/my/path/were/i/keep/built/arm/stuff --extra-cflags='-march=armv6' --extra-ldflags='-march=armv6'
make
make install

Note that we use CCPREFIX environment variable here, to specify the prefix of all the tools in a toolchain, to be used for this build (it instructs the shell not to call cc, gcc, g++ and other standard tools, but rather to call /opt/cross/x-tools/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-cc, /opt/cross/x-tools/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-gcc, /opt/cross/x-tools/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-g++, etc that will build ARM binaries and libraries).

Compiling ALSA library

cd /my/path/where/i/keep/my/source/code
wget http://mirrors.zerg.biz/alsa/lib/alsa-lib-1.0.25.tar.bz2
tar xjf alsa-lib-1.0.25.tar.bz2
cd alsa-lib-1.0.25/
./configure --host=arm-unknown-linux-gnueabi --prefix=/my/path/were/i/keep/built/arm/stuff
make
make install

Compiling FFmpeg

This part is the same for all the subsequent examples:

cd /my/path/where/i/keep/my/source/code
git clone git://source.ffmpeg.org/ffmpeg.git
cd ffmpeg

Basic FFmpeg, without additional libraries

./configure --enable-cross-compile --cross-prefix=${CCPREFIX} --arch=armel --target-os=linux --prefix=/my/path/were/i/keep/built/arm/stuff
make
make install

FFmpeg with libaacplus, libx264 and alsa-lib

./configure --enable-cross-compile --cross-prefix=${CCPREFIX} --arch=armel --target-os=linux --prefix=/my/path/were/i/keep/built/arm/stuff --enable-gpl --enable-libx264 --enable-nonfree --enable-libaacplus --extra-cflags="-I/my/path/were/i/keep/built/arm/stuff/include" --extra-ldflags="-L/my/path/were/i/keep/built/arm/stuff/lib" --extra-libs=-ldl
make
make install

Also, if some libraries are dependent on pkg-config, you'll most probably be able to solve it using PKG_CONFIG_PATH environment variable, like this:

pkg_config=$(which pkg-config) PKG_CONFIG_PATH=/my/path/were/i/keep/built/arm/stuff/lib/pkgconfig ./configure ...

more

Conclusion

After you've built your FFmpeg for RPi, copy ffmpeg, ffplay and ffserver binaries from "/my/path/were/i/keep/built/arm/stuff/bin/" to your Raspberry Pi and try it to see how it works :)

One important note, that might save you days of headaches is that RPi is a very optimized hardware, which consumes very little power and also provides very little power to its USB ports, so if you plan to attach any external USB disks, cameras, wireless/audio/etc USB dongles, then keep in mind to connect all of these USB peripherals through a self-powered USB hub, which can provide enough power for devices to work properly, so your RPi won't be rebooting itself, due to sudden dramatic voltage fluctuations.

Good luck with all that.

Last modified 8 years ago Last modified on Aug 11, 2016, 4:24:14 PM

Attachments (1)

Download all attachments as: .zip

Note: See TracWiki for help on using the wiki.