您当前的位置: 首页 > 学无止境 > JS经典实例 网站首页JS经典实例
js实现文件下载到内存(远程地址下载为file对象)及提取视频第一帧做为视频封面
发布时间:2020-08-08 19:46:35编辑:雪饮阅读()
有这样一个需求:
需要将一个网络地址(该地址可能是.mp4或者.mov或者干脆无后缀,但其内容就是mp4或者mov类型)。对于此种情况需要用html5的video标签去播放。
在需求的实现时候发现对于h.264的mp4即便无后缀也是ok的可以播放的,但对于mov的若没有后缀则不能播放,而且对于有后缀的mov可能由于其后端处理数据不同,则也有播放不了的情况。
问题解决:
经过实践发现先将待播放的视频下载下来后,用html中的file类型的input选择我们刚下载的文件得到的file对象用js的window.URL.createObjectURL转换后的值做为src给video标签则也都可以完美播放。
那么基于此理论,则有一个想法,我们可以通过js把远程网络地址(可理解为附件地址)中的附件下载为file对象然后用window.URL.createObjectURL转换为src给video标签。
经过一番折腾发现互联网上目前对于js下载远程附件为file对象的目前还没有成熟的方案,但有一个插件jquery-ajax-blob-arraybuffer.js可以用,虽然有说该插件存在兼容性,但目前还没有发现不支持的情况。
需求的完成:
那么我们实现该需求则如:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>js下载文件到内存</title>
<script src="jquery.min.js"></script>
<script src="jquery-ajax-blob-arraybuffer.js"></script>
<script src="layer/layer.js"></script>
<script type="text/javascript">
function base64ToBlob(base64Data) {
let arr = base64Data.split(','),
fileType = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
l = bstr.length,
u8Arr = new Uint8Array(l);
while (l--) {
u8Arr[l] = bstr.charCodeAt(l);
}
return new Blob([u8Arr], {
type: fileType
});
};
function layerLoad(){
return layer.load(1, {
shade: [0.1,'#fff'],
time:false
});
}
async function loadVideo(){
var videoUrl="https://api.testletsgomessenger.com:443/CDN/attachment/CfDJ8Na7AzXMPppGk8l7u9ETZtzzagpbUcJM8VfRE0i5Wt1FHLg72ciBFQerTzY40imMVNmYen1LWJiCmlU36Pk5WVVJpOruAT5EWw91i3y_8WSdVgropcP73sLqkyqO4CQOH4Iwxz5L6WygXfauXWFN0c-BwIAA9loT4u56M4PZbkvzWYfuKVR-afd3WVqaVZWYWg/TsvPUWlY.mov";
var load=layerLoad();
var message="";
var objectURL=await new Promise((resolve=>{
$.ajax({url:videoUrl,dataType:"blob"})
.done(function(data,status,jqXHR){
var reader = new window.FileReader();
reader.readAsDataURL(data);
reader.onloadend = function() {
var file=base64ToBlob(reader.result);
var objUrl=window.URL.createObjectURL(file);
resolve(objUrl);
};
})
.fail(function(jqXHR, textStatus) {
message=textStatus;
resolve(false);
});
}));
layer.close(load);
if(objectURL==false){
layer.msg(message);
return false;
}
$("video").attr("src",objectURL);
$("video").show();
}
$(function(){
var width=$(window).width();
var height=$(window).height();
$(".demo").css({"width":width+"px","height":height+"px","display":"flex"});
});
</script>
<style>
.demo{
align-items: center;
justify-content: center;
display:none;
flex-direction: column;
}
video{
display:none;
width:500px;
height:500px;
}
body{
overflow:hidden;
padding:0;
margin:0;
}
</style>
</head>
<body>
<div class="demo">
<button onclick="loadVideo()">加载视频</button>
<video controls="controls"></video>
</div>
</body>
</html>
需求的扩展:
完成该需求后我们的设计又说需要有一个视频封面(第二次提到这个了),第一次讲的时候我给讲了实现的难度,最后我没有实现这个功能,结果这次又提到这个,好吧,既然这样,为了争一口气,也只能迎难而上了。找到相关资料是通过canvas渲染视频拿到第一帧图片的,目前测试发现有两个问题:
(1)在微信内置浏览器中(用安卓测试的)获取到的图片是黑屏的
(2)即便用async await等也不能够在循环中使用,大概是因为dom没有完全加载ok的原因吧。
不过就目前所知我们这个需求不用考虑微信内置浏览器,微信内置浏览器真不愧被称为新一代的ie6
那么我们忽略这两个问题后的实现方法则如:
async function getVideoFirstImgFromUpload(file){
load=layerLoad();
var objUrl=window.URL.createObjectURL(file);
var $video = $(`<video controls autoplay src="${objUrl}"></video>`);
var videoElement=$video[0];
var imgData=await new Promise((resolve=>{
videoElement.addEventListener("loadeddata", function(_event) {
var canvas = document.createElement("canvas");
canvas.width = videoElement.videoWidth;
canvas.height = videoElement.videoHeight;
canvas.getContext("2d").drawImage(videoElement, 0, 0, canvas.width, canvas.height);
var firstImg=canvas.toDataURL("image/png");
console.log("第一帧图片",firstImg); //第一帧图片url
resolve(firstImg);
})
}));
layer.close(load);
return imgData;
}
坑点总结:
Js文件下载据说有兼容性、提取视频第一帧图片在微信内置浏览器中为黑屏、js的Blob接口不支持自定义name(不过影响不大)
demo下载
关键字词:js,文件下载,file对象,blob,video,封面,第一帧,远程地址,内存
下一篇:js实现阿拉伯数字转大写