一、FileReader API
本地圖片預覽
<input type="file" accept="image/*" onchange="loadFile(event)" />
const loadFile = function (event) {
const reader = new FileReader();
reader.onload = function () {
const output = document.querySelector("#previewContainer");
output.src = reader.result;
};
reader.readAsDataURL(event.target.files[0]);
};
- 以上的reader.readAsDataURL用來把本地的file對象轉換成 Data URL(base64 編碼),Data URL就是file文件的一個臨時地址。
- FileReader支持把File/Blob對象轉換成Data URL 之外,還有readAsArrayBuffer() 和 readAsText()方法,把File/Blob對象轉換成其他格式
二、Blob URL。
網絡圖片預覽
const xhr = new XMLHttpRequest();
xhr.open('get', '圖片文件二進制流地址', true);
xhr.setRequestHeader('contentType', `application/png`);
xhr.responseType = 'blob';
xhr.onload = () => {
if (xhr.status === 200) {
// 接受二進制文件流
const blob = xhr.response;
const objectURL = window.URL.createObjectURL(blob);// 生成的二進制流的本地地址
image.src = objectURL;
window.URL.revokeObjectURL(objectURL) // 釋放掉blob對象
}
}
xhr.send();
它允許 Blob 或 File 對象用作圖像,下載二進制數據鏈接等的 URL 源。
- 瀏覽器內部為每個通過 URL.createObjectURL 生成的 URL 存儲了一個 「URL → Blob」 映射。因此,此類 URL 較短,但可以訪問 Blob。
- URL.revokeObjectURL(url) 方法,從內部映射中刪除引用,從而允許刪除 Blob(如果沒有其他引用),并釋放內存
網絡文件流下載
三、canvas的圖片處理
- 圖片灰度處理
const ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, 230, 230);// image繪制到頁面的 Canvas 容器
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);// 獲取的圖片像素
const data = imageData.data;
const grayscale = function () {
for (let i = 0; i < data.length; i += 4) { // 4 代表rgba4個色值
const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
data[i] = avg; // red
data[i + 1] = avg; // green
data[i + 2] = avg; // blue
}
ctx.putImageData(imageData, 0, 0);
};
- 視頻截圖canvas.toDataURL()
let ctx = canvas.getContext("2d");
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
img.src = canvas.toDataURL();
- 圖片壓縮
const imageDataURL = canvas.toDataURL(mimeType, 0.7);
// mimeType 圖片的類型 0.7壓縮比例
四、視頻流的處理
直接使用視頻地址
<video src="/xxxx.mp4"></video>
缺少了諸如視頻分段加載、視頻碼率切換、部分加載等等現代播放器應該有的功能。單純的使用URL.createObjectURL()的方式講二進制流裝換成本地地址的話,需要將流下載完畢才能進行視頻的播放,如果視頻過大的話會造成長時間的延遲,所以要使用流媒體的方式使媒體文件可以邊下載邊播放
1. 流媒體傳輸協議 HLS和DASH
- HLS工作原理是把整個流分成一個個小的基于 HTTP 的msu8文件來下載,每次只下載一些。當媒體流正在播放時,客戶端可以選擇從許多不同的備用源中以不同的速率下載同樣的資源,允許流媒體會話適應不同的數據速率。后端處理分片視頻使用ffmpeg 分割、轉碼,通過http輸出切割后的視頻文件。騰訊直播使用這種協議
- MPEG-DASH 會將內容分解成一系列小型的基于 HTTP 的MPD文件片段,每個片段包含很短長度的可播放內容,而內容總長度可能長達數小時。bilibili使用這種傳輸協議,開源了flv.js,純 JavaScript 編寫的 HTML5 Flash Video(FLV)播放器,它底層依賴于 Media Source Extensions。在實際運行過程中,它會自動解析 FLV 格式文件并喂給原生 HTML5 Video 標簽播放音視頻數據,使瀏覽器在不借助 Flash 的情況下播放 FLV 成為可能。
2. MediaSource媒體資源對象接口
const video = document.querySelector('video');
//視頻資源存放路徑,假設下面有5個分段視頻 video1.mp4 ~ video5.mp4,第一個段為初始化視頻init.mp4
const assetURL = "http://www.demo.com";
//視頻格式和編碼信息,主要為判斷瀏覽器是否支持視頻格式,但如果信息和視頻不符可能會報錯
const mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource); //將video與MediaSource綁定,此處生成一個Blob URL
mediaSource.addEventListener('sourceopen', sourceOpen); //可以理解為容器打開
} else {
//瀏覽器不支持該視頻格式
console.error('Unsupported MIME type or codec: ', mimeCodec);
}
function sourceOpen () {
const mediaSource = this;
const sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
let i = 1;
function getNextVideo(url) {
ajax(url, function(buf) {
//往容器中添加請求到的數據,不會影響當下的視頻播放。
sourceBuffer.appendBuffer(buf);
});
}
//每次appendBuffer數據更新完之后就會觸發
sourceBuffer.addEventListener("updateend", function() {
if (i === 1) {
//第一個初始化視頻加載完就開始播放
video.play();
}
if (i < 6) {
//一段視頻加載完成后,請求下一段視頻
getNextVideo(`${assetURL}/video${i}.mp4`);
}
if (i === 6) {
//全部視頻片段加載完關閉容器
mediaSource.endOfStream();
URL.revokeObjectURL(video.src); //Blob URL已經使用并加載,不需要再次使用的話可以釋放掉。
}
i++;
});
//加載初始視頻
getNextVideo(`${assetURL}/init.mp4`);
};
function ajax(url, cb) {
const xhr = new XMLHttpRequest();
xhr.open("get", url);
xhr.responseType = "arraybuffer"; // "text"-字符串 "blob"-Blob對象 "arraybuffer"-ArrayBuffer對象
xhr.onload = function() {
cb(new Uint8Array(xhr.response));
};
xhr.send();
}
文件編碼格式轉換關系
image.png
參考:
1. https://juejin.im/post/6850037275579121671#heading-14
2. https://juejin.im/post/6844904117605761031#heading-20
3. https://juejin.im/post/6846687590783909902