MinGWはMinimalist GNU for Windowsの略で、Linux等で利用されているフリーのコンパイラ、gccを使ってWindowsアプリケーションをビルドできる環境をつくることができます。 MinGWを使って、動画・音声の変換ソフトとして名高いffmpeg、MPEG-4動画の作成ソフト、x264をビルドしてみます。 基本的な方向性はこんな感じで。
ちなみに、MinGW環境だとプロセスの生成やファイルのI/Oがかなり遅いようで、特にconfigureが涙が出るほど遅いです。
できあがるバイナリは別に遅くないのですが、ビルドにはものすご〜く時間がかかるので試す人は覚悟しておきましょう(笑)
各種ライブラリのビルドで試行錯誤している時には何度も心が折れそうになりました…。
Windows上でやってる話ですが、やってることはLinuxでのそれと同じ感覚なので、このメモもLinuxのとこに置いてみるw
というか、Linuxでクロスビルドした方が早かったんじゃ?
等と書いていましたが、まあビルドするときだけの話だし、当時はともかく今のスペックだとそこまで遅いとも感じませんね。 最初のMinGW環境の構築も、今ならMSYS2をインストールすれば、パッケージマネージャーpacmanでgccやgitの追加、インストール済パッケージのアップデートもコマンド一発で済みます。
自分も、今はMSYS2に移行してますが、ffmpegやx264, x265本体、またlameやfdk-aac,xvidcore等のi686/x86_64のライブラリは自前でビルドしてます。 gitでリモートブランチをひっぱって、適当な自分設定をしてビルド、インストールまでをスクリプト化しちゃってるので、すっかり楽ちん♪
なんとなく一部のライブラリを入れ替えてライセンスをGPLにしたffmpeg, x264のバイナリを置いてみる。 一応、Windows Defederでチェック済。 MSYS2のgcc-6.3.0でビルドしたものだけど、最適化フラグとかの関係でHaswell以降のCPUじゃないと動かないかも。
MinGW環境を作るには、公式のMinGW及びMSYSのインストーラを使う方法が一般的ですが、できるだけ新しいgccを使ってビルドしたいし、いろいろツールを探したり、32bitと64bitを両方ビルドできる環境を作るのはかなり面倒そうなので、xhmikosrさんのところから丸ごといただくことにしましたw
toolsフォルダにあるMSYS_MinGW_GCC_452_x86-x64_Full.7zをダウンロードし、適当なフォルダに展開します。
以降、D:\bin\msys
に展開したとします。
解凍したMSYSフォルダにある msys.batをダブルクリックし、MinGWのプロンプトを立ち上げます。 以降、MinGWを起動するには msys.bat を実行する必要があるので、デスクトップにでもショートカットを作っておくと楽です。 ちなみにインストーラを使ってませんし、D:\bin\msys 以下をコピーすれば他のパソコンに環境を丸ごと持っていけるようになってます。
まずは、後々configureする時のために、pkg-config.exe等をコピーしておきます。
$ cd /bin $ cp -af pkg-config.exe x86_64-w64-mingw32-pkg-config.exe $ cd /mingw/bin $ cp -af ar.exe i686-pc-mingw32-ar.exe $ cp -af as.exe i686-pc-mingw32-as.exe
色々なソフトの開発中の最新のリポジトリからソースを入手するためには、cvsやsvn、git等が必要になることがありますが、xhmikosrさんのパッケージにはgitが入ってません。 なので、msysgitからダウンロードしてインストールします。
私は執筆時点の最新版、PortableGit-1.7.4-preview20110204.7z を落として、MinGWと同じ D:\bin\msys 以下に解凍しました。 etcやbinの一部のファイルがxhmikosrのツリーと重複しますが、カブったファイルはすべて無視、つまりxhmikosrさん側優先で大丈夫なようです(多分w)。 sharedビルドのため、同じライブラリのバージョン違いのdllが複数入ってしまいますが、これは仕方ないところですね。
今回のお題目のffmpeg、x264のソースが必要になります。 リリース版ではなく最新のリビジョンを試したかったので、MinGWのプロンプトから以下のコマンドでそれぞれ入手しました。 ちなみにffmpegのソースはffmpeg-mtを試しています。
$ git clone git://git.videolan.org/x264.git x264 $ git clone git://git.gitorious.org/~astrange/ffmpeg/ffmpeg-mt.git ffmpeg-mt $ svn checkout http://ffmpegsource.googlecode.com/svn/trunk/ ffms2
さっそく本題のビルドにいきたいところだけど、その前にまずx264が利用するgpacをインストールしておきます。 どうも公式のソースはちょっと問題があったりするらしいので、golgol7777さんのソースを使わせてもらいました。
$ git clone git://github.com/golgol7777/gpac.git gpac 【gpac 32bit版】 $ cd gpac $ ./configure --prefix=/mingw/i686-pc-mingw32 --strip --static-mp4box $ make lib apps $ make install-lib $ cp -f ./bin/gcc/MP4Box.exe /mingw/i686-pc-mingw32/bin 【gpac 64bit版】 $ make clean $ ./configure --prefix=/mingw/x86_64-w64-mingw32 --host=x86_64-w64-mingw32 \ --cross-prefix=x86_64-w64-mingw32- --cpu=x86_64 --target-os=mingw32 --strip --static-mp4box $ make lib apps $ make install-lib $ cp -f ./bin/gcc/MP4Box.exe /mingw/x86_64-w64-mingw32/bin
外部ライブラリをできるだけ入れるようにすると、ffmpegがx264に、x264がffmpegに依存する形になるので、まずは仮に一周目のビルドをします。 外部ライブラリは何も使わないなら、ここで終わってもいいと思います。 うまくいけば、mingw/i686-pc-mingw32 以下に32bit版が、mingw/x86_64-w64-mingw32 以下に64bit版が作られ、binフォルダのexeファイル単独で実行可能になるはずです。 以下、ビルドの際の注意点を書いときます。
$ PKG_CONFIG_PATH=/mingw/i686-pc-mingw32/lib/pkgconfig \ ./configure --prefix=/mingw/i686-pc-mingw32 --enable-gpl --enable-version3 --enable-nonfree \ --enable-postproc --enable-memalign-hack --enable-runtime-cpudetect --enable-avisynth \ --enable-w32threads $ make -j 5;make install【ffmpeg-mt 64bit版】
$ make clean $ PKG_CONFIG_PATH=/mingw/x86_64-w64-mingw32/lib/pkgconfig \ ./configure --prefix=/mingw/x86_64-w64-mingw32 --enable-gpl --enable-version3 --enable-nonfree \ --enable-postproc --enable-memalign-hack --enable-runtime-cpudetect --enable-avisynth \ --enable-w32threads --cross-prefix=x86_64-w64-mingw32- --target-os=mingw32 --arch=x86_64 --cpu=x86_64 $ make -j 5;make install【ffms2 32bit版】
$ CFLAGS="-O3 -march=native -fforce-addr -mfpmath=sse -msse2 -fomit-frame-pointer -fno-tree-vectorize" \ PKG_CONFIG_PATH=/mingw/i686-pc-mingw32/lib/pkgconfig \ ./configure --prefix=/mingw/i686-pc-mingw32 $ make -j 5;make install-strip 【ffms2 64bit版】 $ make clean $ CFLAGS="-O3 -march=native -fforce-addr -mfpmath=sse -msse2 -fomit-frame-pointer -fno-tree-vectorize" \ PKG_CONFIG_PATH=/mingw/x86_64-w64-mingw32/lib/pkgconfig \ ./configure --prefix=/mingw/x86_64-w64-mingw32 --host=x86_64-w64-mingw32 $ make -j 5;make install-strip【x264 32bit版】
$ PKG_CONFIG_PATH=/mingw/i686-pc-mingw32/lib/pkgconfig ./configure --prefix=/mingw/i686-pc-mingw32 \
--enable-win32thread
(config.makを書き換え)
$ make -j 5 fprofiled VIDS="~/soccer_4cif.y4m"; make install
【x264 64bit版】
$ make clean
$ PKG_CONFIG_PATH=/mingw/x86_64-w64-mingw32/lib/pkgconfig ./configure --prefix=/mingw/x86_64-w64-mingw32 \
--enable-win32thread --host=x86_64-w64-mingw32 --cross-prefix=x86_64-w64-mingw32-
(config.makを書き換え)
$ make -j 5 fprofiled VIDS="~/soccer_4cif.y4m"; make install
ffmpegで使う各種ライブラリをダウンロードし、それぞれビルドします。 今回試したライブラリとバージョンは以下のとおり。
configureスクリプトが用意されているものが多いので、ビルド方法はほぼ共通、それぞれ解凍したソースのフォルダでこんな感じに。 CFLAGSを指定して最適化するならお好みで。 ただし、libvpxとかはcpudetectしてるみたいなので留意されたし。
なお、configureオプションには、speexでは --enable-sse を、lameでは --enable-nasm を追加します。 xvidcoreは --disable-shared を除去し、ビルド完了後にlibフォルダにあるdllを削除、xvidcore.aをlibxvidcore.a にリネームしておきます。
$ PKG_CONFIG_PATH=/mingw/i686-pc-mingw32/lib/pkgconfig \ ./configure --prefix=/mingw/i686-pc-mingw32 --disable-shared $ make -j 5;make install【64bit版】
$ make clean $ PKG_CONFIG_PATH=/mingw/x86_64-w64-mingw32/lib/pkgconfig \ ./configure --prefix=/mingw/x86_64-w64-mingw32 --host=x86_64-w64-mingw32 --disable-shared $ make -j 5;make install
gsmにはconfigureスクリプトはないので、こんな感じでビルド。 frontendのexeファイルのとこでエラーが発生しますが、ライブラリはできてるのでとりあえず無視(^^;;
$ make $ install -m 644 lib/libgsm.a /mingw/i686-pc-mingw32/lib/ $ mkdir -p /mingw/i686-pc-mingw32/include/gsm/ $ install -m 644 inc/gsm.h /mingw/i686-pc-mingw32/include/gsm/【gsm 64bit版】
$ make clean $ make CC=x86_64-w64-mingw32-gcc $ install -m 644 lib/libgsm.a /mingw/x86_64-w64-mingw32/lib/ $ mkdir -p /mingw/x86_64-w64-mingw32/include/gsm/ $ install -m 644 inc/gsm.h /mingw/x86_64-w64-mingw32/include/gsm/
当初、うまくffmpegに入らなかったlibrtmpとlibschroedingerですが、何とか問題を回避する方法をみつけたので、こちらに移動しました(4/23)。 configureのログを眺めていたらlibrtmpのチェックのところでundefined reference 'timeGetTime@0'とか出ていて、この辺の関数はwinmmにあるもののようです。 schroedingerも、orcライブラリの辺りでundefined referenceになっていました。
結局、ffmpegのconfigureスクリプトに--extra-libs="-lwinmm -lorc-0.4"
を追加してみたらOKでした。
【OpenSSL 32bit版】 $ ./Configure mingw threads no-shared zlib --prefix=/mingw/i686-pc-mingw32 $ make -j 5; make test $ make install 【OpenSSL 64bit版】 $ ./Configure mingw64 threads no-shared zlib no-asm --prefix=/mingw/x86_64-w64-mingw32 \ --cross-compile-prefix=x86_64-w64-mingw32- $ make -j 5; make test $ make install 【rtmpdump 32bit版】 $ make SYS=mingw SHARED= CROSS_COMPILE=i686-pc-mingw32- \ OPT="-O3 -march=native -fno-tree-vectorize" $ make SYS=mingw SHARED= install prefix=/mingw/i686-pc-mingw32 【rtmpdump 64bit版】 $ make SYS=mingw SHARED= CROSS_COMPILE=x86_64-w64-mingw32- \ OPT="-O3 -march=native -fno-tree-vectorize" $ make SYS=mingw SHARED= install prefix=/mingw/x86_64-w64-mingw32
WebMはx68_64のMinGWがtargetにないので無理やりパッチを当ててみて、とりあえずビルドはできたけど、やっぱりffmpegでまともに使えないみたいなので、とりあえず32bit版だけ利用し、64bitは現状断念…。
$ PKG_CONFIG_PATH=/mingw/i686-pc-mingw32/lib/pkgconfig \ ./configure --target=x86-win32-gcc --cpu=i686 --prefix=/mingw/i686-pc-mingw32 --disable-shared \ --disable-examples $ make -j 5;make install【libvpx 64bit版】
$ make clean $ PKG_CONFIG_PATH=/mingw/x86_64-w64-mingw32/lib/pkgconfig CROSS=x86_64-w64-mingw32- \ ./configure --target=x86_64-win64-gcc --prefix=/mingw/x86_64-w64-mingw32 --disable-shared \ --disable-examples $ make -j 5;make install
OpenCVは、OpenCVのソースファイルと、ビルドに必要なCMakeを入手して、こんな感じでやったらビルドはできたっぽい。 ちなみにx86_64版をビルドする場合は、4のconfigureで[Specify options for cross-compiling] を選び、C, C++, Fortranは mingw/bin/x86_64-w64-mingw32-の付いたgcc.exe、c++exe、gfortran.exeを、OSは[Windows]を指定すればいいみたい。
けど、static版ライブラリのファイル名がおかしかったり、ffmpegのconfigureで認識できなかったりする…。 別に動画の対応フォーマットが増えるわけでもないみたいだから、とりあえず抜きにして、後で考えるかなぁ。
xavsやnutはビルドはできたけど、まあいいやってことでスキップ。 この辺は、とりあえず自分的に優先度が低いので放置w
ライブラリも揃ったところで本番のビルド。 といってもffmpegのビルドオプションがやけに増えてる以外は一周目と同じことを繰り返しているだけです。 ただし、一周目のゴミが残っているとマズいのでそれぞれmake cleanしてから実行します。 libvpxは現在32bit版しかうまく動いていないので、64bit版のオプションからは外しています。
configureスクリプトがlibrtmp等の認識に失敗するので、--extra-libs="-lwinmm -lorc-0.4"
を追加しました(4/23)。
$ make clean $ PKG_CONFIG_PATH=/mingw/i686-pc-mingw32/lib/pkgconfig \ ./configure --prefix=/mingw/i686-pc-mingw32 --enable-gpl --enable-version3 --enable-nonfree \ --enable-postproc --enable-memalign-hack --enable-runtime-cpudetect --enable-avisynth --disable-debug \ --extra-libs="-lwinmm -lorc-0.4" --enable-w32threads --enable-zlib --enable-bzlib --enable-libmp3lame \ --enable-libfaac --enable-libvorbis --enable-libtheora --enable-libspeex --enable-libopencore-amrnb \ --enable-libopencore-amrwb --enable-libopenjpeg --enable-libxvid --enable-libgsm --enable-librtmp \ --enable-libschroedinger --enable-libx264 --enable-libvpx $ make -j 5;make install【ffmpeg-mt 64bit版】
$ make clean $ PKG_CONFIG_PATH=/mingw/x86_64-w64-mingw32/lib/pkgconfig \ ./configure --prefix=/mingw/x86_64-w64-mingw32 --cross-prefix=x86_64-w64-mingw32- --target-os=mingw32 \ --arch=x86_64 --cpu=x86_64 --enable-gpl --enable-version3 --enable-nonfree --enable-postproc \ --enable-memalign-hack --enable-runtime-cpudetect --enable-avisynth --disable-debug \ --extra-libs="-lwinmm -lorc-0.4" --enable-w32threads --enable-zlib --enable-bzlib --enable-libmp3lame \ --enable-libfaac --enable-libvorbis --enable-libtheora --enable-libspeex --enable-libopencore-amrnb \ --enable-libopencore-amrwb --enable-libopenjpeg --enable-libxvid --enable-libgsm --enable-librtmp \ --enable-libschroedinger --enable-libx264 $ make -j 5;make install【ffms2 32bit版】
$ make clean $ CFLAGS="-O3 -march=native -fforce-addr -mfpmath=sse -msse2 -fomit-frame-pointer -fno-tree-vectorize" \ PKG_CONFIG_PATH=/mingw/i686-pc-mingw32/lib/pkgconfig \ ./configure --prefix=/mingw/i686-pc-mingw32 $ make -j 5;make install-strip 【ffms2 64bit版】 $ make clean $ CFLAGS="-O3 -march=native -fforce-addr -mfpmath=sse -msse2 -fomit-frame-pointer -fno-tree-vectorize" \ PKG_CONFIG_PATH=/mingw/x86_64-w64-mingw32/lib/pkgconfig \ ./configure --prefix=/mingw/x86_64-w64-mingw32 --host=x86_64-w64-mingw32 $ make -j 5;make install-strip【x264 32bit版】
$ make clean
$ PKG_CONFIG_PATH=/mingw/i686-pc-mingw32/lib/pkgconfig ./configure --prefix=/mingw/i686-pc-mingw32 \
--enable-win32thread
(config.makを書き換え)
$ make -j 5 fprofiled VIDS="~/soccer_4cif.y4m"; make install
【x264 64bit版】
$ make clean
$ PKG_CONFIG_PATH=/mingw/x86_64-w64-mingw32/lib/pkgconfig ./configure --prefix=/mingw/x86_64-w64-mingw32 \
--enable-win32thread --host=x86_64-w64-mingw32 --cross-prefix=x86_64-w64-mingw32-
(config.makを書き換え)
$ make -j 5 fprofiled VIDS="~/soccer_4cif.y4m"; make install
すべてつつがなく完了すると、D:\bin\msys
\mingw\i686-pc-mingw32\bin にx86版、D:\bin\msys
\mingw\x86_64-w64-mingw32\bin にx86_64版のffmpeg.exe、x264.exeができあがります(D:\bin\msys は最初にMinGWをインストールしたフォルダ)。
外部ライブラリをすべてstaticにビルドしてるので、ファイルサイズが結構大きくなっていますが(私の環境では10MB以上)、そのかわりobjdumpで確認してみても、素のWindowsが持ってるdllしか参照していません。
あとはこのファイルを任意のフォルダにコピーするなり、煮るなり、焼くなり、ご随意に。
といっても、この方法でビルドしたバイナリは自分のところで使う分にはOKですが、ライセンス上問題があるので勝手に第三者に配布してはいけません。
今回の趣旨に関係ないので試してませんが、ffmpegのビルドオプションから --enable-nonfree を除けば大丈夫…、になるかな?
$ cd /mingw/x86_64-w64-mingw32/bin $ objdump -p ffmpeg.exe|grep "DLL Name" DLL Name: AVICAP32.dll DLL Name: AVIFIL32.dll DLL Name: KERNEL32.dll DLL Name: msvcrt.dll DLL Name: msvcrt.dll DLL Name: PSAPI.DLL DLL Name: USER32.dll $ objdump -p x264.exe|grep "DLL Name" DLL Name: AVIFIL32.dll DLL Name: KERNEL32.dll DLL Name: msvcrt.dll DLL Name: msvcrt.dll DLL Name: WINMM.dll
D:\bin\msys\mingw\x86_64-w64-mingw32\bin>x264 --version x264 0.114.1924 08d04a4 (libswscale 0.12.0) (libavformat 52.104.0) (ffmpegsource 2.15.0.1) built on Apr 10 2011, gcc: 4.5.2 configuration: --bit-depth=8 x264 license: GPL version 2 or later libswscale/libavformat/ffmpegsource license: nonfree and unredistributable WARNING: This binary is unredistributable!
最後に、作成されたバイナリがまともな速度で動作しているかどうか、XvidVideo.RUと自分でビルドしたバイナリの簡単な比較をしてみました。 ちなみにリビジョンはともに1924です。 下の表は、soccer_4cif.y4m をオプションを何も指定しないで mp4に変換した際の平均fpsですが、ほぼ遜色ない速度が出ていると言って良さそうです。
x86版 | x86_64版 | |
---|---|---|
XvidVideo.RU | 237.43fps | 267.06fps |
自ビルド | 245.44fps | 263.39fps |