React学习笔记(番外一)——video.js视频播放组件的入门及排坑经历

前言

很久没有静下心写博客了。近段时间接到一个任务,前端页面要加上视频播放功能。实现加排坑前后花了三天时间(别问我问什么这么久😂),觉得还是有必要记录一下的。


video.js的支持的视频格式及编码方式

这一部分有必要写在最前面,避免你看了一长串安装、引入、代码,然后发现自己想要播放的视频格式或编码video.js不支持。

支持的扩展名(格式)

从另一篇博客[1]中了解到,它支持mp4、webm、ogv、m3u8、flv、rtmp等扩展名的视频文件。

支持的视频编码

mp4为例,虽然扩展名都可以是mp4,但不同视频文件的编码可以是MPEG4、H.264等,这里要注意,video.js只支持H.264编码的mp4文件, 如果你要播放的文件编码不是H.264,需要先转换编码,或者在录制的时候设置为H.264

查看视频文件编码方式的方法:

  • Mac
    文件右键菜单 -> 显示简介 -> 更多信息 -> 编解码器
    在这里插入图片描述
  • Windows
    文件右键菜单 -> 属性

video.js的安装

现在比较知名的前端库都支持node.js,video.js也不例外,所以安装只需要:

    npm install video.js

将video.js引入React

起初按照一些博文抄代码到自己的项目,发现会有一些报错,后来耗时很久没有解决,找到了官方给的示例代码[2],简洁且跑起来没有报错。
我这里把注释翻译一下,略作改动:

自定义播放器控件

import React from 'react';
import videojs from 'video.js';
// 记得引用css文件!
import 'video.js/dist/video-js.css';

export const VideoJS = (props) => {
  // video标签的引用Hook
  const videoRef = React.useRef(null);
  // 播放器实例的引用Hook
  const playerRef = React.useRef(null);
  const {options, onReady} = props;

  React.useEffect(() => {
	  // 确保video.js的播放器实例player仅被初始化一次,否则会报错
	  if (!playerRef.current) {
	      const videoElement = videoRef.current;
	      if (!videoElement) {
	          return;
	      }
	
	      const player = playerRef.current = videojs(videoElement, options, () => {
	          videojs.log('播放器准备就绪!');
	          onReady && onReady(player);
	      });
	  // 当props发生变化时,可以对已经存在的player实例作一些操作,如:
	  } else {
	     // const player = playerRef.current;
	     // player.autoplay(options.autoplay);
	     // player.src(options.sources);
	  }
  }, [options, videoRef]);

  // 控件被unmount卸载的时候,记得要对player实例执行反初始化dispose
  React.useEffect(() => {
    const player = playerRef.current;

    return () => {
      if (player) {
        player.dispose();
        playerRef.current = null;
      }
    };
  }, [playerRef]);

  return (
    <div data-vjs-player>
      <video ref={videoRef} className='video-js vjs-big-play-centered'/>
    </div>
  );
}

export default VideoJS;

引用自定义视频播放器控件

有了上述的视频播放器控件,我们可以在任意需要播放视频的页面中引用它:

import React from 'react';

// 从控件的路径引用它,这里默认它和页面在同一目录下
import VideoJS from './VideoJS'

const App = () => {
	const playerRef = React.useRef(null);

	const videoJsOptions = {
		// 自动播放:为true时,加载完毕自动播放
		autoplay: true,
		// 播放器子控件是否显示:为true时显示暂停、播放速率等按钮
		controls: true,
		// 响应性:为true时,播放视频进度条会自动移动
		responsive: true,
		// 流式布局:为true时尽可能大得填满父标签的剩余空间
		fluid: true,
		// 视频源
		sources: [{
			// 视频文件的路径,可以是一个前端相对路径、后台视频文件URL、直播源等
			src: '/path/to/video.mp4',
			// 视频源类型
			type: 'video/mp4'
		}]
	};

	// 播放器实例化完成后的事件动作,注意!不是视频加载成功
	const handlePlayerReady = (player) => {
		playerRef.current = player;
		// 播放器的子事件在这里定义

		player.on("canplaythrough", () => {
	        console.log("视频加载完成!")
        });
        
		player.on("error", () => {
            console.log(`视频文件加载失败,请稍后重试!`);
        });
        
        player.on("stalled", () => {
            console.log(`网络异常,请稍后重试!`);
        });
	};

	return (
		<>
			<!-- ... -->
			<VideoJS options={videoJsOptions} onReady={handlePlayerReady}/>
			<!-- ... -->
		</>
	);
}

更多的播放器事件定义可以参考另一篇博文[3]


排坑记录

报错VIDEOJS ERROR (CODE4 MEDIA_ERR_SRC_NOT_SUPPORTED) No compatible source was found for this media

我自己遇到两种情况引起的这个报错:

  1. 视频源的格式或编码方式video.js真的不支持 - 这种情况只能调整视频源,转码或者替换其他前端视频播放控件。

    我当时遇到的情况是: 起初不太懂同样是MP4文件,还有编码方式的区别。幸而有多个视频源,有的可以播放,有的不可以播放。点开文件属性进行对比,发现了编码方式的区别,即上述不支持MPEG4编码的问题。
  2. HTML DOM树中没有指定的video标签 - 从上述代码中可以看到,我们需要一个<video></video>标签去初始化video.js。如果因为一些代码逻辑问题,DOM树中没有video标签,此时初始化video.js对象也会报这个错。

    我当时遇到的情况是: 一个高阶组件通过props里的参数控制渲染一个<img></img>图片标签还是<video></video>视频标签。由于js代码逻辑有漏洞,渲染<img></img>图片标签的同时通过videojs(...)初始化了一个播放器对象。

重复初始化报错

严格意义上说是一个警告,原文不记得了,大致意思就是说player对象已经初始化过一次,所以不再接受options里的新参数。

这个是因为在组件上次unmount卸载的时候没有对player对象进行销毁dispose(),按上述的代码去写,就不会有这个问题。

React底层代码报错:要删除的标签video不存在

由于dispose()函数会删除<video></video>标签,之前借鉴其他博文里通过id初始化video.js对象,dispose()的时候就报了这个错。

原本的预期应该是React底层先unmount,这个时候就删除了<video></video>标签,dispose()在其后执行就不会报错。但是借鉴了那些代码之后不知道为什么dispose()执行在unmount之前了,React底层找不到要删除的<video></video>标签,就抛错了,并且导致了页面白屏。

解决方法同上,使用官方给出的示例代码去实现就好了,不会报这样的错。


后记

首先,感谢video.js视频播放组件的开发者及贡献者。这个组件很简单易用,为音视频的门外汉节省了很多时间和代码量。

实现过程中,一开始参考一些个人博文的代码,大多数是基于class组件实现的,和我的函数式组件及React Hook框架有些水土不服。所以花了些时间在踩坑和排坑上。如果一开始就看了官方的示例,就能省些时间。另外遇到及处理视频编码的问题,也额外学习到了一些相应的知识。


  1. video 、video.js、playease.js支持的视频格式 ↩︎

  2. React and Video.js ↩︎

  3. videojs的一些监听事件汇总 ↩︎

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IMplementist

你的鼓励,是我继续写文章的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值