giving up, idk what is wrong

This commit is contained in:
ThaUnknown 2020-11-19 19:52:58 +01:00
parent 677753d323
commit 3a0b9fbd46
6 changed files with 394 additions and 10287 deletions

View file

@ -473,7 +473,7 @@
<script src="js/rangeParser.js"></script>
<script src="js/idbkv-chunk-store.js"></script>
<script src="js/torrentHandler.js"></script>
<script src="https://cdn.jsdelivr.net/npm/matroska-subtitles@3.2.3/dist/matroska-subtitles.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/mathiasvr/matroska-subtitles@zip/dist/matroska-subtitles.min.js"></script>
<script src="js/subtitles-octopus.js"></script>
<script src="js/subtitleOctopus.js"></script>
</body>

View file

@ -14,7 +14,7 @@ function subStream(stream) {
playerData.headers = []
}
playerData.headers[track.number] = track
playerData.subtitles[track.number] = []
playerData.subtitles[track.number] = new Set()
playerData.selectedHeader = 3
} else {
playerData.tracks[track.number] = video.addTextTrack('captions', track.type, track.language);
@ -29,19 +29,21 @@ function subStream(stream) {
})
}
playerData.subtitleStream.on('subtitle', (subtitle, trackNumber) => {
console.log("subtitle")
if (playerData.headers) {
let formatSub = "Dialogue: " + subtitle.layer + "," + new Date(subtitle.time).toISOString().slice(12, -1).slice(0, -1) + "," + new Date(subtitle.time + subtitle.duration).toISOString().slice(12, -1).slice(0, -1) + "," + subtitle.style + "," + subtitle.name + "," + subtitle.marginL + "," + subtitle.marginR + "," + subtitle.marginV + "," + subtitle.effect + "," + subtitle.text
if (!playerData.subtitles[trackNumber].includes(formatSub)) {
playerData.subtitles[trackNumber].push(formatSub)
if (playerData.selectedHeader == trackNumber)
renderSubs.call(null, trackNumber)
}
} else {
if (!Object.values(playerData.tracks[trackNumber].cues).some(c => c.text == subtitle.text && c.startTime == subtitle.time / 1000 && c.endTime == (subtitle.time + subtitle.duration) / 1000)) {
let cue = new VTTCue(subtitle.time / 1000, (subtitle.time + subtitle.duration) / 1000, subtitle.text)
playerData.tracks[trackNumber].addCue(cue)
if (!playerData.subtitles[trackNumber].has(subtitle)) {
playerData.subtitles[trackNumber].add(subtitle)
// if (playerData.selectedHeader == trackNumber){
renderSubs(trackNumber, subtitle)
// }
}
}
// } else {
// if (!Object.values(playerData.tracks[trackNumber].cues).some(c => c.text == subtitle.text && c.startTime == subtitle.time / 1000 && c.endTime == (subtitle.time + subtitle.duration) / 1000)) {
// let cue = new VTTCue(subtitle.time / 1000, (subtitle.time + subtitle.duration) / 1000, subtitle.text)
// playerData.tracks[trackNumber].addCue(cue)
// }
// }
})
playerData.subtitleStream.on('file', file => {
file.mimetype == ("application/x-truetype-font" || "application/font-woff") ? playerData.fonts.push(window.URL.createObjectURL(new Blob([file.data], { type: file.mimetype }))) : ""
@ -49,13 +51,17 @@ function subStream(stream) {
stream.pipe(playerData.subtitleStream)
}
}
function renderSubs(trackNumber) {
function renderSubs(trackNumber, subtitle) {
if (trackNumber) {
var trackContent = playerData.headers[trackNumber].header.slice(0, -1) + playerData.subtitles[trackNumber].join("\n")
var trackContent = playerData.headers[trackNumber].header.slice(0, -1)
// playerData.subtitles[trackNumber].join("\n")
console.log("1")
} else {
var trackContent = playerData.headers[3].header.slice(0, -1)
console.log("2")
}
if (!playerData.octopusInstance) {
console.log("3")
let options = {
video: video,
subContent: trackContent,
@ -64,7 +70,25 @@ function renderSubs(trackNumber) {
workerUrl: 'js/subtitles-octopus-worker.js'
};
playerData.octopusInstance = new SubtitlesOctopus(options);
} else {
playerData.octopusInstance.setTrack(trackContent)
playerData.octopusInstance.getStyles()
}
console.log("4")
// playerData.octopusInstance.setTrack(trackContent)
let subObject = {
Start: subtitle.time,
Duration: subtitle.duration,
ReadOrder: playerData.subtitles[trackNumber].size - 1,
Layer: parseInt(subtitle.layer),
Style: 1, //playerData.styles.findIndex(style => style.Name == subtitle.style) + 1 ||
Name: subtitle.name || "",
MarginL: parseInt(subtitle.marginL),
MarginR: parseInt(subtitle.marginR),
MarginV: parseInt(subtitle.marginV),
Effect: subtitle.effect || "",
Text: subtitle.text
}
console.log(subObject)
playerData.octopusInstance.createEvent(subObject)
playerData.octopusInstance.getEvents()
}

File diff suppressed because one or more lines are too long

Binary file not shown.

View file

@ -9,10 +9,23 @@ var SubtitlesOctopus = function (options) {
}
} catch (e) {
}
console.log("WebAssembly support detected: " + (supportsWebAssembly ? "yes" : "no"));
var self = this;
self.canvas = options.canvas; // HTML canvas element (optional if video specified)
self.lossyRender = options.lossyRender; // Speedup render for heavy subs
self.renderMode = options.renderMode || (options.lossyRender ? 'fast' : (options.blendRender ? 'blend' : 'normal'));
// play with those when you need some speed, e.g. for slow devices
self.dropAllAnimations = options.dropAllAnimations || false;
self.libassMemoryLimit = options.libassMemoryLimit || 0; // set libass bitmap cache memory limit in MiB (approximate)
self.libassGlyphLimit = options.libassGlyphLimit || 0; // set libass glyph cache memory limit in MiB (approximate)
self.targetFps = options.targetFps || 60;
self.prescaleTradeoff = options.prescaleTradeoff || null; // render subtitles less than viewport when less than 1.0 to improve speed, render to more than 1.0 to improve quality; set to null to disable scaling
self.softHeightLimit = options.softHeightLimit || 1080; // don't apply prescaleTradeoff < 1 when viewport height is less that this limit
self.hardHeightLimit = options.hardHeightLimit || 2160; // don't ever go above this limit
self.resizeVariation = options.resizeVariation || 0.2; // by how many a size can vary before it would cause clearance of prerendered buffer
self.renderAhead = options.renderAhead || 0; // how many MiB to render ahead and store; 0 to disable (approximate)
self.isOurCanvas = false; // (internal) we created canvas and manage it
self.video = options.video; // HTML video element (optional if canvas specified)
self.canvasParent = null; // (internal) HTML canvas parent element
@ -33,9 +46,21 @@ var SubtitlesOctopus = function (options) {
self.timeOffset = options.timeOffset || 0; // Time offset would be applied to currentTime from video (option)
self.renderedItems = []; // used to store items rendered ahead when renderAhead > 0
self.renderAhead = self.renderAhead * 1024 * 1024 * 0.9 /* try to eat less than requested */;
self.oneshotState = {
eventStart: null,
eventOver: false,
iteration: 0,
renderRequested: false,
requestNextTimestamp: -1,
prevWidth: null,
prevHeight: null
}
self.hasAlphaBug = false;
(function () {
(function() {
if (typeof ImageData.prototype.constructor === 'function') {
try {
// try actually calling ImageData, as on some browsers it's reported
@ -98,12 +123,17 @@ var SubtitlesOctopus = function (options) {
URL: document.URL,
currentScript: self.workerUrl,
preMain: true,
fastRender: self.lossyRender,
renderMode: self.renderMode,
subUrl: self.subUrl,
subContent: self.subContent,
fonts: self.fonts,
availableFonts: self.availableFonts,
debug: self.debug
debug: self.debug,
targetFps: self.targetFps,
libassMemoryLimit: self.libassMemoryLimit,
libassGlyphLimit: self.libassGlyphLimit,
renderOnDemand: self.renderAhead > 0,
dropAllAnimations: self.dropAllAnimations
});
};
@ -173,6 +203,9 @@ var SubtitlesOctopus = function (options) {
self.video.addEventListener("seeked", function () {
self.video.addEventListener("timeupdate", timeupdate, false);
self.setCurrentTime(video.currentTime + self.timeOffset);
if (self.renderAhead > 0) {
_cleanPastRendered(video.currentTime + self.timeOffset, true);
}
}, false);
self.video.addEventListener("ratechange", function () {
self.setRate(video.playbackRate);
@ -231,6 +264,189 @@ var SubtitlesOctopus = function (options) {
self.subUrl = subUrl;
};
function _cleanPastRendered(currentTime, seekClean) {
var retainedItems = [];
for (var i = 0, len = self.renderedItems.length; i < len; i++) {
var item = self.renderedItems[i];
if (item.emptyFinish < 0 || item.emptyFinish >= currentTime) {
// item is not yet finished, retain it
retainedItems.push(item);
}
}
if (seekClean && retainedItems.length > 0) {
// items are ordered by event start time when we push to self.renderedItems,
// so first item is the earliest
if (currentTime < retainedItems[0].eventStart) {
if (retainedItems[0].eventStart - currentTime > 60) {
console.info("seeked back too far, cleaning prerender buffer");
retainedItems = [];
} else {
console.info("seeked backwards, need to free up some buffer");
var size = 0, limit = self.renderAhead * 0.3 /* try to take no more than 1/3 of buffer */;
var retain = [];
for (var i = 0, len = retainedItems.length; i < len; i++) {
var item = retainedItems[i];
size += item.size;
if (size >= limit) break;
retain.push(item);
}
retainedItems = retain;
}
}
}
var removed = retainedItems.length < self.renderedItems;
self.renderedItems = retainedItems;
return removed;
}
function tryRequestOneshot(currentTime, renderNow) {
if (!self.renderAhead || self.renderAhead <= 0) return;
if (self.oneshotState.renderRequested && !renderNow) return;
if (typeof currentTime === 'undefined') {
if (!self.video) return;
currentTime = self.video.currentTime + self.timeOffset;
}
var size = 0;
for (var i = 0, len = self.renderedItems.length; i < len; i++) {
var item = self.renderedItems[i];
if (item.emptyFinish < 0) {
console.info('oneshot already reached end-of-events');
return;
}
if (currentTime >= item.eventStart && currentTime < item.emptyFinish) {
// an event for requested time already exists
console.debug('not requesting a render for ' + currentTime +
' as event already covering it exists (start=' +
item.eventStart + ', empty=' + item.emptyFinish + ')');
return;
}
size += item.size;
}
if (size <= self.renderAhead) {
lastRendered = currentTime - (renderNow ? 0 : 0.001);
if (!self.oneshotState.renderRequested) {
self.oneshotState.renderRequested = true;
self.worker.postMessage({
target: 'oneshot-render',
lastRendered: lastRendered,
renderNow: renderNow,
iteration: self.oneshotState.iteration
});
} else {
if (self.workerActive) {
console.info('worker busy, requesting to seek');
}
self.oneshotState.requestNextTimestamp = lastRendered;
}
}
}
function _renderSubtitleEvent(event, currentTime) {
var eventOver = event.eventFinish < currentTime;
if (self.oneshotState.eventStart == event.eventStart && self.oneshotState.eventOver == eventOver) return;
self.oneshotState.eventStart = event.eventStart;
self.oneshotState.eventOver = eventOver;
var beforeDrawTime = performance.now();
if (event.viewport.width != self.canvas.width || event.viewport.height != self.canvas.height) {
self.canvas.width = event.viewport.width;
self.canvas.height = event.viewport.height;
}
self.ctx.clearRect(0, 0, self.canvas.width, self.canvas.height);
if (!eventOver) {
for (var i = 0; i < event.items.length; i++) {
var image = event.items[i];
self.bufferCanvas.width = image.w;
self.bufferCanvas.height = image.h;
self.bufferCanvasCtx.putImageData(image.image, 0, 0);
self.ctx.drawImage(self.bufferCanvas, image.x, image.y);
}
}
if (self.debug) {
var drawTime = Math.round(performance.now() - beforeDrawTime);
console.log('render: ' + Math.round(event.spentTime - event.blendTime) + ' ms, blend: ' + Math.round(event.blendTime) + ' ms, draw: ' + drawTime + ' ms');
}
}
function oneshotRender() {
window.requestAnimationFrame(oneshotRender);
if (!self.video) return;
var currentTime = self.video.currentTime + self.timeOffset;
var finishTime = -1, eventShown = false, animated = false;
for (var i = 0, len = self.renderedItems.length; i < len; i++) {
var item = self.renderedItems[i];
if (!eventShown && item.eventStart <= currentTime && (item.emptyFinish < 0 || item.emptyFinish > currentTime)) {
_renderSubtitleEvent(item, currentTime);
eventShown = true;
finishTime = item.emptyFinish;
} else if (finishTime >= 0) {
// we've already found a known event, now find
// the farthest point of consequent events
// NOTE: self.renderedItems may have gaps due to seeking
if (item.eventStart - finishTime < 0.01) {
finishTime = item.emptyFinish;
animated = item.animated;
} else {
break;
}
}
}
if (!eventShown) {
if (Math.abs(self.oneshotState.requestNextTimestamp - currentTime) > 0.01) {
_cleanPastRendered(currentTime);
tryRequestOneshot(currentTime, true);
}
} else if (_cleanPastRendered(currentTime) && finishTime >= 0) {
tryRequestOneshot(finishTime, animated);
}
}
self.resetRenderAheadCache = function (isResizing) {
if (self.renderAhead > 0) {
var newCache = [];
if (isResizing && self.oneshotState.prevHeight && self.oneshotState.prevWidth) {
if (self.oneshotState.prevHeight == self.canvas.height &&
self.oneshotState.prevWidth == self.canvas.width) return;
var timeLimit = 10, sizeLimit = self.renderAhead * 0.3;
if (self.canvas.height >= self.oneshotState.prevHeight * (1.0 - self.resizeVariation) &&
self.canvas.height <= self.oneshotState.prevHeight * (1.0 + self.resizeVariation) &&
self.canvas.width >= self.oneshotState.prevWidth * (1.0 - self.resizeVariation) &&
self.canvas.width <= self.oneshotState.prevWidth * (1.0 + self.resizeVariation)) {
console.debug('viewport changes are small, leaving more of prerendered buffer');
timeLimit = 30;
sizeLimit = self.renderAhead * 0.5;
}
var stopTime = self.video.currentTime + self.timeOffset + timeLimit;
var size = 0;
for (var i = 0; i < self.renderedItems.length; i++) {
var item = self.renderedItems[i];
if (item.emptyFinish < 0 || item.emptyFinish >= stopTime) break;
size += item.size;
if (size >= sizeLimit) break;
newCache.push(item);
}
}
console.info('resetting prerender cache');
self.renderedItems = newCache;
self.oneshotState.eventStart = null;
self.oneshotState.iteration++;
self.oneshotState.renderRequested = false;
self.oneshotState.prevHeight = self.canvas.height;
self.oneshotState.prevWidth = self.canvas.width;
window.requestAnimationFrame(oneshotRender);
tryRequestOneshot(undefined, true);
}
}
self.renderFrameData = null;
function renderFrames() {
var data = self.renderFramesData;
@ -252,7 +468,12 @@ var SubtitlesOctopus = function (options) {
}
if (self.debug) {
var drawTime = Math.round(performance.now() - beforeDrawTime);
console.log(Math.round(data.spentTime) + ' ms (+ ' + drawTime + ' ms draw)');
var blendTime = data.blendTime;
if (typeof blendTime !== 'undefined') {
console.log('render: ' + Math.round(data.spentTime - blendTime) + ' ms, blend: ' + Math.round(blendTime) + ' ms, draw: ' + drawTime + ' ms; TOTAL=' + Math.round(data.spentTime + drawTime) + ' ms');
} else {
console.log(Math.round(data.spentTime) + ' ms (+ ' + drawTime + ' ms draw)');
}
self.renderStart = performance.now();
}
}
@ -350,6 +571,86 @@ var SubtitlesOctopus = function (options) {
self.canvas[data.object][data.property] = data.value;
break;
}
case 'oneshot-result': {
if (data.iteration != self.oneshotState.iteration) {
console.debug('received stale prerender, ignoring');
return;
}
if (self.debug) {
console.info('oneshot received (start=' +
data.eventStart + ', empty=' + data.emptyFinish +
'), render: ' + Math.round(data.spentTime) + ' ms');
}
self.oneshotState.renderRequested = false;
if (Math.abs(data.lastRenderedTime - self.oneshotState.requestNextTimestamp) < 0.01) {
self.oneshotState.requestNextTimestamp = -1;
}
if (data.eventStart - data.lastRenderedTime > 0.01) {
// generate bogus empty element, so all timeline is covered anyway
self.renderedItems.push({
eventStart: data.lastRenderedTime,
eventFinish: data.lastRenderedTime - 0.001,
emptyFinish: data.eventStart,
viewport: data.viewport,
spentTime: 0,
blendTime: 0,
items: [],
animated: false,
size: 0
});
}
var items = [];
var size = 0;
for (var i = 0, len = data.canvases.length; i < len; i++) {
var item = data.canvases[i];
items.push({
w: item.w,
h: item.h,
x: item.x,
y: item.y,
image: new ImageData(new Uint8ClampedArray(item.buffer), item.w, item.h)
});
size += item.buffer.byteLength;
}
var eventSplitted = false;
if ((data.emptyFinish > 0 && data.emptyFinish - data.eventStart < 1.0 / self.targetFps) || data.animated) {
var newFinish = data.eventStart + 1.0 / self.targetFps;
data.emptyFinish = newFinish;
data.eventFinish = newFinish;
eventSplitted = true;
}
self.renderedItems.push({
eventStart: data.eventStart,
eventFinish: data.eventFinish,
emptyFinish: data.emptyFinish,
spentTime: data.spentTime,
blendTime: data.blendTime,
viewport: data.viewport,
items: items,
animated: data.animated,
size: size
});
self.renderedItems.sort(function (a, b) {
return a.eventStart - b.eventStart;
});
if (self.oneshotState.requestNextTimestamp >= 0) {
// requesting an out of order event render
tryRequestOneshot(self.oneshotState.requestNextTimestamp, true);
} else if (data.eventStart < 0) {
console.info('oneshot received "end of frames" event');
} else if (data.emptyFinish >= 0) {
// there's some more event to render, try requesting next event
tryRequestOneshot(data.emptyFinish, eventSplitted);
} else {
console.info('there are no more events to prerender');
}
break;
}
default:
throw 'eh?';
}
@ -383,6 +684,7 @@ var SubtitlesOctopus = function (options) {
break;
}
case 'get-styles': {
console.log(data.target);
console.log(data.styles);
playerData.styles = data.styles
break;
@ -392,14 +694,48 @@ var SubtitlesOctopus = function (options) {
}
};
function _computeCanvasSize(width, height) {
if (self.prescaleTradeoff === null) {
if (height > self.hardHeightLimit) {
width = width * self.hardHeightLimit / height;
height = self.hardHeightLimit;
}
} else if (self.prescaleTradeoff > 1) {
if (height * self.prescaleTradeoff <= self.softHeightLimit) {
width *= self.prescaleTradeoff;
height *= self.prescaleTradeoff;
} else if (height < self.softHeightLimit) {
width = width * self.softHeightLimit / height;
height = self.softHeightLimit;
} else if (height >= self.hardHeightLimit) {
width = width * self.hardHeightLimit / height;
height = self.hardHeightLimit;
}
} else if (height >= self.softHeightLimit) {
if (height * self.prescaleTradeoff <= self.softHeightLimit) {
width = width * self.softHeightLimit / height;
height = self.softHeightLimit;
} else if (height * self.prescaleTradeoff <= self.hardHeightLimit) {
width *= self.prescaleTradeoff;
height *= self.prescaleTradeoff;
} else {
width = width * self.hardHeightLimit / height;
height = self.hardHeightLimit;
}
}
return {'width': width, 'height': height};
}
self.resize = function (width, height, top, left) {
var videoSize = null;
top = top || 0;
left = left || 0;
if ((!width || !height) && self.video) {
videoSize = self.getVideoPosition();
width = videoSize.width * self.pixelRatio;
height = videoSize.height * self.pixelRatio;
var newsize = _computeCanvasSize(videoSize.width * self.pixelRatio, videoSize.height * self.pixelRatio);
width = newsize.width;
height = newsize.height;
var offset = self.canvasParent.getBoundingClientRect().top - self.video.getBoundingClientRect().top;
top = videoSize.y - offset;
left = videoSize.x;
@ -413,10 +749,10 @@ var SubtitlesOctopus = function (options) {
if (
self.canvas.width != width ||
self.canvas.height != height ||
self.canvas.style.top != top ||
self.canvas.style.left != left
self.canvas.width != width ||
self.canvas.height != height ||
self.canvas.style.top != top ||
self.canvas.style.left != left
) {
self.canvas.width = width;
self.canvas.height = height;
@ -437,6 +773,7 @@ var SubtitlesOctopus = function (options) {
width: self.canvas.width,
height: self.canvas.height
});
self.resetRenderAheadCache(true);
}
};
@ -471,6 +808,7 @@ var SubtitlesOctopus = function (options) {
target: 'set-track-by-url',
url: url
});
self.resetRenderAheadCache(false);
};
self.setTrack = function (content) {
@ -478,12 +816,14 @@ var SubtitlesOctopus = function (options) {
target: 'set-track',
content: content
});
self.resetRenderAheadCache(false);
};
self.freeTrack = function (content) {
self.worker.postMessage({
target: 'free-track'
});
self.resetRenderAheadCache(false);
};

View file

@ -147,12 +147,12 @@ function postDownload(file) {
subtitles = []
parser.once('tracks', pTracks => {
pTracks.forEach(track => {
subtitles[track.number] = []
subtitles[track.number] = new Set()
})
})
parser.on('subtitle', (subtitle, trackNumber) => {
if (playerData.headers) {
subtitles[trackNumber].push("Dialogue: " + subtitle.layer + "," + new Date(subtitle.time).toISOString().slice(12, -1).slice(0, -1) + "," + new Date(subtitle.time + subtitle.duration).toISOString().slice(12, -1).slice(0, -1) + "," + subtitle.style + "," + subtitle.name + "," + subtitle.marginL + "," + subtitle.marginR + "," + subtitle.marginV + "," + subtitle.effect + "," + subtitle.text)
subtitles[trackNumber].add("Dialogue: " + subtitle.layer + "," + new Date(subtitle.time).toISOString().slice(12, -1).slice(0, -1) + "," + new Date(subtitle.time + subtitle.duration).toISOString().slice(12, -1).slice(0, -1) + "," + subtitle.style + "," + subtitle.name + "," + subtitle.marginL + "," + subtitle.marginR + "," + subtitle.marginV + "," + subtitle.effect + "," + subtitle.text)
} else if (!Object.values(playerData.tracks[trackNumber].cues).some(c => c.text == subtitle.text && c.startTime == subtitle.time / 1000 && c.endTime == (subtitle.time + subtitle.duration) / 1000)) {
let cue = new VTTCue(subtitle.time / 1000, (subtitle.time + subtitle.duration) / 1000, subtitle.text)
playerData.tracks[trackNumber].addCue(cue)