UNPKG

webm-duration-fix-electron

Version:

based on ts-ebml and support large file(than 2GB) and optimize memory usage during repair

143 lines (127 loc) 4.19 kB
import { tools, Decoder, Reader } from './ebml'; const mimeType = 'video/webm\;'; /** * based on ts-ebml and support large file,optimize memory usage during repair * * @param blob the blob you need to fix * @returns the blob that has been fixed * */ export async function fixWebmDuration(blob: Blob): Promise<Blob> { if (!blob) { throw Error('call to fixWebmDuration requires a blob'); } const decoder = new Decoder(); const reader = new Reader(); const readstream = blob.stream() as any; const readerBlob = readstream.getReader(); while (true) { let { done, value } = await readerBlob.read(); if (done) { reader.stop(); break; } let elms = decoder.decode(value); // As browser upgrade webm meta attributes are gradually added, // so filter unknown type to bypass this issue. elms = elms?.filter(elm => elm.type !== 'unknown') elms.forEach(elm => { reader.read(elm) }); value = null; } const refinedMetadataBuf = tools.makeMetadataSeekable(reader.metadatas, reader.duration, reader.cues); const refinedMetadataBlob = new Blob([refinedMetadataBuf], { type: mimeType }); const firstPartBlobWithoutMetadata = blob.slice(reader.metadataSize); const finalBlob = new Blob([refinedMetadataBlob, firstPartBlobWithoutMetadata], { type: mimeType }); return finalBlob; } interface Callback { (size : number , blobWithHeader : Blob) : void; } export class FixWebmProcess { private _processBlob : Blob; private _nextBlob : Blob[]; private _end : boolean; private _decoder : Decoder; private _reader : Reader; private _finish : boolean; private _callback : Callback; private _enableLog : boolean; constructor() { this._end = true; this._decoder = new Decoder(); this._reader = new Reader(); this._processBlob = new Blob(); this._nextBlob = []; this._finish = false; this._callback = (size : number , blobWithHeader : Blob) => {}; this._enableLog = true; // this._MyBlob = new Blob(); } public processBlob(blob : Blob) : void { if (this._end) { this._processBlob = new Blob([blob], {type : mimeType}); this._end = false; this.fixWebmDuration() } else { this._nextBlob[this._nextBlob.length] = blob; } } private async fixWebmDuration() : Promise<void> { if (!this._processBlob) { throw Error('call to fixWebmDuration requires a blob'); } let readstream = this._processBlob.stream() as any; let readerBlob = readstream.getReader(); while (true) { let { done, value } = await readerBlob.read(); if (done) { if (this._nextBlob.length == 0) { this._end = true; if (this._finish) { this.LOG('<FixWebmProcess> finish from fixWebmDuration') this.finish(this._callback); } break; } else { this._processBlob = this._nextBlob.shift() as Blob; readstream = this._processBlob.stream() as any; readerBlob = readstream.getReader(); continue; } } let elms = this._decoder.decode(value); // As browser upgrade webm meta attributes are gradually added, // so filter unknown type to bypass this issue. elms = elms?.filter(elm => elm.type !== 'unknown') elms.forEach(elm => { this._reader.read(elm) }); value = null; } } private LOG(log : String) { if (this._enableLog) { console.log(log); } } public finish(callback : Callback) { this._finish = true; this._callback = callback; this.LOG('<FixWebmProcess> call finish') if (this._end) { this.LOG('<FixWebmProcess> finish from finish function') this._reader.stop(); this.fixBlob(); } } public setEnableLog(enable : boolean) { this._enableLog = enable; } private fixBlob() { const refinedMetadataBuf = tools.makeMetadataSeekable(this._reader.metadatas, this._reader.duration, this._reader.cues); const refinedMetadataBlob = new Blob([refinedMetadataBuf], { type: mimeType }); this._callback(this._reader.metadataSize, refinedMetadataBlob); } }