Moved to chunk decoding.
This commit is contained in:
parent
23d1ee3ab9
commit
b8899d13b0
|
@ -1,60 +0,0 @@
|
|||
import React, { useState } from 'react';
|
||||
|
||||
export default function Test() {
|
||||
const [mediaUrl, setMediaUrl] = useState<string>();
|
||||
|
||||
const startStream = async () => {
|
||||
const source = new MediaSource();
|
||||
const url = URL.createObjectURL(source);
|
||||
setMediaUrl(url);
|
||||
|
||||
source.addEventListener('sourceopen', async () => {
|
||||
if (!source.sourceBuffers.length) {
|
||||
console.log('supported', MediaSource.isTypeSupported('video/mp4; codecs="avc1.64000d,mp4a.40.2"'));
|
||||
const sourceBuffer = source.addSourceBuffer('video/mp4; codecs="avc1.64000d,mp4a.40.2"');
|
||||
const resp = await fetch('https://nickdesaulniers.github.io/netfix/demo/frag_bunny.mp4');
|
||||
const reader = resp.body.getReader();
|
||||
new ReadableStream({
|
||||
start() {
|
||||
// The following function handles each data chunk
|
||||
function push() {
|
||||
console.log('read', source.readyState);
|
||||
// "done" is a Boolean and value a "Uint8Array"
|
||||
reader.read().then(({ done, value }) => {
|
||||
// Is there more data to read?
|
||||
if (!done) {
|
||||
sourceBuffer.appendBuffer(value);
|
||||
} else {
|
||||
console.log('close');
|
||||
source.endOfStream();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
sourceBuffer.addEventListener('updateend', () => {
|
||||
push();
|
||||
});
|
||||
|
||||
push();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
source.addEventListener('sourceended', () => {
|
||||
console.log('sourceend');
|
||||
});
|
||||
}
|
||||
|
||||
return (<div>
|
||||
<button onClick={startStream}>Stream Video</button>
|
||||
<div>
|
||||
{
|
||||
mediaUrl &&
|
||||
(<video width={640} height={360} controls>
|
||||
<source src={mediaUrl} />
|
||||
</video>)
|
||||
}
|
||||
</div>
|
||||
</div>)
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { getToken } from 'utils/common/key';
|
||||
import { file } from './fileService';
|
||||
import { file, getFile } from './fileService';
|
||||
import HTTPService from './HTTPService';
|
||||
import { getEndpoint, getFileUrl, getThumbnailUrl } from 'utils/common/apiUtil';
|
||||
import { getFileExtension } from 'utils/common/utilFunctions';
|
||||
|
@ -59,30 +59,7 @@ class DownloadManager {
|
|||
getFile = async (file: file) => {
|
||||
if (!this.fileDownloads.get(file.id)) {
|
||||
const download = (async () => {
|
||||
try {
|
||||
const resp = await HTTPService.get(
|
||||
getFileUrl(file.id),
|
||||
null,
|
||||
{ 'X-Auth-Token': this.token },
|
||||
{ responseType: 'arraybuffer' }
|
||||
);
|
||||
const worker = await new CryptoWorker();
|
||||
const decryptedFile: any = await worker.decryptFile(
|
||||
new Uint8Array(resp.data),
|
||||
await worker.fromB64(file.file.decryptionHeader),
|
||||
file.key
|
||||
);
|
||||
let decryptedFileBlob = new Blob([decryptedFile]);
|
||||
|
||||
if (getFileExtension(file.metadata.title) === TYPE_HEIC) {
|
||||
decryptedFileBlob = await this.convertHEIC2JPEG(
|
||||
decryptedFileBlob
|
||||
);
|
||||
}
|
||||
return URL.createObjectURL(decryptedFileBlob);
|
||||
} catch (e) {
|
||||
console.log('get file failed ', e);
|
||||
}
|
||||
return await getFile(this.token, file);
|
||||
})();
|
||||
this.fileDownloads.set(file.id, download);
|
||||
}
|
||||
|
|
|
@ -167,70 +167,52 @@ export const getFile = async (token: string, file: file) => {
|
|||
);
|
||||
return URL.createObjectURL(new Blob([decrypted]));
|
||||
} else {
|
||||
const source = new MediaSource();
|
||||
source.addEventListener('sourceopen', async () => {
|
||||
if (!source.sourceBuffers.length) {
|
||||
const sourceBuffer = source.addSourceBuffer('video/mp4; codecs="avc1.64000d,mp4a.40.2"');
|
||||
const resp = await fetch(`${ENDPOINT}/files/download/${file.id}?token=${token}`);
|
||||
const reader = resp.body.getReader();
|
||||
new ReadableStream({
|
||||
async start() {
|
||||
let { pullState, decryptionChunkSize, tag } = await worker.initDecryption(
|
||||
await worker.fromB64(file.file.decryptionHeader),
|
||||
file.key
|
||||
);
|
||||
console.log(pullState, decryptionChunkSize, tag);
|
||||
let data = new Uint8Array();
|
||||
// The following function handles each data chunk
|
||||
function push() {
|
||||
// "done" is a Boolean and value a "Uint8Array"
|
||||
reader.read().then(async ({ done, value }) => {
|
||||
// Is there more data to read?
|
||||
if (!done) {
|
||||
const buffer = new Uint8Array(data.byteLength + value.byteLength);
|
||||
buffer.set(new Uint8Array(data), 0);
|
||||
buffer.set(new Uint8Array(value), data.byteLength);
|
||||
if (buffer.length > decryptionChunkSize) {
|
||||
const fileData = buffer.slice(0, decryptionChunkSize);
|
||||
const { decryptedData, newTag } = await worker.decryptChunk(fileData, pullState);
|
||||
sourceBuffer.appendBuffer(decryptedData);
|
||||
tag = newTag;
|
||||
data = buffer.slice(decryptionChunkSize);
|
||||
console.log('>', decryptionChunkSize, data.length, tag);
|
||||
console.log();
|
||||
} else {
|
||||
data = buffer;
|
||||
push();
|
||||
}
|
||||
} else {
|
||||
if (data) {
|
||||
const { decryptedData } = await worker.decryptChunk(data, pullState);
|
||||
sourceBuffer.appendBuffer(decryptedData);
|
||||
data = null;
|
||||
} else {
|
||||
// console.log('end', value.length);
|
||||
console.log(source);
|
||||
// source.endOfStream();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
sourceBuffer.addEventListener('updateend', () => {
|
||||
console.log('appended');
|
||||
const resp = await fetch(`${ENDPOINT}/files/download/${file.id}?token=${token}`);
|
||||
const reader = resp.body.getReader();
|
||||
const stream = new ReadableStream({
|
||||
async start(controller) {
|
||||
console.log('start');
|
||||
const decryptionHeader = await worker.fromB64(file.file.decryptionHeader);
|
||||
const fileKey = await worker.fromB64(file.key);
|
||||
console.log(decryptionHeader, fileKey);
|
||||
let { pullState, decryptionChunkSize, tag } = await worker.initDecryption(decryptionHeader, fileKey);
|
||||
let data = new Uint8Array();
|
||||
// The following function handles each data chunk
|
||||
function push() {
|
||||
// "done" is a Boolean and value a "Uint8Array"
|
||||
reader.read().then(async ({ done, value }) => {
|
||||
// Is there more data to read?
|
||||
if (!done) {
|
||||
const buffer = new Uint8Array(data.byteLength + value.byteLength);
|
||||
buffer.set(new Uint8Array(data), 0);
|
||||
buffer.set(new Uint8Array(value), data.byteLength);
|
||||
if (buffer.length > decryptionChunkSize) {
|
||||
const fileData = buffer.slice(0, decryptionChunkSize);
|
||||
const { decryptedData, newTag } = await worker.decryptChunk(fileData, pullState);
|
||||
controller.enqueue(decryptedData);
|
||||
tag = newTag;
|
||||
data = buffer.slice(decryptionChunkSize);
|
||||
console.log('>', decryptionChunkSize, data.length, tag);
|
||||
} else {
|
||||
data = buffer;
|
||||
console.log('>', data.length);
|
||||
}
|
||||
push();
|
||||
});
|
||||
|
||||
push();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (data) {
|
||||
const { decryptedData } = await worker.decryptChunk(data, pullState);
|
||||
controller.enqueue(decryptedData);
|
||||
data = null;
|
||||
}
|
||||
controller.close();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
push();
|
||||
}
|
||||
});
|
||||
|
||||
source.addEventListener('sourceended', () => {
|
||||
console.log('sourceend');
|
||||
});
|
||||
return URL.createObjectURL(source);
|
||||
return URL.createObjectURL(await new Response(stream, { headers: { "Content-type": "video/mp4" } }).blob());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue