diff --git a/src/ext/lib/aard/gl/GlCanvas.ts b/src/ext/lib/aard/gl/GlCanvas.ts index 6ec954d..ad4266a 100644 --- a/src/ext/lib/aard/gl/GlCanvas.ts +++ b/src/ext/lib/aard/gl/GlCanvas.ts @@ -82,6 +82,12 @@ export class GlCanvas { private programInfo: GlCanvasProgramInfo; private projectionMatrix: mat4; + get width() { + return this.canvas.width; + } + get height() { + return this.canvas.height; + } constructor(options: GlCanvasOptions) { this.canvas = document.createElement('canvas'); @@ -117,6 +123,18 @@ export class GlCanvas { return this.frameBuffer; } + /** + * Cleans up after itself + */ + destroy() { + this.gl.deleteProgram(this.programInfo.program); + this.gl.deleteBuffer(this.buffers.position); + this.gl.deleteBuffer(this.buffers.normal); + this.gl.deleteBuffer(this.buffers.textureCoord); + this.gl.deleteBuffer(this.buffers.indices); + this.gl.deleteTexture(this.texture); + } + private initWebgl() { // Initialize the GL context this.gl.clearColor(0.0, 0.0, 0.0, 1.0); diff --git a/src/ext/lib/ar-detect/ArDetector.ts b/src/ext/lib/ar-detect/ArDetector.ts index 08fe34e..f5d1db4 100644 --- a/src/ext/lib/ar-detect/ArDetector.ts +++ b/src/ext/lib/ar-detect/ArDetector.ts @@ -14,6 +14,7 @@ import Logger from '../Logger'; import VideoData from '../video-data/VideoData'; import Settings from '../Settings'; import EventBus from '../EventBus'; +import { GlCanvas } from '../aard/gl/GlCanvas'; enum VideoPlaybackState { Playing, @@ -82,11 +83,10 @@ class ArDetector { _nextTick: boolean; private animationFrameHandle: any; - private attachedCanvas: HTMLCanvasElement; - canvas: HTMLCanvasElement; - private context: CanvasRenderingContext2D; canvasImageDataRowLength: number; + glCanvas: GlCanvas; + private timers = { nextFrameCheckTime: Date.now() } @@ -189,43 +189,24 @@ class ArDetector { // // [1] initiate canvases // - - if (!cwidth) { - cwidth = this.settings.active.arDetect.canvasDimensions.sampleCanvas.width; - cheight = this.settings.active.arDetect.canvasDimensions.sampleCanvas.height; + if (this.glCanvas) { + this.glCanvas.destroy(); } - - if (this.canvas) { - this.canvas.remove(); - } - // if (this.blackframeCanvas) { - // this.blackframeCanvas.remove(); - // } - - // things to note: we'll be keeping canvas in memory only. - this.canvas = document.createElement("canvas"); - this.canvas.width = cwidth; - this.canvas.height = cheight; - // this.blackframeCanvas = document.createElement("canvas"); - // this.blackframeCanvas.width = this.settings.active.arDetect.canvasDimensions.blackframeCanvas.width; - // this.blackframeCanvas.height = this.settings.active.arDetect.canvasDimensions.blackframeCanvas.height; - - this.context = this.canvas.getContext("2d"); + this.glCanvas = new GlCanvas(this.settings.active.arDetect.canvasDimensions.sampleCanvas); // // [2] determine places we'll use to sample our main frame // - let ncol = this.settings.active.arDetect.sampling.staticCols; let nrow = this.settings.active.arDetect.sampling.staticRows; - let colSpacing = this.canvas.width / ncol; - let rowSpacing = (this.canvas.height << 2) / nrow; + let colSpacing = this.glCanvas.width / ncol; + let rowSpacing = (this.glCanvas.height << 2) / nrow; this.sampleLines = []; this.sampleCols = []; - for(let i = 0; i < ncol; i++){ + for (let i = 0; i < ncol; i++){ if(i < ncol - 1) this.sampleCols.push(Math.round(colSpacing * i)); else{ @@ -233,7 +214,7 @@ class ArDetector { } } - for(let i = 0; i < nrow; i++){ + for (let i = 0; i < nrow; i++){ if(i < ncol - 5) this.sampleLines.push(Math.round(rowSpacing * i)); else{ @@ -244,7 +225,6 @@ class ArDetector { // // [3] do other things setup needs to do // - this.resetBlackLevel(); // if we're restarting ArDetect, we need to do this in order to force-recalculate aspect ratio @@ -253,11 +233,10 @@ class ArDetector { this.canvasImageDataRowLength = cwidth << 2; this.start(); - - if(Debug.debugCanvas.enabled){ + // if(Debug.debugCanvas.enabled){ // this.debugCanvas.init({width: cwidth, height: cheight}); // DebugCanvas.draw("test marker","test","rect", {x:5, y:5}, {width: 5, height: 5}); - } + // } this.conf.arSetupComplete = true; } @@ -391,20 +370,6 @@ class ArDetector { ); } - private attachCanvas(canvas){ - if(this.attachedCanvas) - this.attachedCanvas.remove(); - - // todo: place canvas on top of the video instead of random location - canvas.style.position = "absolute"; - canvas.style.left = "200px"; - canvas.style.top = "1200px"; - canvas.style.zIndex = 10000; - - document.getElementsByTagName("body")[0] - .appendChild(canvas); - } - /** * Adds execution time sample for performance metrics * @param performanceObject @@ -749,19 +714,19 @@ class ArDetector { // aspect ratio and correct our calculations to account for that const fileAr = this.video.videoWidth / this.video.videoHeight; - const canvasAr = this.canvas.width / this.canvas.height; + const canvasAr = this.glCanvas.width / this.glCanvas.height; let widthCorrected; if (edges.top && edges.bottom) { // in case of letterbox, we take canvas height as canon and assume width got stretched or squished if (fileAr != canvasAr) { - widthCorrected = this.canvas.height * fileAr; + widthCorrected = this.glCanvas.height * fileAr; } else { - widthCorrected = this.canvas.width; + widthCorrected = this.glCanvas.width; } - return widthCorrected / (this.canvas.height - letterbox); + return widthCorrected / (this.glCanvas.height - letterbox); } } @@ -822,22 +787,19 @@ class ArDetector { return; } - if (!this.context) { + if (!this.glCanvas) { this.init(); } let sampleCols = this.sampleCols.slice(0); - - let startTime = performance.now(); - await new Promise( + const imageData = await new Promise( resolve => { - this.context.drawImage(this.video, 0, 0, this.canvas.width, this.canvas.height); - resolve(); + this.glCanvas.drawVideoFrame(this.video); + resolve(this.glCanvas.getImageData()); } ) - const imageData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height).data; timerResults.imageDrawTime = performance.now() - startTime; startTime = performance.now(); @@ -1130,7 +1092,7 @@ class ArDetector { // returns 'false' if we found a non-black edge pixel. // If we detect anything darker than blackLevel, we modify blackLevel to the new lowest value - const rowOffset = this.canvas.width * (this.canvas.height - 1); + const rowOffset = this.glCanvas.width * (this.glCanvas.height - 1); let currentMin = 255, currentMax = 0, colOffset_r, colOffset_g, colOffset_b, colOffset_rb, colOffset_gb, colOffset_bb, blthreshold = this.settings.active.arDetect.blackbar.threshold; // detect black level. if currentMax comes above blackbar + blackbar threshold, we know we aren't letterboxed diff --git a/src/ext/lib/ar-detect/GuardLine.ts b/src/ext/lib/ar-detect/GuardLine.ts index 0326948..e635021 100644 --- a/src/ext/lib/ar-detect/GuardLine.ts +++ b/src/ext/lib/ar-detect/GuardLine.ts @@ -42,7 +42,7 @@ class GuardLine { // to odstrani vse neveljavne nastavitve in vse možnosti, ki niso smiselne // this removes any configs with invalid values or values that dont make sense - if (bbTop < 0 || bbBottom >= this.aard.canvas.height ){ + if (bbTop < 0 || bbBottom >= this.aard.glCanvas.height ){ throw {error: "INVALID_SETTINGS_IN_GUARDLINE", bbTop, bbBottom} } @@ -99,7 +99,7 @@ class GuardLine { return { success: true }; } - let offset = (this.aard.canvas.width * this.settings.active.arDetect.guardLine.ignoreEdgeMargin) << 2; + let offset = (this.aard.glCanvas.width * this.settings.active.arDetect.guardLine.ignoreEdgeMargin) << 2; let offenders = []; let offenderCount = -1; // doing it this way means first offender has offenderCount==0. Ez index. @@ -117,8 +117,8 @@ class GuardLine { // <<<=======| checking upper row |========>>> - rowStart = ((edge_upper * this.aard.canvas.width) << 2) + offset; - rowEnd = rowStart + ( this.aard.canvas.width << 2 ) - (offset * 2); + rowStart = ((edge_upper * this.aard.glCanvas.width) << 2) + offset; + rowEnd = rowStart + ( this.aard.glCanvas.width << 2 ) - (offset * 2); if (Debug.debugCanvas.enabled && Debug.debugCanvas.guardLine) { // offenderCount = this._gl_debugRowCheck(image, rowStart, rowEnd, offenders, offenderCount); @@ -127,8 +127,8 @@ class GuardLine { } // <<<=======| checking lower row |========>>> - rowStart = ((edge_lower * this.aard.canvas.width) << 2) + offset; - rowEnd = rowStart + ( this.aard.canvas.width << 2 ) - (offset * 2); + rowStart = ((edge_lower * this.aard.glCanvas.width) << 2) + offset; + rowEnd = rowStart + ( this.aard.glCanvas.width << 2 ) - (offset * 2); if (Debug.debugCanvas.enabled && Debug.debugCanvas.guardLine) { // offenderCount = this._gl_debugRowCheck(image, rowStart, rowEnd, offenders, offenderCount); @@ -158,7 +158,7 @@ class GuardLine { if(!this.imageBar.top || !this.imageBar.bottom) return { success: false }; - let offset = (this.aard.canvas.width * this.settings.active.arDetect.guardLine.ignoreEdgeMargin) << 2; + let offset = (this.aard.glCanvas.width * this.settings.active.arDetect.guardLine.ignoreEdgeMargin) << 2; // TODO: implement logo check. @@ -167,14 +167,14 @@ class GuardLine { // how many non-black pixels we need to consider this check a success. We only need to detect enough pixels // on one edge (one of the edges can be black as long as both aren't) - let successThreshold = (this.aard.canvas.width * this.settings.active.arDetect.guardLine.imageTestThreshold); + let successThreshold = (this.aard.glCanvas.width * this.settings.active.arDetect.guardLine.imageTestThreshold); let rowStart, rowEnd; // <<<=======| checking upper row |========>>> - rowStart = ((edge_upper * this.aard.canvas.width) << 2) + offset; - rowEnd = rowStart + ( this.aard.canvas.width << 2 ) - (offset * 2); + rowStart = ((edge_upper * this.aard.glCanvas.width) << 2) + offset; + rowEnd = rowStart + ( this.aard.glCanvas.width << 2 ) - (offset * 2); let res = false; @@ -190,7 +190,7 @@ class GuardLine { // <<<=======| checking lower row |========>>> - rowStart = ((edge_lower * this.aard.canvas.width) << 2) + offset; + rowStart = ((edge_lower * this.aard.glCanvas.width) << 2) + offset; // rowEnd = rowStart + ( this.conf.canvas.width << 2 ) - (offset * 2); diff --git a/src/ext/lib/ar-detect/edge-detect/EdgeDetect.ts b/src/ext/lib/ar-detect/edge-detect/EdgeDetect.ts index 3d078ca..07ea2bc 100644 --- a/src/ext/lib/ar-detect/edge-detect/EdgeDetect.ts +++ b/src/ext/lib/ar-detect/edge-detect/EdgeDetect.ts @@ -2,7 +2,7 @@ import Debug from '../../../conf/Debug'; import EdgeStatus from './enums/EdgeStatusEnum'; import EdgeDetectQuality from './enums/EdgeDetectQualityEnum'; import EdgeDetectPrimaryDirection from './enums/EdgeDetectPrimaryDirectionEnum'; -import AntiGradientMode from '../../../../common/enums/AntiGradientMode.enum'; +import AntiGradientMode from '../../../../common/enums/AntiGradientMode.enum'; import ArDetector from '../ArDetector'; import Logger from '../../Logger'; import Settings from '../../Settings'; @@ -31,7 +31,7 @@ class EdgeDetect{ this.settings = ardConf.settings; this.sampleWidthBase = this.settings.active.arDetect.edgeDetection.sampleWidth << 2; // corrected so we can work on imageData - this.halfSample = this.sampleWidthBase >> 1; + this.halfSample = this.sampleWidthBase >> 1; this.detectionThreshold = this.settings.active.arDetect.edgeDetection.detectionThreshold; @@ -40,7 +40,7 @@ class EdgeDetect{ // initiates things that we may have to change later down the line init() { - + } findBars(image, sampleCols, direction = EdgeDetectPrimaryDirection.Vertical, quality = EdgeDetectQuality.Improved, guardLineOut?, blackFrameAnalysis?){ @@ -48,7 +48,7 @@ class EdgeDetect{ if (direction == EdgeDetectPrimaryDirection.Vertical) { try { fastCandidates = this.findCandidates(image, sampleCols, guardLineOut); - + if (! this.isValidSample(fastCandidates)) { return {status: EdgeStatus.ARUnknown}; } @@ -67,17 +67,17 @@ class EdgeDetect{ } return bars; - + } findCandidates(image, sampleCols, guardLineOut){ try { let upper_top, upper_bottom, lower_top, lower_bottom; - + // const cols_a = sampleCols.slice(0); const cols_a = new Array(sampleCols.length); const res_top = []; - + for (let i = 0; i < cols_a.length; i++) { cols_a[i] = { id: i, @@ -87,52 +87,52 @@ class EdgeDetect{ const cols_b = cols_a.slice(0); const res_bottom = []; - + this.colsThreshold = sampleCols.length * this.settings.active.arDetect.edgeDetection.minColsForSearch; if (this.colsThreshold == 0) this.colsThreshold = 1; - + this.blackbarThreshold = this.conf.blackLevel + this.settings.active.arDetect.blackbar.threshold; this.imageThreshold = this.blackbarThreshold + this.settings.active.arDetect.blackbar.imageThreshold; - + // if guardline didn't fail and imageDetect did, we don't have to check the upper few pixels // but only if upper and lower edge are defined. If they're not, we need to check full height if(guardLineOut){ if(guardLineOut.imageFail && !guardLineOut.blackbarFail && this.conf.guardLine.blackbar.top) { upper_top = this.conf.guardLine.blackbar.top; - upper_bottom = this.conf.canvas.height >> 1; + upper_bottom = this.conf.glCanvas.height >> 1; lower_top = upper_bottom; lower_bottom = this.conf.guardLine.blackbar.bottom; } else if (! guardLineOut.imageFail && !guardLineOut.blackbarFail && this.conf.guardLine.blackbar.top) { // ta primer se lahko zgodi tudi zaradi kakšnega logotipa. Ker nočemo, da nam en jeben - // logotip vsili reset razmerja stranic, se naredimo hrvata in vzamemo nekaj varnostnega + // logotip vsili reset razmerja stranic, se naredimo hrvata in vzamemo nekaj varnostnega // pasu preko točke, ki jo označuje guardLine.blackbar. Recimo 1/8 višine platna na vsaki strani. // a logo could falsely trigger this case, so we need to add some extra margins past // the point marked by guardLine.blackbar. Let's say 1/8 of canvas height on either side. upper_top = 0; - upper_bottom = this.conf.guardLine.blackbar.top + (this.conf.canvas.height >> 3); - lower_top = this.conf.guardLine.blackbar.bottom - (this.conf.canvas.height >> 3); - lower_bottom = this.conf.canvas.height - 1; + upper_bottom = this.conf.guardLine.blackbar.top + (this.conf.glCanvas.height >> 3); + lower_top = this.conf.guardLine.blackbar.bottom - (this.conf.glCanvas.height >> 3); + lower_bottom = this.conf.glCanvas.height - 1; } else { upper_top = 0; - upper_bottom = (this.conf.canvas.height >> 1) /*- parseInt(this.conf.canvas.height * this.settings.active.arDetect.edgeDetection.middleIgnoredArea);*/ - lower_top = (this.conf.canvas.height >> 1) /*+ parseInt(this.conf.canvas.height * this.settings.active.arDetect.edgeDetection.middleIgnoredArea);*/ - lower_bottom = this.conf.canvas.height - 1; + upper_bottom = (this.conf.glCanvas.height >> 1) /*- parseInt(this.conf.glCanvas.height * this.settings.active.arDetect.edgeDetection.middleIgnoredArea);*/ + lower_top = (this.conf.glCanvas.height >> 1) /*+ parseInt(this.conf.glCanvas.height * this.settings.active.arDetect.edgeDetection.middleIgnoredArea);*/ + lower_bottom = this.conf.glCanvas.height - 1; } } else{ upper_top = 0; - upper_bottom = (this.conf.canvas.height >> 1) /*- parseInt(this.conf.canvas.height * this.settings.active.arDetect.edgeDetection.middleIgnoredArea);*/ - lower_top = (this.conf.canvas.height >> 1) /*+ parseInt(this.conf.canvas.height * this.settings.active.arDetect.edgeDetection.middleIgnoredArea);*/ - lower_bottom = this.conf.canvas.height - 1; + upper_bottom = (this.conf.glCanvas.height >> 1) /*- parseInt(this.conf.glCanvas.height * this.settings.active.arDetect.edgeDetection.middleIgnoredArea);*/ + lower_top = (this.conf.glCanvas.height >> 1) /*+ parseInt(this.conf.glCanvas.height * this.settings.active.arDetect.edgeDetection.middleIgnoredArea);*/ + lower_bottom = this.conf.glCanvas.height - 1; } this.logger.log('info', 'arDetect', '[EdgeDetect::findCandidates] searching for candidates on ranges', upper_top, '<->', upper_bottom, ';', lower_top, '<->', lower_bottom); - + let upper_top_corrected = upper_top * this.conf.canvasImageDataRowLength; let upper_bottom_corrected = upper_bottom * this.conf.canvasImageDataRowLength; let lower_top_corrected = lower_top * this.conf.canvasImageDataRowLength; let lower_bottom_corrected = lower_bottom * this.conf.canvasImageDataRowLength; - + // if(Debug.debugCanvas.enabled){ // this._columnTest_dbgc(image, upper_top_corrected, upper_bottom_corrected, cols_a, res_top, false); // this._columnTest_dbgc(image, lower_top_corrected, lower_bottom_corrected, cols_b, res_bottom, true); @@ -140,9 +140,9 @@ class EdgeDetect{ this._columnTest3_cross(image, upper_top_corrected, upper_bottom_corrected, cols_a, res_top, false); this._columnTest3_cross(image, lower_top_corrected, lower_bottom_corrected, cols_b, res_bottom, true); // } - + this.logger.log('info', 'arDetect', '[EdgeDetect::findCandidates] candidates found -->', {res_top: res_top, res_bottom: res_bottom}); - + return {res_top: res_top, res_bottom: res_bottom}; } catch (e) { this.logger.log('error', 'debug', '[EdgeDetect::findCandidates] there was an error while finding candidates:', e); @@ -157,7 +157,7 @@ class EdgeDetect{ // NOTE: this is very simple and will need to be reworked in case we ever // go for quorum-based edge detection. (Probably not gonna happen) const topPoint = { - row: this.conf.canvas.height, + row: this.conf.glCanvas.height, gradient: false, // does current row have a gradient sample noGradient: false, // does current row have 100% confirmed edge sample } @@ -211,7 +211,7 @@ class EdgeDetect{ return true; } - + if (! topPoint.noGradient) { if (! bottomPoint.noGradient) { // top sample in both is a gradient with no solid sample present in that row @@ -220,7 +220,7 @@ class EdgeDetect{ } else { // if top gradient-only sample is closer to the edge than the bottom sample, // validation also fails. Otherwise, we can assume success. - return (topPoint.row >= this.conf.canvas.height - bottomPoint.row); + return (topPoint.row >= this.conf.glCanvas.height - bottomPoint.row); } } @@ -229,7 +229,7 @@ class EdgeDetect{ // whether gradient-only result of bottom row is closer to the edge than than the top // sample. if (! bottomPoint.noGradient) { - return (topPoint.row < this.conf.canvas.height - bottomPoint.row); + return (topPoint.row < this.conf.glCanvas.height - bottomPoint.row); } return false; @@ -238,37 +238,37 @@ class EdgeDetect{ edgeDetect(image, samples){ let edgeCandidatesTop = {count: 0}; let edgeCandidatesBottom = {count: 0}; - + let detections; - let canvasWidth = this.conf.canvas.width; - let canvasHeight = this.conf.canvas.height; - + let canvasWidth = this.conf.glCanvas.width; + let canvasHeight = this.conf.glCanvas.height; + let sampleStart, sampleEnd, loopEnd; let sampleRow_black, sampleRow_color; - + let blackEdgeViolation = false; - + let topEdgeCount = 0; let bottomEdgeCount = 0; - + try { for (const sample of samples.res_top){ blackEdgeViolation = false; // reset this - + // determine our bounds. Note that sample.col is _not_ corrected for imageData, but halfSample is sampleStart = (sample.col << 2) - this.halfSample; - + if(sampleStart < 0) sampleStart = 0; - + sampleEnd = sampleStart + this.sampleWidthBase; if (sampleEnd > this.conf.canvasImageDataRowLength) sampleEnd = this.conf.canvasImageDataRowLength; - + // calculate row offsets for imageData array sampleRow_black = (sample.black - this.settings.active.arDetect.edgeDetection.edgeTolerancePx - 1) * this.conf.canvasImageDataRowLength; sampleRow_color = (sample.black + this.settings.active.arDetect.edgeDetection.edgeTolerancePx) * this.conf.canvasImageDataRowLength; - + // že ena kršitev črnega roba pomeni, da kandidat ni primeren // even a single black edge violation means the candidate is not an edge loopEnd = sampleRow_black + sampleEnd; @@ -284,7 +284,7 @@ class EdgeDetect{ if (blackEdgeViolation) { continue; } - + detections = 0; loopEnd = sampleRow_color + sampleEnd; @@ -294,40 +294,40 @@ class EdgeDetect{ this._imageTest(image, sampleRow_color + sampleStart, loopEnd, sample.black, edgeCandidatesTop); } } - + for (const sample of samples.res_bottom){ blackEdgeViolation = false; // reset this - + // determine our bounds. Note that sample.col is _not_ corrected for imageData, but this.halfSample is sampleStart = (sample.col << 2) - this.halfSample; - + if(sampleStart < 0) sampleStart = 0; - + sampleEnd = sampleStart + this.sampleWidthBase; if(sampleEnd > this.conf.canvasImageDataRowLength) sampleEnd = this.conf.canvasImageDataRowLength; - + // calculate row offsets for imageData array sampleRow_black = (sample.black + this.settings.active.arDetect.edgeDetection.edgeTolerancePx + 1) * this.conf.canvasImageDataRowLength; sampleRow_color = (sample.black - this.settings.active.arDetect.edgeDetection.edgeTolerancePx) * this.conf.canvasImageDataRowLength; - + // že ena kršitev črnega roba pomeni, da kandidat ni primeren // even a single black edge violation means the candidate is not an edge loopEnd = sampleRow_black + sampleEnd; - + if(Debug.debugCanvas.enabled){ // blackEdgeViolation = this._blackbarTest_dbg(image, sampleRow_black + sampleStart, loopEnd); } else { blackEdgeViolation = this._blackbarTest(image, sampleRow_black + sampleStart, loopEnd); } - + // če je bila črna črta skrunjena, preverimo naslednjega kandidata // if we failed, we continue our search with the next candidate if (blackEdgeViolation) { continue; } - + detections = 0; loopEnd = sampleRow_color + sampleEnd; @@ -340,7 +340,7 @@ class EdgeDetect{ } catch (e) { this.logger.log('error', 'debug', '[EdgeDetect::edgeDetect] There was an error:', e); } - + return { edgeCandidatesTop: edgeCandidatesTop, edgeCandidatesTopCount: edgeCandidatesTop.count, @@ -352,13 +352,13 @@ class EdgeDetect{ edgePostprocess(edges){ let edgesTop = []; let edgesBottom = []; - let alignMargin = this.conf.canvas.height * this.settings.active.arDetect.allowedMisaligned; - + let alignMargin = this.conf.glCanvas.height * this.settings.active.arDetect.allowedMisaligned; + let missingEdge = edges.edgeCandidatesTopCount == 0 || edges.edgeCandidatesBottomCount == 0; - + // pretvorimo objekt v tabelo // convert objects to array - + delete(edges.edgeCandidatesTop.count); delete(edges.edgeCandidatesBottom.count); @@ -372,40 +372,40 @@ class EdgeDetect{ }); } } - + if( edges.edgeCandidatesBottomCount > 0){ for(let e in edges.edgeCandidatesBottom){ let edge = edges.edgeCandidatesBottom[e]; edgesBottom.push({ - distance: this.conf.canvas.height - edge.offset, + distance: this.conf.glCanvas.height - edge.offset, absolute: edge.offset, count: edge.count }); } } - + // sort by distance edgesTop = edgesTop.sort((a,b) => {return a.distance - b.distance}); edgesBottom = edgesBottom.sort((a,b) => {return a.distance - b.distance}); - + // če za vsako stran (zgoraj in spodaj) poznamo vsaj enega kandidata, potem lahko preverimo nekaj // stvari - + if (!missingEdge){ // predvidevamo, da je logo zgoraj ali spodaj, nikakor pa ne na obeh straneh hkrati. // če kanal logotipa/watermarka ni vključil v video, potem si bosta razdaliji (edge.distance) prvih ključev - // zgornjega in spodnjega roba približno enaki + // zgornjega in spodnjega roba približno enaki // // we'll assume that no youtube channel is rude enough to put channel logo/watermark both on top and the bottom // of the video. If logo's not included in the video, distances (edge.distance) of the first two keys should be // roughly equal. Let's check for that. if( edgesTop[0].distance >= edgesBottom[0].distance - alignMargin && edgesTop[0].distance <= edgesBottom[0].distance + alignMargin ){ - - let blackbarWidth = edgesTop[0].distance > edgesBottom[0].distance ? + + let blackbarWidth = edgesTop[0].distance > edgesBottom[0].distance ? edgesTop[0].distance : edgesBottom[0].distance; - + if (edgesTop[0].count + edgesBottom[0].count > this.settings.active.arDetect.edgeDetection.singleSideConfirmationThreshold || ( edgesTop[0].count > this.settings.active.arDetect.edgeDetection.confirmationThreshold && edgesBottom[0].count > this.settings.active.arDetect.edgeDetection.confirmationThreshold) ){ return { @@ -419,7 +419,7 @@ class EdgeDetect{ }; } } - + // torej, lahko da je na sliki watermark. Lahko, da je slika samo ornh črna. Najprej preverimo za watermark // it could be watermark. It could be a dark frame. Let's check for watermark first. if (edgesTop[0].distance < edgesBottom[0].distance && @@ -428,16 +428,16 @@ class EdgeDetect{ // možno, da je watermark zgoraj. Preverimo, če se kateri od drugih potencialnih robov na zgornjem robu // ujema s prvim spodnjim (+/- variance). Če je temu tako, potem bo verjetno watermark. Logo mora imeti // manj vzorcev kot navaden rob. - + if (edgesTop[0].length > 1){ let lowMargin = edgesBottom[0].distance - alignMargin; let highMargin = edgesBottom[0].distance + alignMargin; - + for (let i = 1; i < edgesTop.length; i++){ if(edgesTop[i].distance >= lowMargin && edgesTop[i].distance <= highMargin){ // dobili smo dejanski rob. vrnimo ga // we found the actual edge. let's return that. - let blackbarWidth = edgesTop[i].distance > edgesBottom[0].distance ? + let blackbarWidth = edgesTop[i].distance > edgesBottom[0].distance ? edgesTop[i].distance : edgesBottom[0].distance; if (edgesTop[i].count + edgesBottom[0].count > this.settings.active.arDetect.edgeDetection.singleSideConfirmationThreshold @@ -447,7 +447,7 @@ class EdgeDetect{ blackbarWidth: blackbarWidth, guardLineTop: edgesTop[i].distance, guardLineBottom: edgesBottom[0].absolute, - + top: edgesTop[i].distance, bottom: edgesBottom[0].distance }; @@ -459,18 +459,18 @@ class EdgeDetect{ if (edgesBottom[0].distance < edgesTop[0].distance && edgesBottom[0].count < edgesTop[0].count && edgesBottom[0].count < this.conf.sampleCols.length * this.settings.active.arDetect.edgeDetection.logoThreshold){ - + if(edgesBottom[0].length > 1){ let lowMargin = edgesTop[0].distance - alignMargin; let highMargin = edgesTop[0].distance + alignMargin; - + for(let i = 1; i < edgesBottom.length; i++){ if (edgesBottom[i].distance >= lowMargin && edgesTop[i].distance <= highMargin) { // dobili smo dejanski rob. vrnimo ga // we found the actual edge. let's return that. - let blackbarWidth = edgesBottom[i].distance > edgesTop[0].distance ? + let blackbarWidth = edgesBottom[i].distance > edgesTop[0].distance ? edgesBottom[i].distance : edgesTop[0].distance; - + if (edgesTop[0].count + edgesBottom[i].count > this.settings.active.arDetect.edgeDetection.singleSideConfirmationThreshold || (edgesTop[0].count > this.settings.active.arDetect.edgeDetection.singleSideConfirmationThreshold && edgesBottom[i].count > this.settings.active.arDetect.edgeDetection.confirmationThreshold)) { return { @@ -489,22 +489,22 @@ class EdgeDetect{ } } else { - // zgornjega ali spodnjega roba nismo zaznali. Imamo še en trik, s katerim lahko poskusimo + // zgornjega ali spodnjega roba nismo zaznali. Imamo še en trik, s katerim lahko poskusimo // določiti razmerje stranic // either the top or the bottom edge remains undetected, but we have one more trick that we // can try. It also tries to work around logos. - + const edgeDetectionThreshold = this.settings.active.arDetect.edgeDetection.singleSideConfirmationThreshold; - + if (edges.edgeCandidatesTopCount == 0 && edges.edgeCandidatesBottomCount != 0){ for(let edge of edgesBottom){ if(edge.count >= edgeDetectionThreshold) return { - status: EdgeStatus.ARKnown, + status: EdgeStatus.ARKnown, blackbarWidth: edge.distance, guardLineTop: null, guardLineBottom: edge.bottom, - + top: edge.distance, bottom: edge.distance } @@ -518,7 +518,7 @@ class EdgeDetect{ blackbarWidth: edge.distance, guardLineTop: edge.top, guardLineBottom: null, - + top: edge.distance, bottom: edge.distance } @@ -529,7 +529,7 @@ class EdgeDetect{ // if we reach this bit, we have failed in determining aspect ratio. It remains unknown. return {status: EdgeStatus.ARUnknown} } - + pillarTest(image){ // preverimo, če na sliki obstajajo navpične črne obrobe. Vrne 'true' če so zaznane (in če so približno enako debele), 'false' sicer. // true vrne tudi, če zaznamo preveč črnine. @@ -537,20 +537,20 @@ class EdgeDetect{ // checks the image for presence of vertical pillars. Less accurate than 'find blackbar limits'. If we find a non-black object that's // roughly centered, we return true. Otherwise we return false. // we also return true if we detect too much black - + let blackbarThreshold, upper, lower; blackbarThreshold = this.conf.blackLevel + this.settings.active.arDetect.blackbar.threshold; - - - let middleRowStart = (this.conf.canvas.height >> 1) * this.conf.canvas.width; - let middleRowEnd = middleRowStart + this.conf.canvas.width - 1; - + + + let middleRowStart = (this.conf.glCanvas.height >> 1) * this.conf.glCanvas.width; + let middleRowEnd = middleRowStart + this.conf.glCanvas.width - 1; + let rowStart = middleRowStart << 2; - let midpoint = (middleRowStart + (this.conf.canvas.width >> 1)) << 2 + let midpoint = (middleRowStart + (this.conf.glCanvas.width >> 1)) << 2 let rowEnd = middleRowEnd << 2; - + let edge_left = -1, edge_right = -1; - + // preverimo na levi strani // let's check for edge on the left side for(let i = rowStart; i < midpoint; i+=4){ @@ -559,40 +559,40 @@ class EdgeDetect{ break; } } - + // preverimo na desni strani // check on the right for(let i = rowEnd; i > midpoint; i-= 4){ if(image[i] > blackbarThreshold || image[i+1] > blackbarThreshold || image[i+2] > blackbarThreshold){ - edge_right = this.conf.canvas.width - ((i - rowStart) >> 2); + edge_right = this.conf.glCanvas.width - ((i - rowStart) >> 2); break; } } - + // če je katerikoli -1, potem imamo preveč črnine // we probably have too much black if either of those two is -1 if(edge_left == -1 || edge_right == -1){ return true; } - + // če sta oba robova v mejah merske napake, potem vrnemo 'false' // if both edges resemble rounding error, we retunr 'false' if(edge_left < this.settings.active.arDetect.pillarTest.ignoreThinPillarsPx && edge_right < this.settings.active.arDetect.pillarTest.ignoreThinPillarsPx){ return false; } - + let edgeError = this.settings.active.arDetect.pillarTest.allowMisaligned; let error_low = 1 - edgeError; let error_hi = 1 + edgeError; - + // če sta 'edge_left' in 'edge_right' podobna/v mejah merske napake, potem vrnemo true — lahko da smo našli logo na sredini zaslona // if 'edge_left' and 'edge_right' are similar enough to each other, we return true. If we found a logo in a black frame, we could - // crop too eagerly + // crop too eagerly if( (edge_left * error_low) < edge_right && (edge_left * error_hi) > edge_right ){ return true; } - + // če se ne zgodi nič od neštetega, potem nismo našli problemov // if none of the above, we haven't found a problem return false; @@ -607,8 +607,8 @@ class EdgeDetect{ // Here's a fun thing. I reckon this bit of code could potentially run often enough that L1/L2 cache misses // could really start to add up (especially if I figure the RAM usage problem which causes insane RAM usage // if you run this 30-60 times a second) - // - // so here's two functions. _columnTest3_cross has some optimization that tries to minimize cache misses, + // + // so here's two functions. _columnTest3_cross has some optimization that tries to minimize cache misses, // but the problem is that I don't actually know 100% what I'm doing so it might be pointless. It scans the // image array line-by-line, rather than column-by-column. This has some advantages (e.g. we can end the // search for letterbox early), and some disadvantages (the code is a mess) @@ -624,13 +624,13 @@ class EdgeDetect{ let tmpVal = 0; let increment, arrayStart, arrayEnd; - let loopCond, loopComparator, loopIndex; + let loopCond, loopComparator, loopIndex; if (reverseSearchDirection) { increment = -this.conf.canvasImageDataRowLength; // don't subtract this.conf.canvasImageDataRowLength — it has already been accounted for // when we calculated bottom and top - arrayStart = bottom; + arrayStart = bottom; arrayEnd = top; // this is a hack so we get pointer-like things rather than values @@ -669,7 +669,7 @@ class EdgeDetect{ // loopIndex.i could actually be loopCond.compare.i (comparator) and // loopComparator.i could actually be loopCond.index.i (real index) for (loopCond.index.i = arrayStart; loopIndex.i < loopComparator.i; loopCond.index.i += increment) { - + // če smo našli toliko mejnih točk, da s preostalimi stolpci ne moremo doseči naše meje, potem prenehamo // if we found enough edge points so that we couldn't top that limit with remaining columns, then we stop // searching forward @@ -677,7 +677,7 @@ class EdgeDetect{ if (edgeDetectColsLeft < this.colsThreshold || edgeDetectCount >= this.colsThreshold) { break; } - edgeDetectCount = 0; + edgeDetectCount = 0; // če v eni vrstici dobimo dovolj točk, ki grejo čez našo mejo zaznavanja, potem bomo nehali @@ -694,13 +694,13 @@ class EdgeDetect{ // najprej preverimo, če je piksel presegel mejo črnega robu // first we check whether blackbarThreshold was exceeded if (! colsTmp[c].blackFound) { - if( image[tmpI] > this.blackbarThreshold || + if( image[tmpI] > this.blackbarThreshold || image[tmpI + 1] > this.blackbarThreshold || image[tmpI + 2] > this.blackbarThreshold ){ - + colsTmp[c].col = colsIn[c].value; colsTmp[c].blackFound = true; - colsTmp[c].blackRow = ~~(loopCond.index.i / this.conf.canvasImageDataRowLength); + colsTmp[c].blackRow = ~~(loopCond.index.i / this.conf.canvasImageDataRowLength); // prisili, da se zanka izvede še enkrat ter preveri, // ali trenuten piksel preseže tudi imageThreshold @@ -719,13 +719,13 @@ class EdgeDetect{ // when we get a pixel over imageTreshold or gradientSampleSize, we flip the imageFound. We'll bother // with whether that's legit in analysis step, which will follow soon (tm) - if (image[tmpI] > this.imageThreshold || + if (image[tmpI] > this.imageThreshold || image[tmpI + 1] > this.imageThreshold || image[tmpI + 2] > this.imageThreshold ){ - + colsTmp[c].imageRow = ~~(loopCond.index.i / this.conf.canvasImageDataRowLength) - + colsTmp[c].imageFound = true; edgeDetectCount++; } @@ -743,7 +743,7 @@ class EdgeDetect{ colsTmp[c].imageFound = true; continue; } - + } } } @@ -770,7 +770,7 @@ class EdgeDetect{ // if we detected gradient, we'll analyse whether gradient is legit for (i = 0; i < c.diffIndex; i++) { tmpVal += c.diffs[i]; - + // if difference is negative, we aren't looking at a gradient if (c.diffs[i] < this.settings.active.arDetect.blackbar.gradientNegativeTreshold) { colsOut.push({ @@ -789,7 +789,7 @@ class EdgeDetect{ break; } - // in case neither of the previous options happens, we might have a gradient. + // in case neither of the previous options happens, we might have a gradient. // Since this column is sus af, we don't include it for further examination/ // determining aspect ratio } @@ -811,7 +811,7 @@ class EdgeDetect{ }); continue; } else { - // this means we're on a gradient. We still push an object to colsOut — this is + // this means we're on a gradient. We still push an object to colsOut — this is // important. While "bad" detection doesn't help us with determining the aspect // ratio, bad detections can prevent us from setting aspect ratio incorrectly. // for example, if we detect a gradient closer to the frame edge than a proper @@ -827,7 +827,7 @@ class EdgeDetect{ continue; } } else { - // in this case, we aren't looking at a gradient. We also aren't looking at a + // in this case, we aren't looking at a gradient. We also aren't looking at a // valid column continue; } @@ -877,18 +877,18 @@ class EdgeDetect{ continue; } tmpI = i + (colsIn[c].value << 2); - + // najprej preverimo, če je piksel presegel mejo črnega robu // first we check whether blackbarThreshold was exceeded if(! colsIn[c].blackFound) { - if( image[tmpI] > this.blackbarThreshold || + if( image[tmpI] > this.blackbarThreshold || image[tmpI + 1] > this.blackbarThreshold || image[tmpI + 2] > this.blackbarThreshold ){ - + colsOut[c].black = (i / this.conf.canvasImageDataRowLength) - 1; colsOut[c].col = colsIn[c].value; colsIn[c].blackFound = 1; - + // prisili, da se zanka izvede še enkrat ter preveri, // ali trenuten piksel preseže tudi imageThreshold // @@ -902,15 +902,15 @@ class EdgeDetect{ colsIn[c].imageFound = true; continue; } - // zatem preverimo, če je piksel presegel mejo, po kateri sklepamo, da - // predstavlja sliko. Preverimo samo, če smo v stolpcu že presegli + // zatem preverimo, če je piksel presegel mejo, po kateri sklepamo, da + // predstavlja sliko. Preverimo samo, če smo v stolpcu že presegli // blackThreshold // // then we check whether pixel exceeded imageThreshold - if (image[tmpI] > this.imageThreshold || + if (image[tmpI] > this.imageThreshold || image[tmpI + 1] > this.imageThreshold || image[tmpI + 2] > this.imageThreshold ){ - + colsOut[c].image = (i / this.conf.canvasImageDataRowLength) colsIn[c].imageFound = true; edgeDetectCount++; @@ -943,7 +943,7 @@ class EdgeDetect{ sum_avg += colsOut[c].diffs[i-1] - colsOut[c].diffs[i]; } sum_avg /= colsOut[c].diffs.length - 2; - + for (let i = 2; i <= colsOut[c].diffs; i++) { sum_avg += colsOut[c].diffs[i-1] - colsOut[c].diffs[i]; } @@ -952,18 +952,18 @@ class EdgeDetect{ } tmpI = i + (colsIn[c].value << 2); - + // najprej preverimo, če je piksel presegel mejo črnega robu // first we check whether blackbarThreshold was exceeded if(! colsIn[c].blackFound) { - if( image[tmpI] > this.blackbarThreshold || + if( image[tmpI] > this.blackbarThreshold || image[tmpI + 1] > this.blackbarThreshold || image[tmpI + 2] > this.blackbarThreshold ){ - + colsOut[c].black = (i / this.conf.canvasImageDataRowLength) - 1; colsOut[c].col = colsIn[c].value; colsIn[c].blackFound = 1; - + // prisili, da se zanka izvede še enkrat ter preveri, // ali trenuten piksel preseže tudi imageThreshold // @@ -980,18 +980,18 @@ class EdgeDetect{ colsIn[c].imageFound = true; continue; } - // zatem preverimo, če je piksel presegel mejo, po kateri sklepamo, da - // predstavlja sliko. Preverimo samo, če smo v stolpcu že presegli + // zatem preverimo, če je piksel presegel mejo, po kateri sklepamo, da + // predstavlja sliko. Preverimo samo, če smo v stolpcu že presegli // blackThreshold // // then we check whether pixel exceeded imageThreshold - if (image[tmpI] > this.imageThreshold || + if (image[tmpI] > this.imageThreshold || image[tmpI + 1] > this.imageThreshold || image[tmpI + 2] > this.imageThreshold ){ - + colsOut[c].image = (i / this.conf.canvasImageDataRowLength) - + colsIn[c].imageFound = true; edgeDetectCount++; } @@ -1022,10 +1022,10 @@ class EdgeDetect{ // najprej preverimo, če je piksel presegel mejo črnega robu // first we check whether blackbarThreshold was exceeded if(! colsIn[c].blackFound) { - if( image[tmpI] > this.blackbarThreshold || + if( image[tmpI] > this.blackbarThreshold || image[tmpI + 1] > this.blackbarThreshold || image[tmpI + 2] > this.blackbarThreshold ){ - + colsOut[c].black = (i / this.conf.canvasImageDataRowLength); colsOut[c].col = colsIn[c].value; colsIn[c].blackFound = true; @@ -1043,15 +1043,15 @@ class EdgeDetect{ colsIn[c].imageFound = true; continue; } - // zatem preverimo, če je piksel presegel mejo, po kateri sklepamo, da - // predstavlja sliko. Preverimo samo, če smo v stolpcu že presegli + // zatem preverimo, če je piksel presegel mejo, po kateri sklepamo, da + // predstavlja sliko. Preverimo samo, če smo v stolpcu že presegli // blackThreshold // // then we check whether pixel exceeded imageThreshold - if (image[tmpI] > this.imageThreshold || + if (image[tmpI] > this.imageThreshold || image[tmpI + 1] > this.imageThreshold || image[tmpI + 2] > this.imageThreshold ){ - + colsOut[c].image = (i / this.conf.canvasImageDataRowLength) colsIn[c].imageFound = true; edgeDetectCount++; @@ -1072,11 +1072,11 @@ class EdgeDetect{ for(let i = bottom - this.conf.canvasImageDataRowLength; i >= top; i-= this.conf.canvasImageDataRowLength){ for(const col of colsIn){ tmpI = i + (col << 2); - - if( image[tmpI] > this.blackbarThreshold || + + if( image[tmpI] > this.blackbarThreshold || image[tmpI + 1] > this.blackbarThreshold || image[tmpI + 2] > this.blackbarThreshold ){ - + const bottom = (i / this.conf.canvasImageDataRowLength) + 1; colsOut.push({ col: col, @@ -1092,11 +1092,11 @@ class EdgeDetect{ for(let i = top; i < bottom; i+= this.conf.canvasImageDataRowLength){ for(const col of colsIn){ tmpI = i + (col << 2); - - if( image[tmpI] > this.blackbarThreshold || + + if( image[tmpI] > this.blackbarThreshold || image[tmpI + 1] > this.blackbarThreshold || image[tmpI + 2] > this.blackbarThreshold ){ - + colsOut.push({ col: col, top: (i / this.conf.canvasImageDataRowLength) - 1 @@ -1116,11 +1116,11 @@ class EdgeDetect{ // for(let i = bottom - this.conf.canvasImageDataRowLength; i >= top; i-= this.conf.canvasImageDataRowLength){ // for(let col of colsIn){ // tmpI = i + (col << 2); - - // if( image[tmpI] > this.blackbarThreshold || + + // if( image[tmpI] > this.blackbarThreshold || // image[tmpI + 1] > this.blackbarThreshold || // image[tmpI + 2] > this.blackbarThreshold ){ - + // let bottom = (i / this.conf.canvasImageDataRowLength) + 1; // colsOut.push({ // col: col, @@ -1140,17 +1140,17 @@ class EdgeDetect{ // for(let i = top; i < bottom; i+= this.conf.canvasImageDataRowLength){ // for(let col of colsIn){ // tmpI = i + (col << 2); - - // if( image[tmpI] > this.blackbarThreshold || + + // if( image[tmpI] > this.blackbarThreshold || // image[tmpI + 1] > this.blackbarThreshold || // image[tmpI + 2] > this.blackbarThreshold ){ - + // colsOut.push({ // col: col, // top: (i / this.conf.canvasImageDataRowLength) - 1 // }); // colsIn.splice(colsIn.indexOf(col), 1); - // this.conf.debugCanvas.trace(tmpI, DebugCanvasClasses.EDGEDETECT_CANDIDATE); + // this.conf.debugCanvas.trace(tmpI, DebugCanvasClasses.EDGEDETECT_CANDIDATE); // if(tmpI-1 > 0){ // this.conf.debugCanvas.trace(tmpI - 1, DebugCanvasClasses.EDGEDETECT_CANDIDATE_SECONDARY); // } @@ -1183,7 +1183,7 @@ class EdgeDetect{ // if( image[i ] > this.blackbarThreshold || // image[i+1] > this.blackbarThreshold || // image[i+2] > this.blackbarThreshold ){ - + // this.conf.debugCanvas.trace(i, DebugCanvasClasses.VIOLATION) // return true; // } else {