Aard should be nominally complete. Probably.

This commit is contained in:
Tamius Han 2024-10-22 23:43:25 +02:00
parent 7c5e4101b0
commit bf182c65ad
3 changed files with 103 additions and 66 deletions

View File

@ -8,7 +8,7 @@ import { GlCanvas } from './gl/GlCanvas';
import { AardCanvasStore } from './interfaces/aard-canvas-store.interface'; import { AardCanvasStore } from './interfaces/aard-canvas-store.interface';
import { AardDetectionSample, generateSampleArray } from './interfaces/aard-detection-sample.interface'; import { AardDetectionSample, generateSampleArray } from './interfaces/aard-detection-sample.interface';
import { AardStatus, initAardStatus } from './interfaces/aard-status.interface'; import { AardStatus, initAardStatus } from './interfaces/aard-status.interface';
import { AardTestResults, initAardTestResults } from './interfaces/aard-test-results.interface'; import { AardTestResults, initAardTestResults, resetAardTestResults } from './interfaces/aard-test-results.interface';
import { AardTimers, initAardTimers } from './interfaces/aard-timers.interface'; import { AardTimers, initAardTimers } from './interfaces/aard-timers.interface';
@ -214,7 +214,7 @@ class Aard {
//#region configuration parameters //#region configuration parameters
private logger: Logger; private logger: Logger;
private conf: VideoData; private videoData: VideoData;
private settings: Settings; private settings: Settings;
private eventBus: EventBus; private eventBus: EventBus;
private arid: string; private arid: string;
@ -256,7 +256,7 @@ class Aard {
//#region lifecycle //#region lifecycle
constructor(videoData: VideoData){ constructor(videoData: VideoData){
this.logger = videoData.logger; this.logger = videoData.logger;
this.conf = videoData; this.videoData = videoData;
this.video = videoData.video; this.video = videoData.video;
this.settings = videoData.settings; this.settings = videoData.settings;
this.eventBus = videoData.eventBus; this.eventBus = videoData.eventBus;
@ -284,6 +284,10 @@ class Aard {
} }
} }
/**
* Initializes Aard with default values and starts autodetection loop.
* This method should only ever be called from constructor.
*/
private init() { private init() {
this.canvasStore = { this.canvasStore = {
main: new GlCanvas(new GlCanvas(this.settings.active.arDetect.canvasDimensions.sampleCanvas)), main: new GlCanvas(new GlCanvas(this.settings.active.arDetect.canvasDimensions.sampleCanvas)),
@ -300,16 +304,17 @@ class Aard {
), ),
}; };
this.start(); this.start();
} }
//#endregion //#endregion
/**
* Starts autodetection loop.
*/
start() { start() {
if (this.conf.resizer.lastAr.type === AspectRatioType.AutomaticUpdate) { if (this.videoData.resizer.lastAr.type === AspectRatioType.AutomaticUpdate) {
// ensure first autodetection will run in any case // ensure first autodetection will run in any case
this.conf.resizer.lastAr = {type: AspectRatioType.AutomaticUpdate, ratio: this.defaultAr}; this.videoData.resizer.lastAr = {type: AspectRatioType.AutomaticUpdate, ratio: this.defaultAr};
} }
if (this.animationFrame) { if (this.animationFrame) {
@ -318,15 +323,63 @@ class Aard {
this.status.aardActive = true; this.status.aardActive = true;
this.animationFrame = window.requestAnimationFrame( (ts: DOMHighResTimeStamp) => this.onAnimationFrame(ts)); this.animationFrame = window.requestAnimationFrame( (ts: DOMHighResTimeStamp) => this.onAnimationFrame(ts));
// this.logger.log('info', 'debug', `"%c[ArDetect::startLoop] <@${this.arid}> AARD loop started.`, _ard_console_start); }
/**
* Runs autodetection ONCE.
* If autodetection loop is running, this will also stop autodetection loop.
*/
step() {
this.stop();
this.main();
}
/**
* Stops autodetection.
*/
stop() {
if (this.animationFrame) {
window.cancelAnimationFrame(this.animationFrame);
}
}
//#region animationFrame, scheduling, and other shit
/**
* Checks whether conditions for granting a frame check are fulfilled
* @returns
*/
private canTriggerFrameCheck() {
// if (this._paused || this._halted || this._exited) {
// return false;
// }
// if video was paused & we know that we already checked that frame,
// we will not check it again.
const videoState = this.getVideoPlaybackState();
if (videoState !== VideoPlaybackState.Playing) {
if (this.status.lastVideoStatus === videoState) {
return false;
}
}
this.status.lastVideoStatus = videoState;
if (Date.now() < this.timers.nextFrameCheckTime) {
return false;
}
this.timers.nextFrameCheckTime = Date.now() + this.settings.active.arDetect.timers.playing;
return true;
} }
private onAnimationFrame(ts: DOMHighResTimeStamp) { private onAnimationFrame(ts: DOMHighResTimeStamp) {
if (this.canTriggerFrameCheck()) { if (this.canTriggerFrameCheck()) {
resetAardTestResults(this.testResults);
this.main(); this.main();
} }
this.animationFrame = window.requestAnimationFrame( (ts: DOMHighResTimeStamp) => this.onAnimationFrame(ts)); this.animationFrame = window.requestAnimationFrame( (ts: DOMHighResTimeStamp) => this.onAnimationFrame(ts));
} }
//#endregion
/** /**
* Main loop for scanning aspect ratio changes * Main loop for scanning aspect ratio changes
@ -390,42 +443,33 @@ class Aard {
} while (false); } while (false);
// TODO: subtitle check goes here.
// Note that subtitle check should reset aspect ratio outright, regardless of what other tests revealed.
// Also note that subtitle check should run on newest aspect ratio data, rather than lag one frame behind
// But implementation details are something for future Tam to figure out
// if detection is uncertain, we don't do anything at all
if (this.testResults.aspectRatioUncertain) {
return;
}
// TODO: emit debug values if debugging is enabled // TODO: emit debug values if debugging is enabled
this.testResults.isFinished = true; this.testResults.isFinished = true;
// if edge width changed, emit update event.
if (this.testResults.aspectRatioUpdated) {
this.videoData.resizer.updateAr({
type: AspectRatioType.AutomaticUpdate,
ratio: this.getAr(),
offset: this.testResults.letterboxOffset
});
}
} catch (e) { } catch (e) {
console.warn('[Ultrawidify] Aspect ratio autodetection crashed for some reason.\n\nsome reason:', e); console.warn('[Ultrawidify] Aspect ratio autodetection crashed for some reason.\n\nsome reason:', e);
this.videoData.resizer.setAr({type: AspectRatioType.AutomaticUpdate, ratio: this.defaultAr});
} }
} }
/**
* Checks whether conditions for granting a frame check are fulfilled
* @returns
*/
private canTriggerFrameCheck() {
// if (this._paused || this._halted || this._exited) {
// return false;
// }
// if video was paused & we know that we already checked that frame,
// we will not check it again.
const videoState = this.getVideoPlaybackState();
if (videoState !== VideoPlaybackState.Playing) {
if (this.status.lastVideoStatus === videoState) {
return false;
}
}
this.status.lastVideoStatus = videoState;
if (Date.now() < this.timers.nextFrameCheckTime) {
return false;
}
this.timers.nextFrameCheckTime = Date.now() + this.settings.active.arDetect.timers.playing;
return true;
}
private getVideoPlaybackState(): VideoPlaybackState { private getVideoPlaybackState(): VideoPlaybackState {
try { try {
if (this.video.ended) { if (this.video.ended) {
@ -1568,7 +1612,22 @@ class Aard {
this.testResults.aspectRatioUncertain = false; this.testResults.aspectRatioUncertain = false;
this.testResults.letterboxWidth = candidateAvg; this.testResults.letterboxWidth = candidateAvg;
this.testResults.letterboxOffset = diff; this.testResults.letterboxOffset = diff;
this.testResults.aspectRatioUpdated = true;
} }
/**
* Calculates video's current aspect ratio based on data in testResults.
* @returns
*/
private getAr() {
const fileAr = this.video.videoWidth / this.video.videoHeight;
const canvasAr = this.canvasStore.main.width / this.canvasStore.main.height;
const compensatedWidth = fileAr === canvasAr ? this.canvasStore.main.width : this.canvasStore.main.width * fileAr;
return compensatedWidth / (this.canvasStore.main.height - (this.testResults.letterboxWidth * 2));
}
//#endregion //#endregion
} }

View File

@ -28,6 +28,7 @@ export interface AardTestResults {
bottomCandidateQuality: number, bottomCandidateQuality: number,
}, },
aspectRatioUncertain: boolean, aspectRatioUncertain: boolean,
aspectRatioUpdated: boolean,
letterboxWidth: number, letterboxWidth: number,
letterboxOffset: number, letterboxOffset: number,
logoDetected: [boolean, boolean, boolean, boolean] logoDetected: [boolean, boolean, boolean, boolean]
@ -61,10 +62,11 @@ export function initAardTestResults(settings: AardSettings): AardTestResults {
bottomCandidate: 0, bottomCandidate: 0,
bottomCandidateQuality: 0, bottomCandidateQuality: 0,
}, },
aspectRatioUncertain: false,
aspectRatioUpdated: false,
letterboxWidth: 0, letterboxWidth: 0,
letterboxOffset: 0, letterboxOffset: 0,
logoDetected: [false, false, false, false] logoDetected: [false, false, false, false]
} }
} }
@ -77,4 +79,7 @@ export function resetAardTestResults(results: AardTestResults): void {
results.guardLine.cornerViolations[1] = false; results.guardLine.cornerViolations[1] = false;
results.guardLine.cornerViolations[2] = false; results.guardLine.cornerViolations[2] = false;
results.guardLine.cornerViolations[3] = false; results.guardLine.cornerViolations[3] = false;
results.letterboxWidth = 0;
results.letterboxOffset = 0;
results.aspectRatioUpdated = false;
} }

View File

@ -709,39 +709,12 @@ class VideoData {
//#endregion //#endregion
//#region shit that gets propagated to resizer and should be removed. Implement an event bus instead //#region shit that gets propagated to resizer and should be removed. Implement an event bus instead
panHandler(event, forcePan?: boolean) {
if (this.invalid) {
return;
}
if(this.destroyed) {
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
return;
}
if(!this.resizer) {
this.destroy();
return;
}
this.resizer.panHandler(event, forcePan);
}
setPanMode(mode) {
if (this.invalid) {
return;
}
this.resizer.setPanMode(mode);
}
restoreAr(){ restoreAr(){
if (this.invalid) { if (this.invalid) {
return; return;
} }
this.resizer.restore(); this.resizer.restore();
} }
isPlaying() {
return this.video && this.video.currentTime > 0 && !this.video.paused && !this.video.ended;
}
//#endregion //#endregion
checkVideoSizeChange(){ checkVideoSizeChange(){