74

移动端视频转序列图片播放

 4 years ago
source link: https://xiaojiecong.github.io/2019/05/08/移动端视频转序列图片播放/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

项目所用5s的视频,起初使用video标签直接内嵌到页面,看起来很正常。但是在安卓浏览器会弹出小窗播放,不支持视频内嵌。

线上案例: https://mc.163.com/m/brain/

解决方案

将视频转化成序列帧,用JS控制img src的切换,视觉上达到和播放视频一样的效果。这个方法适用于短视频,建议控制在5M以内。最终导出的图片会转化成base64,然后以数组的形式存放在一个JS文件。如果视频太大的话,导出的图片就会多,那么存放base64的JS文件也将会很大,这个要根据具体情况斟酌。

1、使用 Premiere 将视频转化成序列帧

emAziem.png!web

选择合适的尺寸,宽750会比较大,可选600,640。质量选择50左右。输出格式选择JPEG,帧速率选择12-15。5s的视频,选择12帧速率,导出了60张:

qeQFRvq.png!web

2、使用node将导出的图片转化成base64

将导出的图片转化成base64,然后以数组的形式存放在一个JS文件,最终生成这个JS文件。

目录结构

|--img
|--index.js
const fs = require('fs');
const toBase64 = foldername => {
	let fileNmaeArr = fs.readdirSync(foldername);
	let strBase64 = "";
	fileNmaeArr.forEach((item, index, array) => {
		let path = foldername + '/' + item;
		let str = fs.readFileSync(path, {
			encoding: 'base64'
		})
		if (index < array.length - 1) {
			strBase64 += '\"' + str + '\"' + ",";
		} else {
			strBase64 += '\"' + str + '\"';
			let imgs = `var imgList = [${strBase64}]`;
			fs.writeFileSync('img.js', imgs);
			console.log("导出成功!")
		}
	})
}
toBase64('img')

执行 node index.js 导出 img.js

3、JS切换img标签的src,播放序列帧

ImgSequence 调用前,页面要先预加载img.js。

<img src="" id="imgVideo">
var requestAnimFrame = (function() {
	return (
		window.requestAnimationFrame ||
		window.webkitRequestAnimationFrame ||
		window.mozRequestAnimationFrame ||
		window.oRequestAnimationFrame ||
		window.msRequestAnimationFrame ||
		function(callback) {
			window.setTimeout(callback, 1000 / 60)
		}
	)
})()
var ImgSequence = function() {
	var _class = function(opt) {
		this.container = opt.container;
		this.imgArr = [];
		this.isOver = false;
		this.nowpic = opt.nowpic;
		this.stopPicIndex = 0;
		this.speed = opt.speed || 12;
		this.oldpic = -1;
		this.isLoop = opt.isLoop === false ? false : true;
	}
	_class.prototype = {
		loop: function() {
			if (this.isOver) {
				return;
			}
			var ntime = +new Date;
			var diftime = ntime - this.stime;
			this.nowpic = Math.floor(diftime * this.speed * 0.001) + this.stopPicIndex;
			if (this.nowpic == this.imgArr.length) {
				this.stopPicIndex = 0;
				if (this.isLoop) {
					this.play();
				}
				return;
			}
			requestAnimFrame(() => {
				if (+new Date - ntime > 100) { 
					this.stopPicIndex = this.nowpic;
					this.play();
				} else {
					this.loop();
				}
			});
			if (this.nowpic == this.oldpic) {
				return;
			}
			this.container.setAttribute("src", "data:image/jpg;base64," + this.imgArr[this.nowpic]);
			this.oldpic = this.nowpic;
		},
		show: function() {
			if (window["imgList"]) {
				this.container.style.display = 'block';
				this.imgArr = window["imgList"];
				this.play();
			}
		},
		play: function() {
			this.nowpic = 0;
			this.oldpic = -1;
			this.stime = +new Date;
			this.stime += this.nowpic * 1000 / this.speed;
			this.container.setAttribute("src", "data:image/jpg;base64," + this.imgArr[this.nowpic + this.stopPicIndex]);
			this.loop();
		},
		onplay: function() {
			this.isOver = false;
			this.play()
		},
		stop: function() {
			this.isOver = true;
			this.stopPicIndex = this.nowpic;
		}
	}
	return {
		init: function(opt) {
			return new _class(opt);
		}
	}
}()

var imgSequence = ImgSequence.init({
	'container': document.getElementById('imgVideo'),//必填
	'speed': 12, //可选,每秒播放多少帧,默认12 ,小于imgList的长度
	'isLoop': true //可选,默认true
})
imgSequence.show() //初始化显示并播放
imgSequence.stop() //暂停
imgSequence.onplay()//继续播放

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK