Lista de partes traduzidas da série:
- Cozinhar
- Compilando com o Emscripten (você está aqui)
- Converter avi para mp4
Começando com esta parte, o material será mais complicado, por isso não hesite em pesquisar no google durante a leitura, se você não entender o que está acontecendo.
Além disso, tentarei documentar a solução para possíveis problemas, para que você possa compilar a biblioteca com suas configurações.
Nesta parte, analisaremos:
- Como configurar um ambiente para o Emscripten no Docker
- Usando emconfigure e emmake
- Como resolver problemas ao compilar o FFmpeg com o Emscripten
Como configurar um ambiente para o Emscripten no Docker
Na primeira parte, compilamos o FFmpeg com o gcc e podemos usar a imagem do Docker com o emscripten.
Vou usar a versão 1.38.45 do trzeci / emscripten:
$ docker pull trzeci/emscripten:1.38.45
Como a imagem leva cerca de 1 GB, o processo pode levar algum tempo.
Agora, encontraremos a configuração correta para compilar o FFmpeg no emscripten por tentativa e erro, o que exigirá perseverança e leitura de grandes volumes de documentação. Execute o contêiner com emscripten e monte as fontes FFmpeg no diretório / src .
# , FFmpeg $ docker run -it \ -v $PWD:/src \ trzeci/emscripten:1.38.45 \ /bin/bash
Dentro do contêiner, execute ls --color para ver algo assim:
Usando emconfigure e emmake . Como resolver problemas de compilação
Vamos começar com a configuração. Na primeira parte, executamos ./configure --disable-x86asm , em emscripten isso é alcançado com o comando emconfigure ./configure --disable-x86asm . (Para detalhes sobre o uso do emconfigure, veja aqui )
$ emconfigure ./configure --disable-x86asm
E como não vimos nenhum erro, resta apenas executar o emmake make -j4 e obter o cobiçado FFmpeg.js? Infelizmente não. Uma das tarefas mais importantes do emconfigure é substituir o compilador gcc pelo emcc (ou g ++ pelo em ++), mas o resultado de ./configure ainda produz o 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
Qualquer automação tem seus limites e, neste caso, infelizmente, temos que fazer tudo manualmente. Vamos ver se existem argumentos para nos ajudar:
$ ./configure --help
Na seção Opções da cadeia de ferramentas , vemos argumentos para indicar o tipo de compilador.
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 [] ...
Vamos usá-los em emscripten
$ emconfigure ./configure \ --disable-x86asm \ --nm="llvm-nm -g" \ --ar=emar \ --cc=emcc \ --cxx=em++ \ --objcc=emcc \ --dep-cc=emcc
Agora, executar ./configure levará mais tempo, mas, como resultado, obtemos o 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
Vamos ver como vai a compilação.
$ emmake make -j4
E imediatamente um erro ...
root@57ab95def750:/src# emmake make -j4 ... ./libavutil/x86/timer.h:39:24: error: invalid output constraint '=a' in asm : "=a" (a), "=d" (d)); ^
A mensagem mostra que o erro está de alguma forma relacionado ao asm. Abra ./libavutil/x86/timer.h para verificar se o problema está no assembler embutido x86, que é incompatível com o WebAssembly, portanto, desative-o.
$ emconfigure ./configure \ --disable-x86asm \ --disable-inline-asm \ # asm --nm="llvm-nm -g" \ --ar=emar \ --cc=emcc \ --cxx=em++ \ --objcc=emcc \ --dep-cc=emcc
Vamos tentar compilar novamente.
$ emmake make -j4
A compilação continua até o próximo erro.
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....
Algo relacionado à geração de documentação, da qual absolutamente não precisamos, então desligue-o.
$ emconfigure ./configure \ --disable-x86asm \ --disable-inline-asm \ --disable-doc \ # --nm="llvm-nm -g" \ --ar=emar \ --cc=emcc \ --cxx=em++ \ --objcc=emcc \ --dep-cc=emcc
Estamos fazendo de novo.
$ emmake make -j4
Agora, o erro ocorreu no estágio de 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
Como o recorte nativo é incompatível com a nossa versão do WebAssembly, também o desabilitaremos.
$ 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
Quarta tentativa.
$ emmake make -j4
Finalmente, o processo terminou sem erros. Mas somente na saída obtivemos o arquivo ffmpeg , que não inicia, e não é um arquivo js (ou arquivo wasm). Para obter o arquivo js, precisamos adicionar -o ffmpeg.js ao comando emcc, o que pode ser feito de duas maneiras:
- Alterar o Makefile do próprio FFmpeg
- Adicionar compilação / vinculação adicionais
Vamos escolher a segunda maneira, já que não quero tocar nas fontes do FFmpeg por causa de possíveis efeitos colaterais. Então, descobrimos como o ffmpeg é gerado usando make. É aqui que a opção make é útil para executar uma execução a seco.
$ emmake make -n
Vemos a equipe de geração.
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 ...
Há muitas coisas desnecessárias, então vamos remover os argumentos não utilizados (que você verá no final da compilação), limpar um pouco e renomear ffmpeg_g para 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
Deveria ter funcionado, mas encontraremos o problema da falta de memória.
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
Adicione o argumento TOTAL_MEMORY para aumentar o tamanho da memória (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
Finalmente conseguimos nossos arquivos js e wasm
root@57ab95def750:/src# ls ffmpeg* ffmpeg ffmpeg.js ffmpeg.js.mem ffmpeg.wasm ffmpeg.worker.js ffmpeg_g
Crie test.html para testar o FFmpeg.js
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <script src="./ffmpeg.js"></script> </head> <body> </body> </html>
Vamos iniciar o servidor fácil (executando python2 -m SimpleHTTPServer ) e abrir a página resultante ( http: // localhost: 8000 / test.html ) e abrir o Chrome DevTools.
Como você pode ver, o FFmpeg está trabalhando pela metade com um pecado, então agora você pode começar a polir o ffmpeg.js.
O script de construção completo pode ser encontrado neste repositório (build-with-docker.sh e build-js.sh)
.