Mengkompilasi FFmpeg ke WebAssembly (= ffmpeg.js): Bagian 2 - Mengkompilasi dengan Emscripten



Daftar bagian terjemahan seri:


  1. Memasak
  2. Kompilasi dengan Emscripten (Anda ada di sini)
  3. Konversi avi ke mp4


Dimulai dengan bagian ini, materi akan lebih rumit, jadi jangan ragu untuk google selama membaca, jika Anda tidak mengerti apa yang terjadi.


Selain itu, saya akan mencoba mendokumentasikan solusi untuk masalah yang mungkin terjadi sehingga Anda dapat mengkompilasi perpustakaan dengan pengaturan Anda.


Pada bagian ini kita akan menganalisis:


  1. Cara mengatur lingkungan untuk Emscripten di Docker
  2. Menggunakan emconfigure dan emmake
  3. Bagaimana mengatasi masalah saat kompilasi FFmpeg dengan Emscripten



Cara mengatur lingkungan untuk Emscripten di Docker


Pada bagian pertama, kami mengkompilasi FFmpeg dengan gcc dan dapat beralih ke menggunakan gambar Docker dengan emscripten.


Saya akan menggunakan trzeci / emscripten versi 1.38.45:


$ docker pull trzeci/emscripten:1.38.45 

Karena gambar membutuhkan sekitar 1 GB, prosesnya mungkin memakan waktu.


Sekarang kita akan menemukan konfigurasi yang benar untuk mengkompilasi FFmpeg ke emscripten dengan coba-coba, yang akan membutuhkan ketekunan dan membaca volume besar dokumentasi. Jalankan wadah dengan emscripten dan pasang sumber FFmpeg di direktori / src .


 # ,      FFmpeg $ docker run -it \ -v $PWD:/src \ trzeci/emscripten:1.38.45 \ /bin/bash 

Di dalam wadah, jalankan ls --color untuk melihat sesuatu seperti ini:



Menggunakan emconfigure dan emmake . Bagaimana mengatasi masalah kompilasi


Mari kita mulai dengan konfigurasi. Pada bagian pertama, kami melakukan ./configure --disable-x86asm , dalam emscripten ini dicapai dengan emconfigure ./configure --disable-x86asm perintah . (Untuk detail tentang penggunaan emconfigure, lihat di sini )


 $ emconfigure ./configure --disable-x86asm 

Dan karena kita tidak melihat kesalahan, itu tetap hanya untuk menjalankan emmake make -j4 dan mendapatkan FFmpeg.js yang didambakan? Sayangnya tidak. Salah satu tugas terpenting untuk emconfigure adalah mengganti compiler gcc dengan emcc (atau g ++ dengan em ++), tetapi hasil ./configure masih menghasilkan gcc.


 root@57ab95def750:/src# emconfigure ./configure --disable-x86asm emscripten sdl2-config called with /emsdk_portable/emscripten/tag-1.38.45/system/bin/sdl2-config --cflags emscripten sdl2-config called with /emsdk_portable/emscripten/tag-1.38.45/system/bin/sdl2-config --libs install prefix /usr/local source path . C compiler gcc #    emcc C library glibc ARCH x86 (generic) big-endian no runtime cpu detection yes standalone assembly no x86 assembler nasm 

Otomatisasi apa pun memiliki batasnya, dan dalam hal ini, sayangnya, kita harus melakukan semuanya secara manual. Mari kita lihat apakah ada argumen untuk membantu kami:


 $ ./configure --help 

Di bawah bagian opsi Toolchain , kita melihat argumen untuk menunjukkan jenis kompiler.


 root@57ab95def750:/src# ./configure --help Usage: configure [options] Options: [defaults in brackets after descriptions]Help options: ... Toolchain options: ... --nm=NM use nm tool NM [nm -g] --ar=AR use archive tool AR [ar] --as=AS use assembler AS [] --ln_s=LN_S use symbolic link tool LN_S [ln -s -f] --strip=STRIP use strip tool STRIP [strip] --windres=WINDRES use windows resource compiler WINDRES [windres] --x86asmexe=EXE use nasm-compatible assembler EXE [nasm] --cc=CC use C compiler CC [gcc] --cxx=CXX use C compiler CXX [g++] --objcc=OCC use ObjC compiler OCC [gcc] --dep-cc=DEPCC use dependency generator DEPCC [gcc] --nvcc=NVCC use Nvidia CUDA compiler NVCC [nvcc] --ld=LD use linker LD [] ... 

