浏览器运行ffmpeg

docker编译环境

docker镜像
docker pull abdulachik/ffmpeg.js:latest
docker run -it -p 8090:8090 -v /Users/workspace/Downloads/ffmpeg_wasm:/tmp --privileged=true abdulachik/ffmpeg.js:latest /bin/bash
cd /tmp

打开摄像头

<html>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script>
      function encodeVideo(){}
      function decodeVideo(){
        //获得video摄像头区域
        let video = document.getElementById("video");
        //播放
        video.play();
      }
      function getMedia() {
          let constraints = {
              //参数
              video: {width: 500, height: 500},
              audio: true
          };
          //获得video摄像头区域
          let video = document.getElementById("video");
          //返回的Promise对象
          let promise = navigator.mediaDevices.getUserMedia(constraints);
         //then()异步,调用MediaStream对象作为参数
          promise.then(function (MediaStream) {
              video.srcObject = MediaStream;
              video.play();
              //调用编码器
              encodeVideo();
              decodeVideo();
          });
      }
      </script>
      <body onload="getMedia()">
      <video id="video" width="500px" height="500px" autoplay="autoplay"></video>
      <video id="video2" width="500px" height="500px" autoplay="autoplay"></video>
      </body>
</html>

自定义编译ffmpeg

前端视频帧提取 ffmpeg + Webassembly-1
前端视频帧提取 ffmpeg + Webassembly-2
docker环境的emcc版本

emcc -v
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 2.0.30 (f782b50a7f8dded7cd0e2c7ee4fed41ab743f5c0)
clang version 14.0.0 (https://github.com/llvm/llvm-project c4048d8f50aaf2c4c13b8d3e138abc34a22da754)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /emsdk/upstream/bin

解码器编译命令
cd ~/ffmpeg

emconfigure ./configure \
    --prefix=/tmp/ffmpeg \
    --cc="emcc" \
    --cxx="em++" \
    --ar="emar" \
    --enable-cross-compile \
    --target-os=none \
    --arch=x86_32 \
    --cpu=generic \
    --disable-ffplay \
    --disable-ffprobe \
    --disable-asm \
    --disable-doc \
    --disable-devices \
    --disable-pthreads \
    --disable-w32threads \
    --disable-network \
    --disable-hwaccels \
    --disable-parsers \
    --disable-bsfs \
    --disable-debug \
    --disable-protocols \
    --disable-indevs \
    --disable-outdevs \
    --disable-swresample
make

make install

对视频进行解码和提取图像主要用到 ffmpeg 的解封装、解码和图像缩放转换相关的接口,主要依赖以下的库

  • libavcodec - 音视频编解码
  • libavformat - 音视频解封装
  • libavutil - 工具函数
  • libswscale - 图像缩放&色彩转换
    编译为wasm供js调用
export TOTAL_MEMORY=33554432

export FFMPEG_PATH=/tmp/ffmpeg
//EXPORTED_FUNCTIONS 导出供 js 调用的函数
emcc capture.c ${FFMPEG_PATH}/lib/libavformat.a ${FFMPEG_PATH}/lib/libavcodec.a ${FFMPEG_PATH}/lib/libswscale.a ${FFMPEG_PATH}/lib/libavutil.a \
    -O3 \
    -I "${FFMPEG_PATH}/include" \
    -s WASM=1 \
    -s TOTAL_MEMORY=${TOTAL_MEMORY} \
    -s EXPORTED_FUNCTIONS='["_main", "_free", "_capture"]' \
    -s ASSERTIONS=1 \
    -s ALLOW_MEMORY_GROWTH=1 \
    -o /capture.js

效果

小结

以上实验表明,js调用ffmpeg库好像不能直接调用ffmpeg-mp4.js,需要在c文件中实现

ImageData *capture(int ms, char *path);

然后在html文件中调用

<script src="web-capture.js"></script>

    <script>

        let button = document.querySelector('#js_button');
        let resultContainer = document.querySelector('#js_result');
        let fileInput = document.querySelector('#js_file');
        let timeInput = document.querySelector('#js_time');
        let infoContainer = document.querySelector('#js_info');

        button.addEventListener('click', () => {
            let file = fileInput.files[0];

            let startTime = Date.now();

            window.webCapture.capture(file, timeInput.value * 1000, (dataURL, imageInfo) => {

                const { width, height, duration } = imageInfo;

                resultContainer.innerHTML = `<img src="${dataURL}" />`

                infoContainer.innerHTML = `耗时:${Date.now() - startTime}ms<br>宽度:${width}<br>高度:${height}<br>时长:${duration / 1000000}s`;
            })

        });
    </script>
posted @ 2022-08-15 02:55  qsBye  阅读(349)  评论(0编辑  收藏  举报