Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions src/components/canvas/players/html5-player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,9 +291,10 @@ export class Html5Player extends Player {

// Captured frames are SVG images, which can't load remote files, so ingest files are inlined as data URIs.
// Callers await this only when the asset has ingest URLs, so other assets compose without yielding.
private async composeWithIngestFiles(asset: Html5Asset): Promise<string> {
// Every frame decodes its inlined images again, so a scaled bake inlines images sized for its scale.
private async composeWithIngestFiles(asset: Html5Asset, scale: number = 1): Promise<string> {
const longestEdge = html5ClipLongestEdge(this.clipConfiguration, this.edit.getResolvedEdit()?.output);
return composeHtml5IframeSrcdoc(await inlineHtml5IngestAssets(asset, longestEdge));
return composeHtml5IframeSrcdoc(await inlineHtml5IngestAssets(asset, longestEdge * scale));
}

private async mountIframe(asset: Html5Asset): Promise<void> {
Expand Down Expand Up @@ -442,7 +443,7 @@ export class Html5Player extends Player {
// An earlier capture may have seeked this iframe, and a seeked animation can leave state
// a fresh page lacks (GSAP writes start values inline once a tween has
// rendered). The backend captures from a fresh page, so capture does too.
if (!(await this.loadFreshPage(this.iframe, stale))) return null;
if (!(await this.loadFreshPage(this.iframe, stale, scale))) return null;

const { frameCount } = computeHtml5FrameCount({
clipLengthSeconds: this.getLength(),
Expand Down Expand Up @@ -535,8 +536,9 @@ export class Html5Player extends Player {
return true;
}

private async loadFreshPage(iframe: HTMLIFrameElement, stale: () => boolean): Promise<boolean> {
const srcdoc = findHtml5IngestUrls(this.asset).length > 0 ? await this.composeWithIngestFiles(this.asset) : composeHtml5IframeSrcdoc(this.asset);
private async loadFreshPage(iframe: HTMLIFrameElement, stale: () => boolean, scale: number = 1): Promise<boolean> {
const srcdoc =
findHtml5IngestUrls(this.asset).length > 0 ? await this.composeWithIngestFiles(this.asset, scale) : composeHtml5IframeSrcdoc(this.asset);
if (stale()) return false;
iframe.srcdoc = srcdoc; // eslint-disable-line no-param-reassign -- reloading the iframe it is given is this helper's job
await waitForIframeLoad(iframe, undefined, true);
Expand Down
14 changes: 14 additions & 0 deletions tests/html5-player.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,20 @@ it("keys each bake by its scale", async () => {
expect(jest.requireMock("@canvas/players/html5-cache").html5CachePut).toHaveBeenCalledWith("original@0.5", expect.anything());
});

it("inlines ingest files sized for the bake's scale, and for full size in a still", async () => {
const { player, harness } = createStillPlayer();
shownAt(harness, 0.46);
canvasLib.findHtml5IngestUrls.mockReturnValue([INGEST_URL]);
canvasLib.inlineHtml5IngestAssets.mockImplementation(async asset => asset);

await harness.runCapture();
expect(canvasLib.inlineHtml5IngestAssets).toHaveBeenLastCalledWith(expect.objectContaining({ type: "html5" }), 640);

await player.prepareStaticRender();
player.endStaticRender();
expect(canvasLib.inlineHtml5IngestAssets).toHaveBeenLastCalledWith(expect.objectContaining({ type: "html5" }), 1280);
});

it("keeps stills and captures at full resolution while a scaled bake exists", async () => {
const { player, harness } = createStillPlayer();
Object.assign(harness, { capturedFrames: [new Blob(["baked 0"])], capturedHash: "original@0.5", capturedScale: 0.5 });
Expand Down
Loading