Mari kita gunakan di emscripten


 $ emconfigure ./configure \ --disable-x86asm \ --nm="llvm-nm -g" \ --ar=emar \ --cc=emcc \ --cxx=em++ \ --objcc=emcc \ --dep-cc=emcc 

Sekarang mengeksekusi ./configure akan membutuhkan lebih banyak waktu, tetapi sebagai hasilnya kita mendapatkan emcc.


 root@57ab95def750:/src# emconfigure ... emscripten sdl2-config called with /emsdk_portable/emscripten/tag-1.38.45/system/bin/sdl2-config --cflags emscripten sdl2-config called with /emsdk_portable/emscripten/tag-1.38.45/system/bin/sdl2-config --libs install prefix /usr/local source path . C compiler emcc # emcc    C library ARCH x86 (generic) big-endian no runtime cpu detection yes standalone assembly no 

Mari kita lihat bagaimana kompilasi berjalan.


 $ emmake make -j4 

Dan segera sebuah kesalahan ...


 root@57ab95def750:/src# emmake make -j4 ... ./libavutil/x86/timer.h:39:24: error: invalid output constraint '=a' in asm : "=a" (a), "=d" (d)); ^ 

Pesan tersebut menunjukkan bahwa kesalahan tersebut terkait dengan asm. Buka ./libavutil/x86/timer.h untuk melihat bahwa masalahnya ada di assembler inline x86, yang tidak kompatibel dengan WebAssembly, jadi matikan.


 $ emconfigure ./configure \ --disable-x86asm \ --disable-inline-asm \ #   asm --nm="llvm-nm -g" \ --ar=emar \ --cc=emcc \ --cxx=em++ \ --objcc=emcc \ --dep-cc=emcc 

Ayo coba kompilasi lagi.


 $ emmake make -j4 

Kompilasi berlanjut sampai kesalahan berikutnya.


 root@57ab95def750:/src# emmake make -j4 ... AR libavdevice/libavdevice.a AR libavfilter/libavfilter.a AR libavformat/libavformat.a AR libavcodec/libavcodec.a AR libswresample/libswresample.a AR libswscale/libswscale.a AR libavutil/libavutil.a HOSTLD doc/print_options GENTEXI doc/avoptions_format.texi /bin/sh: 1: doc/print_options: Exec format error doc/Makefile:59: recipe for target 'doc/avoptions_format.texi' failed make: *** [doc/avoptions_format.texi] Error 2 make: *** Waiting for unfinished jobs.... 

Sesuatu yang berkaitan dengan pembuatan dokumentasi, yang sama sekali tidak kita butuhkan, jadi matikan saja.


 $ emconfigure ./configure \ --disable-x86asm \ --disable-inline-asm \ --disable-doc \ #    --nm="llvm-nm -g" \ --ar=emar \ --cc=emcc \ --cxx=em++ \ --objcc=emcc \ --dep-cc=emcc 

Kami melakukannya lagi.


 $ emmake make -j4 

Sekarang kesalahan telah terjadi pada tahap strip.


 root@57ab95def750:/src# emmake make -j4 ... STRIP ffmpeg STRIP ffprobe strip:ffmpeg_g: File format not recognized strip:ffprobe_g: File format not recognized Makefile:101: recipe for target 'ffmpeg' failed make: *** [ffmpeg] Error 1 make: *** Waiting for unfinished jobs.... Makefile:101: recipe for target 'ffprobe' failed make: *** [ffprobe] Error 1 

Karena pemangkasan asli tidak kompatibel dengan versi WebAssembly kami, kami juga akan menonaktifkannya.


 $ emconfigure ./configure \ --disable-x86asm \ --disable-inline-asm \ --disable-doc \ --disable-stripping \ #  strip --nm="llvm-nm -g" \ --ar=emar \ --cc=emcc \ --cxx=em++ \ --objcc=emcc \ --dep-cc=emcc 

Usaha keempat.


 $ emmake make -j4 

