“Offer comes, ask friends to take it! I am participating in the 2022 Spring Recruit Punch card campaign. Click here for more details.”

Premise: The video uploaded in the project of the company has different encoding formats, but when playing in the browser, there is a black screen (with sound). Even the video in MP4 format cannot be played. After checking, it is found that the Video TAB of Chrome browser only supports partial video formats

Usually we use MP4 format, but MP4 is divided into three types: 1.MPEG4(DivX), 2.MPEG4(Xvid), and 3.AVC(H264). Only H264 videos can be played in HTML

Video formats and encodings supported by the tag:

MP4 = MPEG 4 files use H264 video codec and AAC audio codec

WebM = WebM files use VP8 video codecs and Vorbis audio codecs

Ogg = Ogg files use Theora video codec and Vorbis audio codec

format IE Firefox      Opera  Chrome   Safari
Ogg    No 3.5 + 10.5 + 5.0 + No
MPEG4 9.0 +  No No 5.0 + 3.0 +
WebM No  4.0 + 10.6 + 6.0 + No

Note: Internet Explorer 8 and earlier versions do not support the video TAB.

Use FFMPEG transcoding

Preview address: 642134542.github. IO /vue-ffmpeg/

1. Principle:

Ffmpeg. wasm is a pure WebAssembly/JavaScript port for FFMPEG. It supports recording, converting, and streaming video and audio within the browser.

The advent of Webassembly makes front-end transcoding possible

2, according to the official website configuration

2.1 NPM install

npm install @ffmpeg/ffmpeg @ffmpeg/core
Copy the code

2.2 HTML

<div> <h3>Upload a video to transcode to mp4 (x264) and play! </h3> <video id="output-video" controls ></video><br/> <input type="file" id="uploader"> <p id="message"></p> </div>Copy the code

2.3 js

const { createFFmpeg, fetchFile } = FFmpeg;

const ffmpeg = createFFmpeg({

    corePath: 'https://unpkg.com/@ffmpeg/[email protected]/dist/ffmpeg-core.js',

    log: true,

 });

 const transcode = async ({ target: { files } }) => {

   const message = document.getElementById('message');

     const { name } = files[0];

      message.innerHTML = 'Loading ffmpeg-core.js';

     await ffmpeg.load();

      ffmpeg.FS('writeFile', 'name', await fetchFile(files[0]));

      message.innerHTML = 'Start transcoding';

     await ffmpeg.run('-i', 'name', 'output.mp4');

      message.innerHTML = 'Complete transcoding';

     const data = ffmpeg.FS('readFile', 'output.mp4');

     const video = document.getElementById('output-video');

      video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));

   }

   const elm = document.getElementById('uploader');

   elm.addEventListener('change', transcode);
Copy the code

3, the results

The page loads and uploads normally, but an error occurs during transcoding

ReferenceError: SharedArrayBuffer is not defined,

Therefore, the SharedArrayBuffer error needs to be resolved

Compatibility check caniuse.com/?search=Sha…

You can see that SharedArrayBuffer is supported in Google Browser version 79 and above

Why is SharedArrayBuffer not defined

After a hundred degrees and view the issue, because the Security policy mechanism of Google Browser has changed

July 2017 (Chrome 60) SharedArrayBuffer introduced.

Chrome 92 limits SharedArrayBuffer to be used only in Cross-Origin Isolated pages.

Android Chrome 88 has the same restriction.

From the conclusion above, it can be seen that browsers in version 60-91 can be opened normally

What about the 92 version

In vue-CLI development environment we can configure in vue.config.js

devServer: {
  headers: {
      "Cross-Origin-Opener-Policy": "same-origin",
      "Cross-Origin-Embedder-Policy": "require-corp",
    },
}
Copy the code

4, effects,

You can see the file reading and transcoding process in the console,

And the page can display the video and play normally

5. Optimization:

5.1, corePath

The corePath address in createFFmpeg is CDN online, so we need to replace it with our own local resource.

But using import keeps returning errors

NPM install is still not working

We have to put ffmPEg-core. js, ffmPEg-core. wasm, and ffmPEg-core.worker.js in public

5.2, load,

It takes a long time to read the file and transcode, so we need to add a loading layer and a progress bar

ffmpeg.setProgress(({ ratio }) => {

  console.log(ratio);

  this.percentage = Math.floor(ratio * 100)

  /*

  * ratio is a float number between 0 to 1.

  */

});
Copy the code

6. Deployment:

SharedArrayBuffer is not defined, so we need to configure the request header in the proxy

add_header Cross-Origin-Opener-Policy same-origin;

add_header Cross-Origin-Embedder-Policy require-corp;
Copy the code

But there are still error messages

Solutions:

1. Use HTTPS instead of HTTP

2. Use Chrome 60-91

7. Error messages may exist

7.1, Caught (in promise) Error: Oops, something went wrong in FS operation

Solution: Do not use Chinese names, the name can be escaped

7.2, Error: ffmpeg.FS(‘readFile’, ‘output.mp4’) Error. Check if the path exists

Solution: Same as problem 1

7.3. Github Page cannot set the request header. How to solve the SharedArrayBuffer error

One answer to the Stack Overflow question offers a solution github.com/gzuidhof/co… The developer simply needs to introduce coi-serviceworker.js in index.html

<script src="coi-serviceworker.js"></script>
Copy the code

Reference links:

1, juejin. Cn/post / 701696…