# 说明
有用到过视频播放的地方,由于一个 mp4 文件受限于网络等多种原因,播放效果不一定好。了解到有开源的播放器,能实现类似视频网站的自适应分辨率的功能,这里使用的是 Google 的 Shaka Player。
# 使用 Shaka player
# 下载 JS 库
到 release 页面,下载 JS 库。
打开压缩包,在 package/dist
目录下,即可找到 Shaka player 所需的 JS 文件。
shaka-player.compiled.js
播放器 SDKshaka-player.ui.js
带 UI 的播放器 SDKcontrols.css
播放器 UI css 文件
为了使用其自带的播放器 UI ,这里使用 shaka-player.ui.js
。另外 Shaka player 还不支持 hls 的播放,所以需要另外引入 mux.js
<script src="shaka/mux.min.js"></script> | |
<script src="shaka/shaka-player.ui.js"></script> | |
<link rel="stylesheet" type="text/css" href="shaka/controls.css"> |
# 初始化使用
Shaka player 通过 video
标签初始化,先添加 video
标签:
<video data-shaka-player id="video" style="width:100%;height:100%" | |
autoplay x5-video-player-type="h5" x5-video-player-fullscreen="true" | |
playsinline="true" | |
> | |
<source src="vp9.mpd" /> | |
<source src="h264.m3u8" /> | |
</video> |
可直接在 video
标签中添加 source
来指定视频文件地址,当有多种格式的时候,Shaka player 会选择当前支持的格式播放。
初始化方法官方文档已给出了详细的示例:
// 手动判断平台以加载不同的资源 | |
/** | |
let isIOS = (/iPad|iPhone|iPod/.test(navigator.platform) || | |
(navigator.platform.toUpperCase().indexOf('MAC')>=0)) && | |
!window.MSStream; | |
let manifestUri = "vp9.mpd"; | |
if (isIOS) { | |
manifestUri = "h264.m3u8"; | |
} | |
*/ | |
async function init() { | |
// When using the UI, the player is made automatically by the UI object. | |
const video = document.getElementById('video'); | |
const ui = video['ui']; | |
const controls = ui.getControls(); | |
const player = controls.getPlayer(); | |
// Attach player and ui to the window to make it easy to access in the JS console. | |
window.player = player; | |
window.ui = ui; | |
// Listen for error events. | |
player.addEventListener('error', onPlayerErrorEvent); | |
controls.addEventListener('error', onUIErrorEvent); | |
// 配置播放器按钮 | |
const uiConfig = { | |
'overflowMenuButtons' : ['quality', 'playback_rate', 'picture_in_picture', 'airplay', 'cast'] | |
}; | |
ui.configure(uiConfig); | |
// 手动加载播放地址 | |
/** | |
try { | |
await player.load(manifestUri); | |
// This runs if the asynchronous load is successful. | |
console.log('The video has now been loaded!'); | |
} catch (error) { | |
onPlayerError(error); | |
} | |
*/ | |
} | |
function onPlayerErrorEvent(errorEvent) { | |
// Extract the shaka.util.Error object from the event. | |
onPlayerError(event.detail); | |
} | |
function onPlayerError(error) { | |
// Handle player error | |
alert(error); | |
console.error('Error code', error.code, 'object', error); | |
} | |
function onUIErrorEvent(errorEvent) { | |
// Extract the shaka.util.Error object from the event. | |
onPlayerError(event.detail); | |
} | |
function initFailed(errorEvent) { | |
// Handle the failure to load; errorEvent.detail.reasonCode has a | |
// shaka.ui.FailReasonCode describing why. | |
console.error('Unable to load the UI library!'); | |
} | |
// Listen to the custom shaka-ui-loaded event, to wait until the UI is loaded. | |
document.addEventListener('shaka-ui-loaded', init); | |
// Listen to the custom shaka-ui-load-failed event, in case Shaka Player fails | |
// to load (e.g. due to lack of browser support). | |
document.addEventListener('shaka-ui-load-failed', initFailed); | |
// 微信当中自动播放。非正常操作,不一定一直有效 (⊙o⊙) | |
if (typeof window.WeixinJSBridge !== 'undefined') { | |
window.WeixinJSBridge.invoke('getNetworkType',{},function (e){ | |
// 利用该方法进行自动播放 | |
video.play(); | |
}); | |
} |
虽然使用了 Shaka player 播放视频,但对视频的播放控制并非由 Shaka player 提供,仍然使用 JS 中的 video 对象操作。
# 视频处理
Shaka player 默认支持的 vp9 编码的视频,在 Android 上支持还比较好,但在 iOS 中不能播放,所以在 iOS 中要使用 hls 播放。可以使用 ffmpeg 进行转码。
非专业 ffmpeg 用户,以下命令纯属复制,没有解释😄。
# 转 h264 编码以及不同分辨率
ffmpeg -y -i osc2.mp4 -c:v libx264 \ | |
-r 25 -x264opts 'keyint=48:min-keyint=48:no-scenecut' \ | |
-vf scale=-2:360 -b:v 560k -maxrate 560k \ | |
-movflags faststart -bufsize 8600k \ | |
-profile:v main -preset fast -an "h264_360p.mp4" |
分辨率即 scale
参数设置的,如 1080p 则设为 scale=-2:1080
,同时更高分辨率需要增大它的码率、比特率等,如:
ffmpeg -y -i osc2.mp4 -c:v libx264 \ | |
-r 25 -x264opts 'keyint=48:min-keyint=48:no-scenecut' \ | |
-vf scale=-2:1080 -b:v 4300k -maxrate 4300k \ | |
-movflags faststart -bufsize 8600k \ | |
-profile:v main -preset fast -an "h264_1080p.mp4" |
# 转 vp9 编码
ffmpeg -i osc2.mp4 -c:v libvpx-vp9 -b:v 0 -crf 30 -pass 1 -an -f null /dev/null && \ | |
ffmpeg -i osc2.mp4 -c:v libvpx-vp9 -vf scale=-2:720 -b:v 0 -crf 30 -pass 2 -c:a libopus vp9_720.webm |
这里调整分辨率依旧是 scale
参数,不同的是质量是通过 -crf
来控制的。业余的理解:它执行了两次 ffmpeg 命令,第一次会生成一个信息文件,第二次会根据这个文件进行压缩转码,以获得更好的质量和更小的体积。降低 crf 以获得更高的视频质量。
# 提取音频
Shaka player 使用 mpd 或 m3u8 播放的时候,音频是作为一个单独的轨道的,因此需要提取出音频,再与视频打包。
ffmpeg -y -i osc2.mp4 -map 0:1 -vn -c:a aac -b:a 128k -ar 48000 -ac 2 audio.m4a |
# 打包
使用 Shaka player 提供的 packager 进行打包,它将对多个视频文件进行切片并生成 mpd 或 m3u8 文件,即可加载到播放器当中使用。
packager \ | |
in=vp9_360.webm,stream=audio,init_segment='dash/audio_init.webm',segment_template='dash/audio_$Number%03d$.webm' \ | |
in=vp9_360.webm,stream=video,init_segment=dash/vp9_360_init.webm,segment_template='dash/vp9_360_$Number%03d$.webm' \ | |
in=vp9_720.webm,stream=video,init_segment=dash/vp9_720_init.webm,segment_template='dash/vp9_720_$Number%03d$.webm' \ | |
in=vp9_1080.webm,stream=video,init_segment=dash/vp9_1080_init.webm,segment_template='dash/vp9_1080_$Number%03d$.webm' \ | |
in=vp9_1440.webm,stream=video,init_segment=dash/vp9_1440_init.webm,segment_template='dash/vp9_1440_$Number%03d$.webm' \ | |
in=vp9_2160.webm,stream=video,init_segment=dash/vp9_2160_init.webm,segment_template='dash/vp9_2160_$Number%03d$.webm' \ | |
--segment_duration 3 \ | |
--generate_static_live_mpd \ | |
--mpd_output vp9.mpd |
packager \ | |
in=audio.m4a,stream=audio,init_segment=hls/audio_init.mp4,segment_template='hls/audio_$Number$.m4s' \ | |
in=h264_360p.mp4,stream=video,init_segment=hls/360p_init.mp4,segment_template='hls/360_$Number$.m4s' \ | |
in=h264_720p.mp4,stream=video,init_segment=hls/720p_init.mp4,segment_template='hls/720_$Number$.m4s' \ | |
in=h264_1080p.mp4,stream=video,init_segment=hls/1080p_init.mp4,segment_template='hls/1080_$Number$.m4s' \ | |
in=h264_1440p.mp4,stream=video,init_segment=hls/1440p_init.mp4,segment_template='hls/1440_$Number$.m4s' \ | |
in=h264_2160p.mp4,stream=video,init_segment=hls/2160p_init.mp4,segment_template='hls/2160_$Number$.m4s' \ | |
--hls_master_playlist_output h264.m3u8 |
其中第二行为音频文件,mpd 的可直接使用视频文件作为输入,它将自动提取音频。 hls 使用上面导出的音频文件。
执行完后将得到包含多个分辨率的 mpd 或 m3u8 文件,以及其视频切片。使用 Shaka player 播放,它将自动识别到不同的分辨率,可在按钮中选择,默认会根据网络加载合适的分辨率。
ffmpeg 功能强大,有众多的参数,因此也有许多不同的方式来转码视频,实现需要的效果。
~