NPlayer is written in Typescript plus Sass, without any third-party runtime dependencies, with a Gzip size of 21KB, IE11 compatibility and SSR support. The player is highly customizable, all ICONS, buttons, colors, etc. can be replaced, and provides built-in components for secondary development. It also has a plug-in system, which is used to provide the function of bullets. The player can access any streaming media such as HLS, Dash and FLV.

  • Website: nplayer.js.org
  • Source: github.com/woopen/npla…
  • Codesandbox.io /s/ancient-s…

The installation

Run the following command to quickly install NPlayer.

npm i -S nplayer
Copy the code

See Installation for more.

Begin to use

import Player from 'nplayer'

const player = new NPlayer({
  src: 'https://v-cdn.zjol.com.cn/280443.mp4'
})

// player.mount('#app')
player.mount(document.body)
Copy the code

The easiest way to create a player is to create a Player object, set the SRC of the video element, and then mount it into document.body.

Of course you can also provide your own video elements.

import Player from 'nplayer'

const video = document.createElement('video')
video.src = 'https://v-cdn.zjol.com.cn/280443.mp4'
const player = new Player({ video, videoAttrs: { autoplay: 'true' } })

player.mount(document.body)
Copy the code

You can also use the videoAttrs parameter to add the attributes of the video element to the video element. VideoAttrs has some default values that will be merged with the ones you pass in and set to the video element. See the parameters section for details.

The player.mount method mounts the player to the page, which takes a parameter, either a string or a DOM element. When it is a string, the DOM element is automatically looked up.

Preview thumbnail

When you hover over the progress bar, a little thumbnail will appear to preview the screenshot at that point in time, which is now available on many video sites. NPlayer also provides this functionality.

NPlayer’s thumbnail has the thumbnail parameter set, which is a thumbnail configuration object with the following interface:

interfaceThumbnailOptions { startSecond? :number; gapSecond? :number; row? :number; col? :number; width? :number; height? :number; images? :string[];
}
Copy the code

The default values for each attribute are as follows:

{
  startSecond: 0.gapSecond: 10.col: 5.row: 5.width: 160.height: 90.images: []}Copy the code

The preview thumbnail is actually a single image made up of a bunch of low-resolution screenshots, as shown below.

We can see that this Sprite image is made up of little 5 x 5 thumbnails, and of course a video could have a bunch of Sprite images like this, which is why the images above are an array of strings.

Now that you know Sprite, let’s see what each parameter means in detail.

parameter describe
startSecond So the time that the thumbnail was created, if the thumbnail was created in the first second of the video then this would be 1
gapSecond Time span of a little thumbnail, if the little thumbnail is every 5 seconds, put 5 here
col The number of columns in a Sprite diagram
row The number of lines in a Sprite diagram
width Small thumbnail width
height Small thumbnail height
images An array of link addresses for Sprite images

Thumbnail making

There are many ways to create a preview thumbnail of a video, such as using the Thumbnails method in the NodeJS Node-Fluent-FFmpeg library. Of course you can find out more online.

Here’s how to generate video thumbnails directly from the FFmPEG command line.

Ffmpeg is a very powerful audio and video tool, which is used as the kernel of many players. See the official documentation for more details.

Download and install FFMPEG from ffMPEG’s official website.

After the installation, you can run the following commands on the CLI.

ffmpeg -i ./test.webm -vf 'fps=1/10:round=zero:start_time=-9,scale=160x90,tile=5x5' M%d.jpg
Copy the code

Use the command above to generate a bunch of 5 x 5 Sprite images, with each Sprite thumbnail size 160 x 90. Sprite image file names are m1.jpg, m2.jp, m3.jpg… Increase like this.

  • The -i parameter is followed by the video file.

  • -vf parameters are followed by filters. If multiple filters are used, separate them. If one filter has multiple parameters, separate them.

  • FPS =1/10 indicates that an image is output every 10 seconds. Round =zero indicates that the timestamp is rounded to 0. Start_time =-9 is going to truncate from the first second, ignoring zero seconds of black screen frames, and the reason why it’s -9 instead of 1 is because FPS is set to 10 seconds, so we want to start at the first second with 1-10 equals -9.

  • Scale =160×90 sets the output image resolution and tile=5×5 groups the small images together in a 5×5 manner.

  • At the end, M%d. JPG is the file name, and %d is the numeric increment.

With the thumbnail generated by the command above, you can set the following parameters.

new Player({
  thumbnail: {
    startSecond: 1.images: ['M1.jpg'.'M2.jpg'.'M3.jpg']}})Copy the code

Since you can use the default values for the other parameters, I will not fill in the blanks here.

Streaming media

Most of the videos you watch online are now streamed using HLS and DASH instead of.MP4 files. NPlayer supports access to any streaming media protocol.

import Hls from 'hls'
import Player from 'player'

const hls = new Hls()
const player = new Player()
hls.attachMedia(player.video)

hls.on(Hls.Events.MEDIA_ATTACHED, function () {
  hls.loadSource('https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8')
})

player.mount(document.body)
Copy the code

Since all these libraries really need is a video element, we just pass in the player.video property, which is the same for any other streaming library. See the streaming section for more information.

Resolution switch

These mainstream video sites on the Internet should be able to adjust the video definition, high definition also need to open membership to watch. And by default, the best resolution is automatically selected based on the current user’s network speed.

It’s easy to do this using the streaming protocol mentioned above, so let’s use NPlayer to switch sharpness. If you’re having trouble with the code, it’s best to read the control section first.

import Player from 'nplayer'
import Hls from 'hls'

