因为工作的关系和自己的兴趣原因,我尝试了自己从ubuntu 14.04 交叉编译ffmpeg。
我交叉编译ffmpeg的方法,完全是摸索得到的。在这之前,我从来没有试过交叉编译。
在从ubuntu成功交叉编译之前,我多次尝试了在MingW、cygwin编译ffmpeg,无一例外全部失败。
这次的成功完全是巧合,因为换个电脑我不确定我会不会还是成功。虽然如此我依然要把这次经理写下来。
首先,我在https://github.com/rdp/ffmpeg-windows-build-helpers获得一个交叉编译的脚本。
这个连接从http://trac.ffmpeg.org/wiki/CompilationGuide/CrossCompilingForWindows获得。
下载它,在/home/username/目录下解压它,然后,
cd ffmpeg-windows-build-helpers-master chmod 777 cross_compile_ffmpeg.sh ./cross_compile_ffmpeg.sh
得到一个这样的界面:
2016年 01月 03日 星期日 23:16:00 CST ##################### Welcome ###################### Welcome to the ffmpeg cross-compile builder-helper script. Downloads and builds will be installed to directories within /home/ldxn/tmp/sandbox If this is not ok, then exit now, and cd to the directory where you‘d like them installed, then run this script again from there. NB that once you build your compilers, you can no longer rename/move the sandbox directory, since it will have some hard coded paths in there. You can, of course, rebuild ffmpeg from within it, etc. Is /home/ldxn/tmp/sandbox ok (requires ~ 5GB space) [Y/n]?
直接回车,使用默认的Y选项。
using default y Would you like to include non-free (non GPL compatible) libraries, like many high quality aac encoders [libfdk_aac] The resultant binary may not be distributable, but can be useful for in-house use. Include these non-free-license libraries [y/N]?
直接回车,使用默认的N选项。
using default n What version of MinGW-w64 would you like to build or update? 1. Both Win32 and Win64 2. Win32 (32-bit only) 3. Win64 (64-bit only) 4. Exit Input your choice [1-4]: 2
问你要编译32位还是64位,还是32和64位,我使用2,怕有些电脑不支持64。虽然我的电脑是64的。键入2,回车。
Input your choice [1-4]: 2 starting to download and build cross compile version of gcc [requires working internet access] with thread count 8... building win32 cross compiler % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 77026 100 77026 0 0 9480 0 0:00:08 0:00:08 --:--:-- 19275 [1/49]: Downloading config.guess... done [2/49]: Downloading mingw-w64-4.0.4.tar.bz2...
运气好的话,这个时候就已经开始下载了。运气差的话,连不上网,以上步骤重新走一次就可以了。
理论上,网络畅通,操作系统环境没问题,当这个脚本运行结束的时候,也就是你获得一个ffmpeg的时候了。
但程序员的日常是绝对不会如此一帆风顺,一波九折绝对不是夸张。
写这篇文章的时候,我已经完成了编译。我没有写博客的习惯,所以我没有在编译的过程中随时记录当时的状态。
现在我仅仅靠记忆,来记录一些我碰到的问题。
1.找不到libpthread
make的时候找不到libpthread,这是下不了这个包,所以没编译。网上找到这个包的地址,在sandbox/cross_compilers/mingw-w64-build-3.6.7.local中替换原来的地址,第二个解决办法是如果是网络超时无法下载,就可以先把地址提取出来,去下好,放在正确的位置,修改mingw-w64-build-3.6.7.local的脚本,然后编译完成后再改回来,我忘了我是使用哪种方法了。
在我的mingw-w64-build-3.6.7.local版本中,搜索build_pthreads_w32,会转到一个函数,如下:
build_pthreads_w32 () { if [[ -z "$pthreads_w32_ver" ]]; then pthreads_w32_ver=‘cvs‘ fi local target prefix target="$1" prefix="$2" shift 2 cd "$pkgs_dir" || print_error create_pkg_dirs ‘pthread-w32‘ || print_error if [[ "$pthreads_w32_ver" = "$pthreads_w32_release_ver" ]]; then download_extract "ftp://sourceware.org/pub/pthreads-win32/pthreads-w32-$pthreads_w32_release_ver-release.tar.gz" if [[ ! -d "pthreads-w32-$pthreads_w32_release_ver" ]]; then mv "pthreads-w32-$pthreads_w32_release_ver-release" "pthreads-w32-$pthreads_w32_release_ver" || print_error fi else unset oldmd5 newmd5 if cd ‘pthreads-w32-cvs‘ 2>/dev/null; then build_progress ‘pthreads-w32 cvs‘ ‘Updating‘ cvs update > >(build_log) 2>&1 || print_error build_progress ‘done‘ cd ‘..‘ else build_progress ‘pthreads-w32 cvs‘ ‘Downloading‘ cvs -d :pserver:[email protected]:/cvs/pthreads-win32 checkout pthreads > >(build_log) 2>&1 || print_error build_progress ‘done‘ mv ‘pthreads‘ ‘pthreads-w32-cvs‘ fi fi cd "pthreads-w32-$pthreads_w32_ver" || print_error make realclean > >(build_log) 2>&1 || print_error if [[ "${static_build[@]}" != *"disable-shared"* ]]; then build_progress ‘pthreads-w32 shared‘ ‘Building‘ make CROSS="$target-" realclean GC ARCH="$pthread_arch" > >(build_log) 2>&1 || print_error build_progress ‘done‘ cp ‘pthreadGC2.dll‘ "$prefix/lib/" || print_error cd "$prefix/lib" || print_error ln -s "./pthreadGC2.dll" "./libpthread.dll" cd "$pkgs_dir/pthread-w32/source/pthreads-w32-$pthreads_w32_ver" || print_error fi build_progress ‘pthreads-w32 static‘ ‘Building‘ make CROSS="$target-" realclean GC-static ARCH="$pthread_arch" > >(build_log) 2>&1 || print_error build_progress ‘done‘ cp ‘libpthreadGC2.a‘ "$prefix/lib/" || print_error cp ‘pthread.h‘ ‘sched.h‘ ‘semaphore.h‘ "$prefix/include/" || print_error cd "$prefix/lib" || print_error ln -s "./libpthreadGC2.a" "./libpthread.a" cd ‘../include‘ || print_error for file in ‘pthread.h‘ ‘sched.h‘ ‘semaphore.h‘; do if ! ed -s "$prefix/include/$file" <<< $‘,s/ __declspec (dllexport)//g\n,s/ __declspec (dllimport)//g\nw\nq‘ > >(build_log) 2>&1; then mv "$file" "$file".orig sed ‘s/ __declspec (dllexport)//g;s/ __declspec (dllimport)//g‘ "$file".orig > "$file" rm -f "$file".orig fi done }
download_extract "ftp://sourceware.org/pub/pthreads-win32/pthreads-w32-$pthreads_w32_release_ver-release.tar.gz"就是它的地址了
你想办法弄到一个这样的有效的地址贴在那里就可以通过了。
你还需要在sandbox/mingw-w64-i686文件夹中删除compiler.done文件,这是cross_compile_ffmpeg.sh赖以判断mingw是否正确安装的文件。
删了之后,注释以下代码:
rm -f $zeranoe_script_name || exit 1 curl -4 https://raw.githubusercontent.com/rdp/ffmpeg-windows-build-helpers/master/patches/$zeranoe_script_name -O || exit 1
因为mingw-w64-build-3.6.7.local是被下载的,重新安装mingw是会删掉原来的配置,而如果删掉了你的修改也就没了。。。
注释掉后的cross_compile_ffmpeg.sh install_cross_compiler 函数如下:
install_cross_compiler() { if [[ -f "mingw-w64-i686/compiler.done" && -f "mingw-w64-x86_64/compiler.done" ]]; then echo "MinGW-w64 compilers already installed, not re-installing..." return # early exit just assume they want both, don‘t even prompt :) fi if [[ -z $compiler_flavors ]]; then pick_compiler_flavors fi if [[ $compiler_flavors == "win32" && -f "mingw-w64-i686/compiler.done" ]]; then echo "win32 cross compiler already installed, not reinstalling" return fi if [[ $compiler_flavors == "win64" && -f "mingw-w64-x86_64/compiler.done" ]]; then echo "win64 cross compiler already installed, not reinstalling" return fi # if they get this far, they want a compiler that‘s not installed, I think...fire away! XXXX if 32 bit compiler installed, and request both, rebuilds 32... local zeranoe_script_name=mingw-w64-build-3.6.7.local #rm -f $zeranoe_script_name || exit 1 #curl -4 https://raw.githubusercontent.com/rdp/ffmpeg-windows-build-helpers/master/patches/$zeranoe_script_name -O || exit 1 chmod u+x $zeranoe_script_name unset CFLAGS # don‘t want these for the compiler itself since it creates executables to run on the local box (we have a parameter allowing them to set them for the script "all builds" basically) # pthreads version to avoid having to use cvs for it echo "starting to download and build cross compile version of gcc [requires working internet access] with thread count $gcc_cpu_count..." echo "" # --disable-shared allows c++ to be distributed at all...which seemed necessary for some random dependency... nice ./$zeranoe_script_name --clean-build --disable-shared --default-configure --pthreads-w32-ver=2-9-1 --cpu-count=$gcc_cpu_count --build-type=$compiler_flavors --gcc-ver=5.3.0 || exit 1 export CFLAGS=$original_cflags # reset it if [[ ! -f mingw-w64-i686/bin/i686-w64-mingw32-gcc && ! -f mingw-w64-x86_64/bin/x86_64-w64-mingw32-gcc ]]; then echo "no gcc cross compiler(s) seem built [?] (build failure [?]) recommend nuke sandbox dir (rm -rf sandbox) and try again!" exit 1 fi if [ -d mingw-w64-x86_64 ]; then touch mingw-w64-x86_64/compiler.done fi if [ -d mingw-w64-i686 ]; then touch mingw-w64-i686/compiler.done fi rm -f build.log clear echo "Ok, done building MinGW-w64 cross-compiler(s) successfully..." }
2.在安装libsndfile-1.0.25的时候卡住
因为GFW的存在,和跨太平洋的网络通信,很多时候有些软件是下不下来的,不是被qiang就是下载速度不给力,
这个包无法安装在我觉得应该是第一个原因。
我在163的镜像站找到了它的源码下载地址,把163的镜像地址替换上去,替换后如下:
build_libsndfile() { # generic_download_and_install http://www.mega-nerd.com/libsndfile/files/libsndfile-1.0.25.tar.gz libsndfile-1.0.25 generic_download_and_install http://mirrors.163.com/ubuntu/pool/main/libs/libsndfile/libsndfile_1.0.25.orig.tar.gz libsndfile-1.0.25 }
把第一个的地址注释,改为163的地址,瞬间解决了问题。其他的下不下来也可以这样解决,主要版本号相差不大应该都是可以的。
无法安装gnutls-3.3.19,也可以这样解决。或者重头开始,多调用几次cross_compile_ffmpeg.sh,也可以解决。
downloading ftp://ftp.gnutls.org/gcrypt/gnutls/v3.3/gnutls-3.3.19.tar.xz % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- 0:00:27 --:--:-- 0curl: (7) Failed to connect to ftp.gnutls.org port 21: 拒绝连接
3.因为网络不给力,祭出大招
像无法安装gnutls-3.3.19的问题,不断地./cross_compile_ffmpeg.sh,然后输入n,输入2,我受够了。所以我学了下bash,写下了如此脚本,死循环!!!
#!/bin/bash while true do ./cross_compile_ffmpeg.sh wait done
新建文本,重命名为tmp.sh,把以上代码贴上去,放在和cross_compile_ffmpeg.sh同一目录:
chmod 777 tmp.sh./tmp.sh
然后要修改一下cross_compile_ffmpeg.sh,因为每次执行cross_compile_ffmpeg.sh都需要n或者2,以做一些设定,把
修改它的目的就把这些设定内置了。修改之后的cross_compile_ffmpeg.sh如下:
intro() { cat <<EOL ##################### Welcome ###################### Welcome to the ffmpeg cross-compile builder-helper script. Downloads and builds will be installed to directories within $cur_dir If this is not ok, then exit now, and cd to the directory where you‘d like them installed, then run this script again from there. NB that once you build your compilers, you can no longer rename/move the sandbox directory, since it will have some hard coded paths in there. You can, of course, rebuild ffmpeg from within it, etc. EOL if [[ $sandbox_ok != ‘y‘ && ! -d sandbox ]]; then yes_no_sel "Is $PWD/sandbox ok (requires ~ 5GB space) [Y/n]?" "y" if [[ "$user_input" = "n" ]]; then exit 1 fi fi mkdir -p "$cur_dir" cd "$cur_dir" if [[ $disable_nonfree = "y" ]]; then non_free="n" else if [[ $disable_nonfree = "n" ]]; then non_free="y" else # yes_no_sel "Would you like to include non-free (non GPL compatible) libraries, like many high quality aac encoders [libfdk_aac] #The resultant binary may not be distributable, but can be useful for in-house use. Include these non-free-license libraries [y/N]?" "n" non_free="n" #$user_input" # save it away fi fi }
把non_free的值设为默认n
第二处:
What version of MinGW-w64 would you like to build or update? 1. Both Win32 and Win64 2. Win32 (32-bit only) 3. Win64 (64-bit only) 4. Exit Input your choice [1-4]:
把它的预设值改为2,修改后的代码如下:
pick_compiler_flavors() { compiler_flavors=win32 # while [[ "$compiler_flavors" != [1-4] ]]; do # if [[ -n "${unknown_opts[@]}" ]]; then # echo -n ‘Unknown option(s)‘ # for unknown_opt in "${unknown_opts[@]}"; do # echo -n " ‘$unknown_opt‘" # done # echo ‘, ignored.‘; echo # fi # cat <<‘EOF‘ #What version of MinGW-w64 would you like to build or update? # 1. Both Win32 and Win64 # 2. Win32 (32-bit only) # 3. Win64 (64-bit only) # 4. Exit #EOF # echo -n ‘Input your choice [1-4]: ‘ # read compiler_flavors # done # case "$compiler_flavors" in # 1 ) compiler_flavors=multi ;; # 2 ) compiler_flavors=win32 ;; # 3 ) compiler_flavors=win64 ;; # 4 ) echo "exiting"; exit 0 ;; # * ) clear; echo ‘Your choice was not valid, please try again.‘; echo ;; # esac }
这样,调用tmp.sh之后,cross_compile_ffmpeg.sh就不断地重复调用,直到编译完成为止也不会停止,bash的高手请告诉我怎么让它在编译完成后停下来。。。
当然,如果你碰上了无法下载包的问题。tmp.sh并不能帮你完成这个。所以你还是需要是不是地看看,是不是在哪里卡了很久了,如果是,你就应该按下ctrl+c,和改下地址了。
4.不断地重复检查新版本
像安装x265 的时候,这个脚本需要x265的最新版本。所以在build_libx265函数中,它会不断地查询x265的最新版本。
但我在边下载边编译ffmpeg的过程中,可能会中断无数次,而build_libx265这个函数检查x265的最新版本非常消耗时间。
所以我,就,注释掉它。你也可以这样做。
总结:
1.我是幸运的,我没有碰到其他奇形怪状我无法解决的问题。
2.因为完成ffmpeg的交叉编译有几天了,我不知道是否遗漏了哪些必要的东西没有记录。所以如果大家看到我的随笔后无法解决问题,可以在回复里联系我,虽然我不一定能够及时看得到。。。
题外:
我现在在尝试交叉编译vlc,编不过去,搞了很久了,都没用。
by:戴华豪