淘宝双十一 遇见十年前的自己 - 移动端视频解决方案

兼容iOS与安卓。

双十一案例:天猫双十一遇见十年前的自己

然后腾讯政务的找到我说两天要做个差不多的宣传黑龙江。我一想这么简单的东西有钱拿最主要的是还能宣传家乡那肯定妥妥的。

腾讯旅游-龙江号列车

白天还的上班,周期又太短做的太仓促有一些不完善的地方,在这用意念修复一下吧

首先看到这个案例想到的肯定是转换为canvas进行播放,但是直接使用canvas在安装上面个video一样不能自动播放,所以想到一招把视频转换为帧图片然后用js控制播放。想法很天真,不过做起来就不对了。

解决方案一

首先作为面对搜索引擎编程的我google了一下果然有现成的库canvid,使用很简单,用ffmpeg导出图片再用montage合成一下大功告成。在电脑的chrome 70.0.3538.102上测试了一下没问题,只要再把音频同步一下就 ok 了。秉着科学严谨的态度在手机上打开???

视频花了???

经过一顿瞎杰宝测试和猜测,在安卓手机上(_安卓不好使 ios 的就没测_)的精灵图大于一定尺寸以后就回出现问题,所以说要么视频必须很短,要么把长视频分割成几个短视频再用js控制播放。要求视频每一个都很短肯定是不行的,分割视频又太麻烦也不行。

解决方案二

再一次google之后发现了第二种解决方案,使用ts格式的视频。

.ts 文件格式是 MPEG 的『传输流』(transport stream),用以将视频、音频信息打包方便在有线电视网络、卫星链路、或无线电广播。这个格式最开始是用于广播的。后来它也被用在如数字录影机等场合。

简单理解就是可以做直播的那种。

在这有个现成的库:jsmpeg

使用方法很简单,API就不翻译了。原作者没有提供开始,_播放中_,结束的回调,在这把它们加上jsmpeg 增加回调

新增回调:

  • preload – 是否在实例化后马上预加载视频,autoplay设置为true时,此项将强行设置为true。 Default false.
  • onended() – 视频播放到最后一帧后回调,如果loop设置为true,则每次结束均回调。 Default undefined.
  • onended() – 视频播放到最后一帧后回调,如果loop设置为true,则每次结束均回调。 Default undefined.
  • oncanplay() – 当文件就绪可以开始播放时(缓冲已足够开始时),无论preload如何设置,这个回调都会出现。 Default undefined.
  • onpreload() – 预加载时实时回调。回传 1 个参数:加载进度,即当前加载量/所需总量。如果开启了progressive,这个回调参数的总量以第一个块的大小来算。 Default undefined.
  • onplay() – 每次从暂停或者加载完成开始播放时。 Default undefined.

之后就简单多了

安装FFmpeg

Mac os在安装的时候有可能会遇到brew的权限问题,搜一下全是解决方案,在这就不说了。

然后转换mp4文件为ts格式的。

1
ffmpeg -i in.mp4 -f mpegts -codec:v mpeg1video -codec:a mp2 -b 0 out.ts

更多参数:

1
2
3
4
ffmpeg -i in.mp4 -f mpegts \
-codec:v mpeg1video -s 960x540 -b:v 1500k -r 30 -bf 0 \
-codec:a mp2 -ar 44100 -ac 1 -b:a 128k \
out.ts

然后就可以开始写逻辑了:

1
2
3
4
5
6
7
//新建播放器
var player = new JSMpeg.Player('video.ts', {
canvas: document.querySelector('.video'),
loop: false,
autoplay: true
});
...

你以为这就完事了?

鲁迅曾经说过:喜欢js的真正原因是因为它总有事情可以做。

解决了安卓上面的问题,拿到iOS设备上一测,没声音。作者在其个人网站上有这么一段话:

Audio Unlocking on iOS

You gotta love the shit that Apple throws into Web devs faces from time to time. One of those things is the need to unlock audio on a page before you can play anything. Basically, audio playback can only be started as a response to a user action. You click on a button, audio plays.

This makes sense. I won’t argue against it. You don’t want to have audio blaring at you unannounced when you visit a page.

What makes it shitty, is that Apple neither provided a way to cleanly unlock Audio nor a way to ask the WebAudio Context if it’s unlocked already. What you do instead, is to play an Audio source and continually check if it’s progressing. You can’t chek immediately after playing, though. No, no. You have to wait a bit!

翻译过来就是:

iOS 上的音频解锁

你将要爱上苹果时不时扔到 Web 开发人员脸上的麻烦。其中之一就是在播放任何内容之前都需要在页面上解锁音频。总的来说,音频播放只能作为对用户操作的响应而启动。你点击了一个按钮,音频则播放了。

这是有道理的。我不反驳它。当你访问某个网页时,你不希望在未经通知的情况下发出声音。

是什么让它变得糟糕透顶呢?是因为苹果公司既没有提供一种利索的解锁音频的方法,也没有提供一种方法来查询 WebAudio Context 是否已经解锁。你所要做的就是播放一个音频源并不断检查是否正在顺序播放。尽管如此,在播放之后你还不能马上检查。是的,你必须等一会!

说白了就是在iOS上是不允许自动播放声音的,而且苹果公司也没提供相应的API,所以在iOS设备上还是推荐使用video解决。

如果得要用jsmpeg,这有一个hack方法

  • 在设计上诱导用户点击,然后:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var player = new JSMpeg.Player(url);
document.addEventListener("touchstart", function() {
// 手动启动audio,解除新的ios audio不能自动播放的问题
var audio = document.createElement("audio");
audio.autoplay = "autoplay";
audio.volume = 0;
// tmp.aac 是一个极短的没有声音的音频
audio.src = "tmp.aac";
// 手动触发audiocontext,让其从suspended变为running模式
player.audioOut.unlock(function() {
player.volume = 1;
player.unlockstate = true;
});
});

总的来说,要想在移动端实现视频自动播放,安卓使用类似于 jsmpeg的解决方案,iOS上依旧使用video。如果是类似于GIF那种的短视频可以使用上面提到的canvid,效果比GIF好,大小比视频小而且不会出现兼容问题。

作者

刘念

发布于

2019-11-12

更新于

2021-02-21

许可协议

评论