Skip to content

Commit

Permalink
more fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
reindernijhoff committed Apr 29, 2024
1 parent 248d976 commit 12f0738
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 54 deletions.
2 changes: 1 addition & 1 deletion example/src/examplePlayBackwards.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ export async function initExamplePlayBackwards(container) {

fastImageSequence.progress = 0;

fastImageSequence.play(-30);
fastImageSequence.play(-200);
}
136 changes: 85 additions & 51 deletions src/lib/FastImageSequence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ export class FastImageSequence {
public width: number = 0;
public height: number = 0;
public frame: number = 0;
public ready: Promise<void>;
public tarball: Tarball | undefined;

private context: CanvasRenderingContext2D;
private tickFuncs: ((dt: number) => void) [] = [];

Expand All @@ -81,6 +81,7 @@ export class FastImageSequence {
private lastFrameDrawn: number = -1;
private destructed: boolean = false;
private logElement: HTMLElement | undefined;
private initialized: boolean = false;

/**
* Creates an instance of FastImageSequence.
Expand Down Expand Up @@ -132,29 +133,17 @@ export class FastImageSequence {
this.frames.push(new Frame(this, i));
}

// load tar file
this.ready = new Promise(async (resolve, reject) => {
if (this.options.tarURL !== undefined) {
const response = await fetch(this.options.tarURL);
const blob = await response.blob();
const data = await blob.arrayBuffer();
this.tarball = new Tarball(data, {useWorker: this.options.useWorkerForTar});

this.frames.forEach(frame => frame.tarImageAvailable = frame.tarImageURL !== undefined && this.tarball?.getInfo(frame.tarImageURL) !== undefined);
this.loadResources().then(() => {
this.initialized = true;

if (this.options.preloadAllTarImages) {
await Promise.all(this.frames.map(frame => frame.fetchTarImage()));
}
if (this.options.showDebugInfo) {
this.logElement = createLogElement();
this.container.appendChild(this.logElement);
this.tick(() => this.logDebugStatus(this.logElement as HTMLDivElement));
}
resolve();
});
this.drawingLoop(-1);

if (this.options.showDebugInfo) {
this.logElement = createLogElement();
this.container.appendChild(this.logElement);
this.tick(() => this.logDebugStatus(this.logElement as HTMLDivElement));
}
this.drawingLoop(-1);
});
}

public get isPlaying(): boolean {
Expand All @@ -181,6 +170,20 @@ export class FastImageSequence {
this.frame = (this.options.frames - 1) * value;
}

public get ready(): Promise<void> {
// check if the sequence is initialized
return new Promise((resolve) => {
const checkInitialized = () => {
if (this.lastFrameDrawn !== -1) {
resolve();
} else {
setTimeout(checkInitialized, 16);
}
};
checkInitialized();
});
}

private get index(): number {
return this.wrapIndex(this.frame);
}
Expand Down Expand Up @@ -251,6 +254,21 @@ export class FastImageSequence {
});
}

private async loadResources() {
if (this.options.tarURL !== undefined) {
const response = await fetch(this.options.tarURL);
const blob = await response.blob();
const data = await blob.arrayBuffer();
this.tarball = new Tarball(data, {useWorker: this.options.useWorkerForTar});

this.frames.forEach(frame => frame.tarImageAvailable = frame.tarImageURL !== undefined && this.tarball?.getInfo(frame.tarImageURL) !== undefined);

if (this.options.preloadAllTarImages) {
await Promise.all(this.frames.map(frame => frame.fetchTarImage()));
}
}
}

private wrapIndex(frame: number) {
const index = frame | 0;
return this.wrapFrame(index);
Expand All @@ -271,7 +289,7 @@ export class FastImageSequence {

time /= 1000;

const dt = this.startTime < 0 ? 1 / 60 : Math.min(time - this.startTime, 1 / 30);
const dt = this.initialized ? this.startTime < 0 ? 1 / 60 : Math.min(time - this.startTime, 1 / 30) : 0;
this.startTime = time > 0 ? time : -1;

if (this.frame - this.prevFrame < 0) this.direction = -1;
Expand All @@ -287,12 +305,6 @@ export class FastImageSequence {
const inViewport = rect.top < window.innerHeight && rect.bottom > 0;

if (inViewport) {
const currentFrame = this.frames[index] as Frame;
currentFrame.getImage().then((image) => {
// this.drawFrame(currentFrame);
}).catch(() => {
});

// find the best matching loaded frame, based on current index and direction
// first set some sort of priority
this.frames.forEach((frame) => {
Expand All @@ -305,7 +317,7 @@ export class FastImageSequence {
// direction *= -1;
}
}
// frame.priority += this.direction * direction === -1 ? this.frames.length : 0;
frame.priority += this.direction * direction === -1 ? this.frames.length : 0;
});
this.frames.sort((a, b) => b.priority - a.priority);
//
Expand Down Expand Up @@ -389,33 +401,41 @@ export class FastImageSequence {
});

// release tar images if needed
if (!this.options.preloadAllTarImages) {
let {numLoaded, numLoading} = this.getTarStatus();
if (numLoaded > this.options.numberOfCachedImages - numLoading) {
this.frames.filter(a => a.tarImage !== undefined && !a.loading && a.priority >= this.spread).forEach(a => {
if (numLoaded > this.options.numberOfCachedImages - numLoading) {
a.releaseTarImage();
numLoaded--;
}
if (!this.options.preloadAllTarImages && this.options.tarURL !== undefined && this.tarball) {
let numLoading = this.getTarStatus().numLoading;
const maxLoading = this.maxLoading;
const imagesToLoad = this.frames.filter(a => a.tarImage === undefined && a.tarImageAvailable && !a.loadingTarImage && a.priority < this.spread).sort((a, b) => a.priority - b.priority);

while (numLoading < maxLoading && imagesToLoad.length > 0) {
const image = imagesToLoad.shift() as Frame;

image.fetchTarImage().then(() => {
this.releaseTarImageWithLowestPriority();
}).catch((e) => {
console.error(e);
});

numLoading++;
}
}

// prioritize loading images and start loading images
let numLoading = this.getLoadStatus().numLoading;
const maxLoading = this.maxLoading;
const imagesToLoad = this.frames.filter(a => a.image === undefined && !a.loading && a.priority < this.spread).sort((a, b) => a.priority - b.priority);

while (numLoading < maxLoading && imagesToLoad.length > 0) {
const image = imagesToLoad.shift() as Frame;

image.fetchImage().then(() => {
this.releaseImageWithLowestPriority();
}).catch((e) => {
console.error(e);
});
if (this.options.imageURLCallback) {
let numLoading = this.getLoadStatus().numLoading;
const maxLoading = this.maxLoading;
const imagesToLoad = this.frames.filter(a => a.image === undefined && !a.loading && a.priority < this.spread).sort((a, b) => a.priority - b.priority);

while (numLoading < maxLoading && imagesToLoad.length > 0) {
const image = imagesToLoad.shift() as Frame;

image.fetchImage().then(() => {
this.releaseImageWithLowestPriority();
}).catch((e) => {
console.error(e);
});

numLoading++;
numLoading++;
}
}
}

Expand All @@ -430,7 +450,7 @@ export class FastImageSequence {

private getTarStatus() {
const used = this.options.tarURL !== undefined;
const tarLoaded = this.tarball !== undefined;
const tarLoaded = this.tarball !== undefined && this.initialized;
const numLoading = this.frames.filter(a => a.loadingTarImage).length;
const numLoaded = this.frames.filter(a => a.tarImage !== undefined).length;
const maxLoaded = this.options.preloadAllTarImages ? this.frames.length : this.options.numberOfCachedImages;
Expand All @@ -449,6 +469,7 @@ export class FastImageSequence {
const {used, tarLoaded, progress, numLoading, numLoaded, maxLoaded} = this.getTarStatus();
debugInfo += `- tar: ${used ? `${formatPercentage(progress)}, numLoading: ${numLoading}, numLoaded: ${numLoaded}/${maxLoaded}` : 'not used'}`;
}

log(output, debugInfo);
}

Expand All @@ -462,4 +483,17 @@ export class FastImageSequence {
}
}
}

private releaseTarImageWithLowestPriority() {
if (!this.options.preloadAllTarImages) {
const loadedImages = this.frames.filter(a => a.tarImage !== undefined && !a.loadingTarImage);
if (loadedImages.length > this.options.numberOfCachedImages) {
const sortedFrame = loadedImages.sort((a, b) => a.priority - b.priority).pop();
if (sortedFrame) {
// console.log('release tar image for frame', sortedFrame.index);
sortedFrame.releaseTarImage();
}
}
}
}
}
4 changes: 2 additions & 2 deletions src/lib/Frame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ export default class Frame {

public async getImage(): Promise<HTMLImageElement | ImageBitmap> {
return new Promise(async (resolve, reject) => {
if (this._image !== undefined) {
resolve(this._image);
if (this.image !== undefined) {
resolve(this.image);
} else if (this.tarImage !== undefined) {
resolve(this.tarImage);
} else {
Expand Down

0 comments on commit 12f0738

Please sign in to comment.