// 1. First create a control bar entry
const Quantity = {
  element: document.createElement('div'),
  init(player) {
    this.btn = document.createElement('div')
    this.btn.textContent = 'quality'
    this.element.appendChild(this.btn)
    this.popover = new player.Player.components.Popover(this.element)
    this.btn.addEventListener('click'.() = >  this.popover.show())
    // Display popover when clicking the button
    this.element.style.display = 'none'
    // Hide by default
    this.element.classList.add('quantity')}}// 2. We put it after spacer
const player = new Player({
  controls: ['play'.'volume'.'time'.'spacer', Quantity, 'airplay'.'settings'.'web-fullscreen'.'fullscreen'],})Create an HLS instance
const hls = new Hls();
hls.on(Hls.Events.MEDIA_ATTACHED, function () {
  hls.on(Hls.Events.MANIFEST_PARSED, function () {
    // 4. Rank sharpness, and the higher the sharpness, the first
    hls.levels.sort((a, b) = > b.height - a.height)
    const frag = document.createDocumentFragment()
    // 5. Add the element corresponding to sharpness and click to switch sharpness
    const listener = (i) = > (init) = > {
      const last = Quantity.itemElements[Quantity.itemElements.length - 1]
      const prev = Quantity.itemElements[Quantity.value] || last
      const el = Quantity.itemElements[i] || last
      prev.classList.remove('quantity_item-active')
      el.classList.add('quantity_item-active')
      Quantity.btn.textContent = el.textContent
      if(init ! = =true && !player.paused) setTimeout(() = > player.play())
      // Since HLS switching sharpness will cause the video to pause, we will let it resume playing automatically
      Quantity.value = hls.currentLevel = hls.loadLevel = i;
      Quantity.popover.hide();
    }
    // 6. Add the sharpness element
    Quantity.itemElements = hls.levels.map((l, i) = > {
      const el = document.createElement('div')
      el.textContent = l.name + 'P'
      if (l.height === 1080) el.textContent += 'super clear'
      if (l.height === 720) el.textContent += 'hd'
      if (l.height === 480) el.textContent += 'clear'
      el.classList.add('quantity_item')
      el.addEventListener('click', listener(i))
      frag.appendChild(el)
      return el;
    })

    const el = document.createElement('div')
    el.textContent = 'automatic'
    el.addEventListener('click', listener(-1))
    el.classList.add(styles.QuantityItem)
    frag.appendChild(el)
    Quantity.itemElements.push(el)
    // Add an 'auto' option here. HLS automatically switches sharpness based on network speed by default

    Quantity.popover.panelElement.appendChild(frag);
    Quantity.element.style.display = 'block';

    listener(hls.currentLevel)(true)
    // Initialize the current sharpness
  })

  // When the binding of the video element succeeds, load the video
  hls.loadSource('https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8')
})

hls.attachMedia(player.video)
player.mount(container.current);

const dispose = () = > {
  hls.destroy()
  player.dispose()
}
// Call Dispose to destroy the video
Copy the code

Here is the use of HLS multi-bit rate to achieve multi-definition video switching. With a few tweaks to the code, you can use NPlayer to add resolution switching to any streaming or regular MP4 video.

How to make multi-bit rate video will be published later, welcome to pay attention to.

barrage

The bullet screen function of NPlayer can keep a large number of bullets without any delay. The experience and performance of the bullet screen system are very similar to that of station B, supporting many Settings, such as anti-collision, bullet screen speed, font, speed, transparency, display area, unlimited bullet screen, etc.

The installation

Run the following command to install it as an NPM package.

npm i -S @nplayer/danmaku
Copy the code

use

import Player from "nplayer";
import Danmaku from "@nplayer/danmaku";
import items from "./items";

const danmaku = new Danmaku({ items });

const player = new Player({
  src: "https://v-cdn.zjol.com.cn/280443.mp4".plugins: [danmaku]
});

player.mount(document.body);
Copy the code

Click on this link to preview and edit: codesandbox.io/s/nplayer-d…

For more information on barrage plugins, see the section on barrage plugins.

Barrage implementation

NPlayer’s bullet screen system tries a variety of implementation schemes, and finally chooses transform and Transition in CSS3, which is also the default scheme of B station’s bullet screen. Of course, B station also supports canvas rendering, and NPlayer also tries. However, when testing a large number of bullets on Firefox, there was a bit of a lag, so I ended up with the better CSS3 solution.

In addition to the rendering mode, there are many other difficulties in the implementation of bullet screen, such as how to prevent collision of bullet screen, how to change the speed of bullet screen when the video is played at double speed, and there will be a small delay in the pause event of video, even if the delay is small, the bullet screen will have the problem of stuck position jumping when the video is paused. Of course, when the user adjusts the speed of the barrage and the video playback speed at the same time, how to ensure that the position of the barrage does not suddenly jump and other problems? NPlayer solves all of these problems and is very similar to the live barrage experience on Station B.

Space is limited here, I plan to write a follow-up ultra detailed implementation of the barrage article, welcome to pay attention.

conclusion

In addition to the above features, NPlayer has many other features, please click the link below to see more details.

If you have questions or want new features, feel free to submit an issue. PR submissions are also welcome.

  • Website: nplayer.js.org
  • Source: github.com/woopen/npla…
  • Codesandbox.io /s/ancient-s…

Related articles

  • Develop danmu video player 1 from scratch
  • Streaming Video Basics MSE Primer & FFmpeg making video preview thumbnails and FMP4
  • The original video sites such as Iyouteng are using this to play streaming media