Akhirnya, proses berakhir tanpa kesalahan. Tetapi hanya pada output kita mendapatkan file ffmpeg , yang tidak dimulai, dan itu bukan file js (atau file wasm). Untuk mendapatkan file js, kita perlu menambahkan -o ffmpeg.js ke perintah emcc, yang dapat dilakukan dengan dua cara:


  1. Ubah Makefile dari FFmpeg itu sendiri
  2. Tambahkan kompilasi / penautan tambahan

Kami akan memilih cara kedua, karena saya tidak ingin menyentuh sumber FFmpeg karena kemungkinan efek samping. Jadi kami menemukan bagaimana ffmpeg dihasilkan menggunakan make. Di sinilah opsi make berguna untuk menjalankan lari kering.


 $ emmake make -n 

Kami melihat tim generasi.


 root@57ab95def750:/src# emmake make -n ... printf "LD\t%s\n" ffmpeg_g; emcc -Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavresample -Llibavutil -Llibpostproc -Llibswscale -Llibswresample -Wl,--as-needed -Wl,-z,noexecstack -Wl,--warn-common -Wl,-rpath-link=libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample -Qunused-arguments -o ffmpeg_g fftools/ffmpeg_opt.o fftools/ffmpeg_filter.o fftools/ffmpeg_hw.o fftools/cmdutils.o fftools/ffmpeg.o -lavdevice -lavfilter -lavformat -lavcodec -lswresample -lswscale -lavutil -lm -pthread -lm -lm -pthread -lm -lm -lm -pthread -lm printf "CP\t%s\n" ffmpeg; cp -p ffmpeg_g ffmpeg ... 

Ada banyak hal yang tidak perlu, jadi mari kita hapus argumen yang tidak digunakan (yang akan Anda lihat di akhir kompilasi), bersihkan sedikit dan ganti nama ffmpeg_g menjadi ffmpeg.js .


 $ emcc \ -Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavresample -Llibavutil -Llibpostproc -Llibswscale -Llibswresample \ -Qunused-arguments \ -o ffmpeg.js fftools/ffmpeg_opt.o fftools/ffmpeg_filter.o fftools/ffmpeg_hw.o fftools/cmdutils.o fftools/ffmpeg.o \ -lavdevice -lavfilter -lavformat -lavcodec -lswresample -lswscale -lavutil -lm -pthread 

Seharusnya berhasil, tetapi kita akan mengalami masalah kurangnya memori.


 root@57ab95def750:/src# emcc ... shared:ERROR: Memory is not large enough for static data (11794000) plus the stack (5242880), please increase TOTAL_MEMORY (16777216) to at least 17037904 

Tambahkan argumen TOTAL_MEMORY untuk menambah ukuran memori (33554432 Bytes: = 32 MB).


 $ emcc \ -Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavresample -Llibavutil -Llibpostproc -Llibswscale -Llibswresample \ -Qunused-arguments \ -o ffmpeg.js fftools/ffmpeg_opt.o fftools/ffmpeg_filter.o fftools/ffmpeg_hw.o fftools/cmdutils.o fftools/ffmpeg.o \ -lavdevice -lavfilter -lavformat -lavcodec -lswresample -lswscale -lavutil -lm -pthread \ -s TOTAL_MEMORY=33554432 

Akhirnya kami mendapat file js dan wasm kami


 root@57ab95def750:/src# ls ffmpeg* ffmpeg ffmpeg.js ffmpeg.js.mem ffmpeg.wasm ffmpeg.worker.js ffmpeg_g 

Buat test.html untuk menguji FFmpeg.js


 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <script src="./ffmpeg.js"></script> </head> <body> </body> </html> 

Mari kita mulai server yang mudah (dengan menjalankan python2 -m SimpleHTTPServer ) dan membuka halaman yang dihasilkan ( http: // localhost: 8000 / test.html ) , lalu buka Chrome DevTools.



Seperti yang Anda lihat, FFmpeg bekerja setengah dengan dosa, jadi sekarang Anda dapat mulai memoles ffmpeg.js.


Skrip build lengkap dapat ditemukan di repositori ini (build-with-docker.sh dan build-js.sh)

.

Source: https://habr.com/ru/post/id473134/


All Articles