Kompilieren von FFmpeg zu WebAssembly (= ffmpeg.js): Teil 2 - Kompilieren mit Emscripten



Liste der übersetzten Teile der Serie:


  1. Kochen
  2. Kompilieren mit Emscripten (Sie sind hier)
  3. Konvertiere avi in ​​mp4


Ab diesem Teil wird das Material komplizierter. Zögern Sie also nicht, während des Lesens zu googeln, wenn Sie nicht verstehen, was passiert.


Außerdem werde ich versuchen, die Lösung möglicher Probleme zu dokumentieren, damit Sie die Bibliothek mit Ihren Einstellungen kompilieren können.


In diesem Teil werden wir analysieren:


  1. So richten Sie eine Umgebung für Emscripten in Docker ein
  2. Verwenden von emconfigure und emmake
  3. So lösen Sie Probleme beim Kompilieren von FFmpeg mit Emscripten



So richten Sie eine Umgebung für Emscripten in Docker ein


Im ersten Teil haben wir FFmpeg mit gcc kompiliert und können das Docker-Image mit emscripten verwenden.


Ich werde trzeci / emscripten Version 1.38.45 verwenden:


$ docker pull trzeci/emscripten:1.38.45 

Da das Image ungefähr 1 GB benötigt, kann der Vorgang einige Zeit dauern.


Jetzt finden wir die richtige Konfiguration für das Kompilieren von FFmpeg in emscripten durch Ausprobieren, was Ausdauer und das Lesen großer Dokumentationsmengen erfordert. Führen Sie den Container mit emscripten aus und hängen Sie die FFmpeg-Quellen im Verzeichnis / src ein .


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

Führen Sie im Container ls --color aus , um Folgendes zu sehen:



Verwenden von emconfigure und emmake . So lösen Sie Kompilierungsprobleme


Beginnen wir mit der Konfiguration. Im ersten Teil haben wir ./configure --disable-x86asm ausgeführt . In emscripten wird dies mit dem Befehl emconfigure ./configure --disable-x86asm erreicht . (Einzelheiten zur Verwendung von emconfigure finden Sie hier )


 $ emconfigure ./configure --disable-x86asm 

Und da wir keine Fehler gesehen haben, bleibt es nur, emmake make -j4 auszuführen und die begehrten FFmpeg.js zu bekommen? Leider gibt es keine. Eine der wichtigsten Aufgaben für emconfigure besteht darin, den gcc-Compiler durch emcc (oder g ++ durch em ++) zu ersetzen. Das Ergebnis von ./configure erzeugt jedoch weiterhin 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 

Jede Automatisierung hat ihre Grenzen, und in diesem Fall müssen wir leider alles manuell erledigen. Mal sehen, ob es Argumente gibt, die uns helfen:


 $ ./configure --help 

Im Abschnitt Toolchain-Optionen sehen wir Argumente, die den Compilertyp angeben.


 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 [] ... 

Verwenden wir sie in emscripten


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

Das Ausführen von ./configure dauert jetzt länger, aber als Ergebnis erhalten wir 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 

Mal sehen, wie die Zusammenstellung verläuft.


 $ emmake make -j4 

Und sofort ein Fehler ...


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

Die Nachricht zeigt, dass der Fehler irgendwie mit asm zusammenhängt. Öffnen Sie ./libavutil/x86/timer.h , um festzustellen , dass das Problem im x86-Inline-Assembler liegt, der nicht mit WebAssembly kompatibel ist. Deaktivieren Sie ihn daher.


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

Versuchen wir noch einmal zu kompilieren.


 $ emmake make -j4 

Die Kompilierung wird bis zum nächsten Fehler fortgesetzt.


 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.... 

Etwas im Zusammenhang mit der Erstellung von Dokumentationen, die wir absolut nicht benötigen, schalten Sie es einfach aus.


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

Wir machen es wieder.


 $ emmake make -j4 

Jetzt ist der Fehler im Strip-Stadium aufgetreten.


 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 

Da das native Zuschneiden nicht mit unserer Version von WebAssembly kompatibel ist, werden wir es auch deaktivieren.


 $ 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 

Vierter Versuch.


 $ emmake make -j4 

Schließlich endete der Prozess ohne Fehler. Aber nur bei der Ausgabe haben wir die ffmpeg- Datei, die nicht startet, und es ist keine js-Datei (oder wasm-Datei). Um die js-Datei zu erhalten, müssen wir -o ffmpeg.js zum Befehl emcc hinzufügen. Dies kann auf zwei Arten erfolgen:


  1. Ändern Sie das Makefile von FFmpeg selbst
  2. Zusätzliche Zusammenstellung / Verknüpfung hinzufügen

Wir werden den zweiten Weg wählen, da ich die FFmpeg-Quellen wegen möglicher Nebenwirkungen nicht berühren möchte. Wir finden also heraus, wie ffmpeg mit make generiert wird. Hier bietet sich die Option make an, um einen Trockenlauf durchzuführen.


 $ emmake make -n 

Wir sehen das Generationenteam.


 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 ... 

Es gibt viele unnötige Dinge, also entfernen wir die nicht verwendeten Argumente (die Sie am Ende der Kompilierung sehen werden), bereinigen Sie ein wenig und benennen Sie ffmpeg_g in ffmpeg.js um .


 $ 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 

Es hätte funktionieren sollen, aber wir werden auf das Problem des Speichermangels stoßen.


 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 

Fügen Sie das Argument TOTAL_MEMORY hinzu, um die Speichergröße zu erhöhen (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 

Endlich haben wir unsere js und wasm Dateien bekommen


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

Erstellen Sie test.html , um FFmpeg.js zu testen


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

Starten wir den easy Server (durch Ausführen von python2 -m SimpleHTTPServer ) und öffnen Sie die resultierende Seite ( http: // localhost: 8000 / test.html ) . Öffnen Sie dann Chrome DevTools.



Wie Sie sehen können, arbeitet FFmpeg in zwei Hälften mit einer Sünde, sodass Sie jetzt mit dem Polieren von ffmpeg.js beginnen können.


Das vollständige Build-Skript finden Sie in diesem Repository (build-with-docker.sh und build-js.sh).

.

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


All Articles